Browse Source

add loading, send message socket

pull/15/head
PhamY0601 1 year ago
parent
commit
0d9f87a306
12 changed files with 191 additions and 88 deletions
  1. +15
    -21
      src/app/modules/homepage/centralized-security-management/centralized-security-management.component.ts
  2. +4
    -5
      src/app/modules/homepage/homepage/home-page.component.html
  3. +43
    -2
      src/app/modules/homepage/homepage/home-page.component.ts
  4. +5
    -2
      src/app/modules/homepage/security-system-details/security-system-details.component.ts
  5. +14
    -9
      src/app/shared/component/camera-dialog/camera-dialog.component.html
  6. +27
    -0
      src/app/shared/component/camera-dialog/camera-dialog.component.scss
  7. +4
    -4
      src/app/shared/component/camera-dialog/camera-dialog.component.ts
  8. +9
    -5
      src/app/shared/component/confirm-dialog/confirm-dialog.component.html
  9. +30
    -15
      src/app/shared/component/confirm-dialog/confirm-dialog.component.ts
  10. +5
    -4
      src/app/shared/component/slider-range/slider-range.component.html
  11. +32
    -19
      src/app/shared/services/alarm-sound.service.ts
  12. +3
    -2
      src/app/shared/services/confirm-dialog.service.ts

+ 15
- 21
src/app/modules/homepage/centralized-security-management/centralized-security-management.component.ts View File

import { AlarmSoundService } from '../../../shared/services/alarm-sound.service'; import { AlarmSoundService } from '../../../shared/services/alarm-sound.service';
import { CameraDialogComponent } from '../../../shared/component/camera-dialog/camera-dialog.component'; import { CameraDialogComponent } from '../../../shared/component/camera-dialog/camera-dialog.component';
import { alarmData, alarmDemo } from '../data/fake-data'; import { alarmData, alarmDemo } from '../data/fake-data';
import { ConfirmDialogService } from '../../../shared/services/confirm-dialog.service';


@Component({ @Component({
selector: 'app-centralized-security-management', selector: 'app-centralized-security-management',
data = alarmData; data = alarmData;
alarmDemo = alarmDemo; alarmDemo = alarmDemo;
state1 = false; state1 = false;
status1 = false;
state2 = false; state2 = false;
status2 = false;
state5 = false; state5 = false;
state6 = false; state6 = false;
isReady = true; isReady = true;
onMessage(message: any) { onMessage(message: any) {
if (message.id == '0' && message.type === 'get') { if (message.id == '0' && message.type === 'get') {
this.state1 = message.state1 === '0'; // 1 OFF // alarm 12h this.state1 = message.state1 === '0'; // 1 OFF // alarm 12h
this.status1 = message.status1 === '1'; // 0 not, 1 ready, 2 error, 3 bypass
this.state2 = message.state2 === '0'; // 1 OFF // alarm 1h this.state2 = message.state2 === '0'; // 1 OFF // alarm 1h
this.status2 = message.status2 === '1'; // 0 not, 1 ready, 2 error, 3 bypass
this.state5 = message.state5 === '1'; // 1 ON, 0 OFF this.state5 = message.state5 === '1'; // 1 ON, 0 OFF
this.isReady = message.ready === '1'; this.isReady = message.ready === '1';
this.alarmSoundService$.startAlarm(this.state5, this.isReady, this.state1, this.state2);
this.alarmSoundService$.startAlarm(this.state5, this.state1,this.status1, this.state2, this.status2);
this.updateIcons(); this.updateIcons();

} }


} }
} }


addMarker(item: any, isDemo: boolean = false): void { addMarker(item: any, isDemo: boolean = false): void {
console.log(this.state5, this.state1, this.status1)
const icon = isDemo const icon = isDemo
? this.getIcon(this.state5, this.isReady, this.state1, this.state2)
? this.getIcon(this.state5, this.state1, this.status1, this.state2, this.status2)
: this.createIcon(item.warning); : this.createIcon(item.warning);
const marker = L.marker( const marker = L.marker(
[item.detail.coordinates.lat, item.detail.coordinates.lng], [item.detail.coordinates.lat, item.detail.coordinates.lng],
</div>`; </div>`;
} }


createIcon(
active: boolean,
className: string = '',
text: any = [],
): L.Icon<L.IconOptions> | L.DivIcon {
createIcon(active: boolean, className: string = '', text: any = []): L.Icon<L.IconOptions> | L.DivIcon {
if (text.length < 1) { if (text.length < 1) {
return L.icon({ return L.icon({
iconUrl: active iconUrl: active
} }
} }


getIcon(
isTurnOn: boolean,
isReady: boolean,
fireArm: boolean,
fenceArm: boolean,
): L.Icon<L.IconOptions> | L.DivIcon {
if (isTurnOn && isReady) {
getIcon(isTurnOn: boolean, fireArm: boolean, fireStatus: boolean, fenceArm: boolean, fenceStatus: boolean): L.Icon<L.IconOptions> | L.DivIcon {
if (isTurnOn) {
let text = []; let text = [];
if (fireArm && fenceArm) {
text.push('FIRE ALARM', 'FENCE ALARM');
} else if (fireArm) {
if (fireStatus && fireArm) {
text.push('FIRE ALARM'); text.push('FIRE ALARM');
} else if (fenceArm) {
}
if (fenceStatus && fenceArm) {
text.push('FENCE ALARM'); text.push('FENCE ALARM');
} }
return this.createIcon(true, '', text);
return this.createIcon(true, '', text);

} }
return this.createIcon(false); return this.createIcon(false);
} }

+ 4
- 5
src/app/modules/homepage/homepage/home-page.component.html View File

</button> </button>
</div> </div>



<mat-card class="sound-group"> <mat-card class="sound-group">
<mat-card-header> <mat-card-header>
<mat-card-title>WHISTLE TIME: {{whistle.time}}s</mat-card-title> <mat-card-title>WHISTLE TIME: {{whistle.time}}s</mat-card-title>
<app-slider-range <app-slider-range
[value]="whistle.time" [value]="whistle.time"
[icon]="'access_alarm'" [icon]="'access_alarm'"
(valueChange)="whistle.time = $event"
(valueChange)="emitSetting('whistle', $event)"
[disable]="!isConnected"
></app-slider-range> ></app-slider-range>
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>



<mat-card class="sound-group"> <mat-card class="sound-group">
<mat-card-header> <mat-card-header>
<mat-card-title>24-HOUR ZONE ALARM TIME: {{alarm.time}}s</mat-card-title> <mat-card-title>24-HOUR ZONE ALARM TIME: {{alarm.time}}s</mat-card-title>
<app-slider-range <app-slider-range
[value]="alarm.time" [value]="alarm.time"
[icon]="'access_alarm'" [icon]="'access_alarm'"
(valueChange)="alarm.time = $event"
(valueChange)="emitSetting('alarm',$event)"
[disable]="!isConnected"
></app-slider-range> ></app-slider-range>
</div> </div>

</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

+ 43
- 2
src/app/modules/homepage/homepage/home-page.component.ts View File

import { Component } from '@angular/core';
import {Component, OnDestroy, OnInit} from '@angular/core';
import {SocketService} from "../../../shared/services/socket.service";
import {Subscription} from "rxjs";


@Component({ @Component({
selector: 'app-homepage', selector: 'app-homepage',
templateUrl: './home-page.component.html', templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.scss'], styleUrls: ['./home-page.component.scss'],
}) })
export class HomePageComponent {
export class HomePageComponent implements OnInit,OnDestroy{
whistle = { whistle = {
time: 10, time: 10,
sound: 0, sound: 0,
time: 30, time: 30,
sound: 0, sound: 0,
}; };
private statusSubscription?: Subscription;
isConnected: boolean = false;
constructor(private socketService$: SocketService,) {
this.statusSubscription = this.socketService$.status$.subscribe(
(isConnected) => {
this.isConnected = isConnected;
},
);
}
ngOnInit() {
this.whistle.time = parseInt(localStorage.getItem('whistletime') ?? '10');
if (!localStorage.getItem('whistletime')) {
localStorage.setItem('whistletime', '10');
}
this.alarm.time = parseInt(localStorage.getItem('alarmtime') ?? '30');
if (!localStorage.getItem('alarmtime')) {
localStorage.setItem('alarmtime', '30');
}
}

emitSetting(type: string, event: any){
if (this.isConnected) {
if (type === 'whistle') {
this.whistle.time = event;
localStorage.setItem('whistletime', event);
this.socketService$.sendMessage({ id: '0', type: 'set', whistletime: event.toString() });
} else if (type === 'alarm') {
this.alarm.time = event;
localStorage.setItem('alarmtime', event);
this.socketService$.sendMessage({ id: '0', type: 'set', arlamtime: event.toString() });
}
}
}

ngOnDestroy(): void {
if (this.statusSubscription) {
this.statusSubscription.unsubscribe();
}
}
} }

+ 5
- 2
src/app/modules/homepage/security-system-details/security-system-details.component.ts View File

import {CameraDialogComponent} from "../../../shared/component/camera-dialog/camera-dialog.component"; import {CameraDialogComponent} from "../../../shared/component/camera-dialog/camera-dialog.component";
import {MatDialog} from "@angular/material/dialog"; import {MatDialog} from "@angular/material/dialog";
import { ConfirmDialogService } from '../../../shared/services/confirm-dialog.service'; import { ConfirmDialogService } from '../../../shared/services/confirm-dialog.service';
import {AlarmSoundService} from "../../../shared/services/alarm-sound.service";


@Component({ @Component({
selector: 'app-security-system-details', selector: 'app-security-system-details',


constructor( constructor(
private socketService$: SocketService, private socketService$: SocketService,
private toastr: ToastrService,
private dialog: MatDialog, private dialog: MatDialog,
private confirm$: ConfirmDialogService
private confirm$: ConfirmDialogService,
private alarmSoundService$: AlarmSoundService,
) {} ) {}


ngOnInit() { ngOnInit() {
clearInterval(this.intervalId); clearInterval(this.intervalId);
} }
this.socketService$.close(); this.socketService$.close();
this.alarmSoundService$.stopAlarm();
} }


getReadings() { getReadings() {
this.confirm$.openDialog(data); this.confirm$.openDialog(data);
// this.toastr.warning('System not ready', 'Warning', {timeOut: 5000}); // this.toastr.warning('System not ready', 'Warning', {timeOut: 5000});
} }
this.alarmSoundService$.startAlarm(this.state5, this.state1,this.status1, this.state2, this.status2);
} }
} }
openDialog(): void { openDialog(): void {

+ 14
- 9
src/app/shared/component/camera-dialog/camera-dialog.component.html View File

<div style="padding: 10px 20px" fxLayout="row" fxLayoutAlign="center">
<div style="text-align: center; font-size: 24px; width: 95%">Camera Stream</div>
<button mat-icon-button color="warn" (click)="onClose()">
<mat-icon>close</mat-icon>
</button>
</div>


<div style="padding: 10px 20px" fxLayout="row" fxLayoutAlign=" center">
<div style="text-align: center; font-size: 24px; width: 95%">Camera Stream</div>
<button mat-icon-button color="warn" (click)="onClose()">
<mat-icon>close</mat-icon>
</button>
<div mat-dialog-content>
<div fxLayout="row" fxLayoutAlign="space-around center" fxLayoutGap="10px"
style="height: 50%;"
*ngIf="!videoLoaded">
<div class="circle-loader"></div>
<div class="loader"></div>
</div> </div>
<div mat-dialog-content>
<canvas class="video" #videoPlayer></canvas>
</div>

<canvas class="video" #videoPlayer [hidden]="!videoLoaded"></canvas>
</div>

+ 27
- 0
src/app/shared/component/camera-dialog/camera-dialog.component.scss View File

.mat-mdc-dialog-content{ .mat-mdc-dialog-content{
max-height: unset; max-height: unset;
} }

.loader {
width: fit-content;
color: orange;
font-family: monospace;
font-size: 30px;
clip-path: inset(0 3ch 0 0);
animation: l4 1s steps(4) infinite;
}
.loader:before {
content:"Loading..."
}
@keyframes l4 {to{clip-path: inset(0 -1ch 0 0)}}

.circle-loader {
width: 50px;
aspect-ratio: 1;
border-radius: 50%;
background:
radial-gradient(farthest-side,#ffa516 94%,#0000) top/8px 8px no-repeat,
conic-gradient(#0000 30%,#ffa516);
-webkit-mask: radial-gradient(farthest-side,#0000 calc(100% - 8px),#000 0);
animation: l13 1s infinite linear;
}
@keyframes l13{
100%{transform: rotate(1turn)}
}

+ 4
- 4
src/app/shared/component/camera-dialog/camera-dialog.component.ts View File

export class CameraDialogComponent implements AfterViewInit{ export class CameraDialogComponent implements AfterViewInit{


player?: Player; player?: Player;
@ViewChild('videoPlayer')
videoPlayer?: ElementRef<HTMLCanvasElement>;

videoLoaded: boolean = false;
@ViewChild('videoPlayer') videoPlayer?: ElementRef<HTMLCanvasElement>;


constructor(public dialogRef: MatDialogRef<CameraDialogComponent>) { } constructor(public dialogRef: MatDialogRef<CameraDialogComponent>) { }


url: 'ws://localhost:8080/stream', url: 'ws://localhost:8080/stream',
canvas: this.videoPlayer!.nativeElement, canvas: this.videoPlayer!.nativeElement,
onDisconnect: () => { onDisconnect: () => {
setTimeout(connect, 5000); // reconnect after 5 seconds
setTimeout(connect, 5000);
}, },
}); });
this.videoLoaded = true;
}; };
connect(); connect();
} }

+ 9
- 5
src/app/shared/component/confirm-dialog/confirm-dialog.component.html View File

<h5 mat-dialog-title >CONFIRM TO IGNORE THE WARNING</h5> <h5 mat-dialog-title >CONFIRM TO IGNORE THE WARNING</h5>
<mat-dialog-content style="padding-bottom: 4px"> <mat-dialog-content style="padding-bottom: 4px">
<div *ngFor="let item of data">
<mat-checkbox [(ngModel)]="item.value" (ngModelChange)="submitChange(item)" name="sensor">
{{ (item.key == 'status1' ? 'Fire' : 'ff')}}
</mat-checkbox>
</div>
<div *ngFor="let item of data">
<mat-checkbox [(ngModel)]="item.value"
(ngModelChange)="submitChange(item)"
[disabled]="isConnected && item.value"
name="sensor">
{{ (item.key == 'status1' ? 'Fire Alarm' : 'Fence Alarm') }}
</mat-checkbox>
</div>
</mat-dialog-content> </mat-dialog-content>

<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button mat-dialog-close cdkFocusInitial>Close</button> <button mat-button mat-dialog-close cdkFocusInitial>Close</button>
</mat-dialog-actions> </mat-dialog-actions>

+ 30
- 15
src/app/shared/component/confirm-dialog/confirm-dialog.component.ts View File

import { Component } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';
import {Component, Inject, OnDestroy, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {SocketService} from "../../services/socket.service";
import {Subscription} from "rxjs";


@Component({ @Component({
selector: 'app-confirm-dialog', selector: 'app-confirm-dialog',
templateUrl: './confirm-dialog.component.html', templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.scss'], styleUrls: ['./confirm-dialog.component.scss'],
}) })
export class ConfirmDialogComponent {
constructor(public dialogRef: MatDialogRef<ConfirmDialogComponent>) {}
data = [
{
key: 'status1',
value: false,
export class ConfirmDialogComponent implements OnDestroy{

private statusSubscription?: Subscription;
isConnected: boolean = false;

constructor(
@Inject(MAT_DIALOG_DATA) public data: any[],
private socketService$: SocketService,
) {
this.statusSubscription = this.socketService$.status$.subscribe(
(isConnected) => {
this.isConnected = isConnected;
}, },
{
name: 'status2',
value: false,
},
];
);
}

submitChange(item: any): void{ submitChange(item: any): void{
console.log(item);
// call socket here
if(this.isConnected) {
const position = item.key === 'status1' ? 1 : 2;
this.socketService$.sendMessage({ id: '0', type: 'bypass', state: position})
item.value = true;
}
}

ngOnDestroy() {
if (this.statusSubscription) {
this.statusSubscription.unsubscribe();
}
} }
} }

+ 5
- 4
src/app/shared/component/slider-range/slider-range.component.html View File

<ng-content></ng-content> <ng-content></ng-content>
<div class="volume-group"> <div class="volume-group">
<div class="speaker"> <div class="speaker">
<mat-icon>{{icon}}</mat-icon>
<mat-icon>{{ icon }}</mat-icon>
</div> </div>
<button class="volume-control" (click)="decreaseVolume()">
<button class="volume-control" [disabled]="disable" (click)="decreaseVolume()">
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" <svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icons/Minus square fill</title> <title>Icons/Minus square fill</title>
<div class="volume-slider"> <div class="volume-slider">
<input type="range" [(ngModel)]="value" (input)="onSliderChange($event)" <input type="range" [(ngModel)]="value" (input)="onSliderChange($event)"
[ngStyle]="onSliderChangeBackground()" [ngStyle]="onSliderChangeBackground()"
[max]="max">
[max]="max"
[disabled]="disable">
</div> </div>
</div> </div>
<button class="volume-control" (click)="increaseVolume()">
<button class="volume-control" [disabled]="disable" (click)="increaseVolume()">
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" <svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icons/Plus square fill</title> <title>Icons/Plus square fill</title>

+ 32
- 19
src/app/shared/services/alarm-sound.service.ts View File

import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import {max} from "rxjs";


@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
private alertInterval: any; private alertInterval: any;
private alertDuration: number = 10000; private alertDuration: number = 10000;
private audio = new Audio(); private audio = new Audio();
private isPlaying: boolean = false;
private isPlay: boolean = false;


constructor() { constructor() {
this.audio.src = 'assets/sound/alarm_5m.mp3'; this.audio.src = 'assets/sound/alarm_5m.mp3';
this.audio.load(); this.audio.load();
this.audio.onended = () => {
// Khi phát hết âm thanh, đặt biến isPlaying về false
this.isPlaying = false;
};

} }


playSound(): void { playSound(): void {
if (!this.isPlaying) {
if(!this.isPlay){
this.audio.play().then(() => { this.audio.play().then(() => {
this.isPlaying = true;
this.isPlay = true;
this.alertInterval = setInterval(() => { this.alertInterval = setInterval(() => {
this.stopAlarm(); this.stopAlarm();
}, this.alertDuration); }, this.alertDuration);
console.error('Error playing audio:', error); console.error('Error playing audio:', error);
}); });
} }

} }


stopSound(): void {
if (this.audio) {
this.audio.pause();
this.audio.currentTime = 0;
this.isPlaying = false;
startAlarm(isTurnOn: boolean, fireArm: boolean, fireStatus: boolean, fenceArm: boolean, fenceStatus: boolean): void {
if (!isTurnOn) {
this.stopAlarm();
return;
} }
}


startAlarm( isTurnOn: boolean, isReady: boolean, fireArm: boolean, fenceArm: boolean): void {
if (isTurnOn && isReady && (fireArm || fenceArm)) {
//this.alertDuration = // setting time
this.playSound();
}else{
const alarmTime = this.getTimeDuration('alarmtime');
const whistleTime = this.getTimeDuration('whistletime');

if (fireArm && fireStatus && fenceArm && fenceStatus) {
this.alertDuration = Math.max(alarmTime, whistleTime);
} else if (fireArm && fireStatus) {
this.alertDuration = alarmTime;
} else if (fenceArm && fenceStatus) {
this.alertDuration = whistleTime;
} else {
this.stopAlarm(); this.stopAlarm();
return;
} }

this.playSound();
} }


stopAlarm(): void { stopAlarm(): void {
this.stopSound();
if (this.audio) {
this.audio.pause();
this.audio.currentTime = 0;
this.isPlay = false;
}
if (this.alertInterval){ if (this.alertInterval){
clearInterval(this.alertInterval); clearInterval(this.alertInterval);
} }
} }


getTimeDuration(key: string) {
return parseInt(localStorage.getItem(key) ?? '0') * 100;
}
} }

+ 3
- 2
src/app/shared/services/confirm-dialog.service.ts View File

openDialog(data: any[]): void { openDialog(data: any[]): void {
if (!this.isDialogOpen) { if (!this.isDialogOpen) {
this.isDialogOpen = true; this.isDialogOpen = true;
const dialogRef = this.dialog.open(ConfirmDialogComponent);

const dialogRef = this.dialog.open(ConfirmDialogComponent, {
data: data
});
dialogRef dialogRef
.afterClosed() .afterClosed()
.pipe(take(1)) .pipe(take(1))

Loading…
Cancel
Save