| @@ -0,0 +1,64 @@ | |||
| export const ICON = { | |||
| sensorOff: `<div style="display: flex; flex-direction: row; gap: 5px"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/sensor-off.png"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/camera.png"> | |||
| </div>`, | |||
| sensorOn: `<div style="display: flex; flex-direction: row; gap: 5px"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/sensor-on.png"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/camera.png"> | |||
| </div>`, | |||
| sensorActive: `<div> | |||
| <div style="width: 30px; height: 30px; position: absolute; display: flex; justify-content: center; align-items: center; border-radius: 50%; background: linear-gradient(#ff0000, #C70039);"> | |||
| <div style="position: absolute !important; width: 100%; height: 100%; background: #ff0000; border-radius: 50%; z-index: 1; animation: sensor-on 2s ease-out infinite;"></div> | |||
| <div style="position: absolute !important; width: 100%; height: 100%; background: #ff0000; border-radius: 50%; z-index: 1; animation: sensor-on 2s ease-out infinite; animation-delay: 1s;"></div> | |||
| <img src="assets/images/sensor-on.png" style="width: 30px; height: 30px; z-index: 9;"> | |||
| </div> | |||
| <img style="width: 30px; height: 30px;margin-left: 40px;" src="assets/images/camera.png"> | |||
| <style> | |||
| @keyframes sensor-on { | |||
| 100% { | |||
| transform: scale(2); | |||
| opacity: 0; | |||
| } | |||
| } | |||
| </style> | |||
| </div>`, | |||
| fireContent: `<div style="display: flex; | |||
| flex-direction: row; | |||
| justify-content: space-between;"> | |||
| <div style="color: #F33152; | |||
| padding: 5px 13px; | |||
| background-color: rgba(243, 49, 82, 0.1); | |||
| border-radius: 20px; | |||
| text-align: center; | |||
| width: 100px;">Sự cố cháy</div> | |||
| <a href="/overview/camera-stream"> | |||
| <svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none"> | |||
| <g stroke="currentColor" stroke-width="2"> | |||
| <path d="M16 16V8a1 1 0 00-1-1H5a1 1 0 00-1 1v8a1 1 0 001 1h10a1 1 0 001-1z"/> | |||
| <path stroke-linejoin="round" d="M20 7l-4 3v4l4 3V7z"/> | |||
| </g> | |||
| </svg> | |||
| </a> | |||
| </div> | |||
| <div><strong>Địa điểm:</strong> 120 Xa Lộ Hà Nội, Thành Phố, Thủ Đức, Thành phố Hồ Chí Minh</div> | |||
| <div><strong>Tọa độ:</strong> 10.8661° N, 106.8029° E</div> | |||
| <div><strong>Thời gian:</strong> 01:54, 16/05/2022</div> | |||
| <a href="/overview/overall-ground" target="_blank">Xem chi tiết</a>`, | |||
| sensorActiveBK: ` | |||
| <div style="width: 30px; height: 30px; position: absolute; display: flex; justify-content: center; align-items: center; border-radius: 50%; background: linear-gradient(#ff0000, #C70039);"> | |||
| <div style="position: absolute !important; width: 100%; height: 100%; background: #ff0000; border-radius: 50%; z-index: 1; animation: sensor-on 2s ease-out infinite;"></div> | |||
| <div style="position: absolute !important; width: 100%; height: 100%; background: #ff0000; border-radius: 50%; z-index: 1; animation: sensor-on 2s ease-out infinite; animation-delay: 1s;"></div> | |||
| <img src="assets/images/sensor-on.png" style="width: 30px; height: 30px; z-index: 9;"> | |||
| </div> | |||
| <style> | |||
| @keyframes sensor-on { | |||
| 100% { | |||
| transform: scale(2); | |||
| opacity: 0; | |||
| } | |||
| } | |||
| </style> | |||
| `, | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| <h3>Camera Stream</h3> | |||
| <canvas #videoPlayer></canvas> | |||
| @@ -0,0 +1,21 @@ | |||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
| import { CameraStreamComponent } from './camera-stream.component'; | |||
| describe('CameraStreamComponent', () => { | |||
| let component: CameraStreamComponent; | |||
| let fixture: ComponentFixture<CameraStreamComponent>; | |||
| beforeEach(() => { | |||
| TestBed.configureTestingModule({ | |||
| declarations: [CameraStreamComponent] | |||
| }); | |||
| fixture = TestBed.createComponent(CameraStreamComponent); | |||
| component = fixture.componentInstance; | |||
| fixture.detectChanges(); | |||
| }); | |||
| it('should create', () => { | |||
| expect(component).toBeTruthy(); | |||
| }); | |||
| }); | |||
| @@ -0,0 +1,30 @@ | |||
| import {Component, OnInit, ViewChild, ElementRef, AfterViewInit, Renderer2} from '@angular/core'; | |||
| import {loadPlayer, Player} from "rtsp-relay/browser"; | |||
| @Component({ | |||
| selector: 'app-camera-stream', | |||
| templateUrl: './camera-stream.component.html', | |||
| styleUrls: ['./camera-stream.component.scss'] | |||
| }) | |||
| export class CameraStreamComponent implements OnInit, AfterViewInit{ | |||
| player?: Player; | |||
| @ViewChild('videoPlayer') | |||
| videoPlayer?: ElementRef<HTMLCanvasElement>; | |||
| ngOnInit() { | |||
| } | |||
| constructor(private el: ElementRef, private renderer: Renderer2) {} | |||
| async ngAfterViewInit() { | |||
| this.player = await loadPlayer({ | |||
| url: 'ws://localhost:8081', | |||
| canvas: this.videoPlayer!.nativeElement, | |||
| onDisconnect: () => console.log('Connection lost!'), | |||
| }); | |||
| console.log('Connected!', this.player); | |||
| } | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| <div class="map-container"> | |||
| <h2>ATMs Security Monitoring and Control</h2> | |||
| <div class="map-frame"> | |||
| <div id="map"></div> <!-- Ensure no extra space after "map" --> | |||
| <div id="map"></div> | |||
| </div> | |||
| </div> | |||
| @@ -9,7 +9,7 @@ | |||
| .map-frame { | |||
| border: 2px solid black; | |||
| height: 100%; | |||
| height: 90%; | |||
| } | |||
| #map { | |||
| @@ -23,3 +23,7 @@ p { | |||
| padding: 3px 2px; | |||
| background-color: rbg(243,49,82,0.1); | |||
| } | |||
| .hidden-background{ | |||
| background: transparent; | |||
| border: none; | |||
| } | |||
| @@ -1,7 +1,8 @@ | |||
| import {AfterViewInit, Component, OnDestroy, OnInit} from '@angular/core'; | |||
| import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core'; | |||
| import * as L from 'leaflet'; | |||
| import {Subscription} from "rxjs"; | |||
| import {SocketService} from "../../../shared/services/socket.service"; | |||
| import { Subscription } from 'rxjs'; | |||
| import { SocketService } from '../../../shared/services/socket.service'; | |||
| import {ICON} from "../../../app.constants"; | |||
| @Component({ | |||
| selector: 'app-map', | |||
| @@ -9,124 +10,106 @@ import {SocketService} from "../../../shared/services/socket.service"; | |||
| styleUrls: ['./map.component.scss'] | |||
| }) | |||
| export class MapComponent implements OnInit, AfterViewInit, OnDestroy { | |||
| private map: any; | |||
| houseIcon = L.icon({ | |||
| iconUrl: '../../../../assets/images/icon.png', | |||
| iconSize: [38, 48], | |||
| shadowSize: [50, 64], | |||
| }); | |||
| fireIcon = L.icon({ | |||
| iconUrl: '../../../../assets/images/fire.gif', | |||
| iconSize: [38, 48], | |||
| }) | |||
| sensorOnIcon = L.divIcon({ | |||
| className: '', | |||
| html:'<div style="width: 30px; height: 30px; position: absolute; display: flex; justify-content: center; align-items: center; border-radius: 50%; background: linear-gradient(#ff0000, #C70039);">'+ | |||
| ' <div style="position: absolute !important; width: 100%; height: 100%; background: #ff0000; border-radius: 50%; z-index: 1; animation: sensor-on 2s ease-out infinite;"></div>'+ | |||
| ' <div style="position: absolute !important; width: 100%; height: 100%; background: #ff0000; border-radius: 50%; z-index: 1; animation: sensor-on 2s ease-out infinite; animation-delay: 1s;"></div>'+ | |||
| ' <img src="assets/images/sensor-on.png" style="width: 30px; height: 30px; z-index: 9;">'+ | |||
| '</div>'+ | |||
| '<style>'+ | |||
| '@keyframes sensor-on {'+ | |||
| ' 100% {'+ | |||
| ' transform: scale(2);'+ | |||
| ' opacity: 0;'+ | |||
| ' }'+ | |||
| '}'+ | |||
| '</style>', | |||
| iconSize: [38, 48] | |||
| private map!: L.Map; | |||
| private featureGroup!: L.FeatureGroup; | |||
| private statusSubscription?: Subscription; | |||
| private messageSubscription?: Subscription; | |||
| sensorOff = ICON.sensorOff; | |||
| sensorOn = ICON.sensorOn; | |||
| sensorActive = ICON.sensorActiveBK; | |||
| sensorActiveIcon = L.divIcon({ | |||
| html: this.sensorActive, | |||
| iconSize: [38, 48], | |||
| className: 'hidden-background' | |||
| }); | |||
| // | |||
| // sensorOffIcon = L.divIcon({ | |||
| // html: this.sensorOff, | |||
| // iconSize: [38, 38], | |||
| // className: 'hidden-background' | |||
| // }); | |||
| // sensorOnIcon = L.divIcon({ | |||
| // html: this.sensorOn, | |||
| // iconSize: [38, 38], | |||
| // className: 'hidden-background' | |||
| // }); | |||
| sensorOffIcon = L.icon({ | |||
| iconUrl: '../../../../assets/images/sensor-off.png', | |||
| iconSize: [38, 38], | |||
| }) | |||
| }); | |||
| state5 = false; | |||
| state6 = false; | |||
| sensorOnIcon = L.icon({ | |||
| iconUrl: '../../../../assets/images/sensor-on.png', | |||
| iconSize: [38, 38], | |||
| }); | |||
| private statusSubscription?: Subscription; | |||
| private messageSubscription?: Subscription; | |||
| constructor(private socketService$: SocketService) {} | |||
| state5 = false; | |||
| state6 = false; | |||
| constructor(private socketService$: SocketService) { } | |||
| ngOnInit() { | |||
| this.statusSubscription = this.socketService$.status$.subscribe(isConnected => { | |||
| if (isConnected) { | |||
| this.messageSubscription = this.socketService$.messages$.subscribe(message => { | |||
| this.messageSubscription = this.socketService$.messages$.subscribe(message => { | |||
| this.onMessage(message); | |||
| }); | |||
| } | |||
| }); | |||
| } | |||
| ngOnDestroy(): void { | |||
| if (this.statusSubscription) { | |||
| this.statusSubscription.unsubscribe(); | |||
| } | |||
| if (this.messageSubscription) { | |||
| this.messageSubscription.unsubscribe(); | |||
| } | |||
| this.socketService$.close(); | |||
| } | |||
| onMessage(message: any) { | |||
| if (message.id == '0' && message.type === 'get') { | |||
| this.state5 = message.state5 === '1'; | |||
| this.state6 = message.state6 === '1' ; | |||
| this.updateIcons(); | |||
| } | |||
| } | |||
| ngAfterViewInit(): void { | |||
| this.initMap(); | |||
| } | |||
| ngOnDestroy(): void { | |||
| this.statusSubscription?.unsubscribe(); | |||
| this.messageSubscription?.unsubscribe(); | |||
| this.socketService$.close(); | |||
| } | |||
| private initMap(): void { | |||
| const mapContainer = document.getElementById('map'); | |||
| if (mapContainer) { | |||
| this.map = L.map('map', { | |||
| center: [10.8494, 106.7537 ], | |||
| center: [10.8494, 106.7537], | |||
| zoom: 12 | |||
| }); | |||
| const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |||
| L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |||
| maxZoom: 18, | |||
| minZoom: 3, | |||
| attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' | |||
| }); | |||
| }).addTo(this.map); | |||
| tiles.addTo(this.map); | |||
| this.addIconToMap() | |||
| this.featureGroup = L.featureGroup().addTo(this.map); | |||
| this.addIconToMap(); | |||
| } else { | |||
| console.error('Map container not found'); | |||
| } | |||
| } | |||
| onMessage(message: any) { | |||
| if (message.id == '0' && message.type === 'get') { | |||
| this.state5 = message.state5 === '1'; | |||
| this.state6 = message.state6 === '1'; | |||
| this.updateIcons(); | |||
| } | |||
| } | |||
| addIconToMap() { | |||
| //add marker | |||
| let popupContent = `<div>Vinhome quận 9</div> | |||
| <a href="/overview/overall-ground" target="_blank">Xem chi tiết</a>`; | |||
| let fireContent = `<div style="color: #F33152; | |||
| padding: 2px 13px; | |||
| background-color: rgba(243, 49, 82, 0.1); | |||
| border-radius: 20px; | |||
| text-align: center; | |||
| width: 100px;"> | |||
| Sự cố cháy | |||
| </div> | |||
| <div><strong>Địa điểm:</strong> 120 Xa Lộ Hà Nội, Thành Phố, Thủ Đức, Thành phố Hồ Chí Minh</div> | |||
| <div><strong>Tọa độ:</strong> 10.8661° N, 106.8029° E</div> | |||
| <div><strong>Thời gian:</strong> 01:54, 16/05/2022</div> | |||
| <a href="/overview/overall-ground" target="_blank">Xem chi tiết</a>` | |||
| L.marker([10.8356, 106.8300], {icon: this.state5 ? this.sensorOnIcon : this.sensorOffIcon}) | |||
| const popupContent = `<div>Vinhome quận 9</div> | |||
| <a href="/overview/overall-ground" target="_blank">Xem chi tiết</a>`; | |||
| const fireContent = ICON.fireContent; | |||
| L.marker([10.8356, 106.8300], {icon: this.applyIcon(this.state5, this.state6)}) | |||
| .addTo(this.map) | |||
| .bindPopup(popupContent); | |||
| L.marker([10.8661, 106.8029], {icon: this.state6 ? this.sensorOnIcon : this.sensorOffIcon}) | |||
| L.marker([10.8661, 106.8029], {icon: this.applyIcon(this.state5, this.state6)}) | |||
| .addTo(this.map) | |||
| .bindPopup(fireContent); | |||
| } | |||
| @@ -140,4 +123,14 @@ export class MapComponent implements OnInit, AfterViewInit, OnDestroy { | |||
| this.addIconToMap(); | |||
| } | |||
| applyIcon(state1: boolean, state2: boolean): L.Icon | L.DivIcon { | |||
| if (state1 && state2) { | |||
| return this.sensorActiveIcon; | |||
| } | |||
| if (state1) { | |||
| return this.sensorOnIcon; | |||
| } | |||
| return this.sensorOffIcon; | |||
| } | |||
| } | |||
| @@ -3,29 +3,19 @@ | |||
| <div class="card-state"> | |||
| <img src="assets/images/ground.png"> | |||
| <p class="state t1" id="State1" [ngClass]="{'sensor-on': state1 === 'ON'}"> | |||
| <img [src]="getImageSource(state1)" style="width: 30px; height: 30px"> | |||
| </p> | |||
| <p class="state t2" id="State2" [ngClass]="{'sensor-on': state2 === 'ON'}"> | |||
| <img [src]="getImageSource(state2)" style="width: 30px; height: 30px"> | |||
| </p> | |||
| <p class="state t3" id="State3" [ngClass]="{'sensor-on': state3 === 'ON'}"> | |||
| <img [src]="getImageSource(state3)" style="width: 30px; height: 30px"> | |||
| </p> | |||
| <p class="state t4" id="State4" [ngClass]="{'sensor-on': state4 === 'ON'}"> | |||
| <img [src]="getImageSource(state4)" style="width: 30px; height: 30px"> | |||
| </p> | |||
| <p class="state t5" id="State5" [ngClass]="{'sensor-on': state5 === 'ON'}"> | |||
| <img [src]="getImageSource(state5)" style="width: 30px; height: 30px"> | |||
| </p> | |||
| <p class="state t6" id="State6" [ngClass]="{'sensor-on': state6 === 'ON'}"> | |||
| <img [src]="getImageSource(state6)" style="width: 30px; height: 30px"> | |||
| </p> | |||
| <div *ngFor="let state of states; let i = index" | |||
| [ngClass]="{'sensor-on': Sstate1 && Sstate2}" | |||
| class="state t{{i + 1}}" | |||
| id="State{{i + 1}}"> | |||
| <img [src]="getImageSource()" style="width: 30px; height: 30px"> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div fxFlex="30" fxLayout="column" fxLayoutGap="50px"> | |||
| <div>Công tắc 1 <button [disabled]="!isConnected" mat-flat-button color="{{Sstate1 ? 'accent' : 'primary'}}" (click)="toggleState1()">{{ Sstate1 ? 'ON' : 'OFF'}}</button></div> | |||
| <div>Công tắc 2 <button [disabled]="!isConnected" mat-flat-button color="{{Sstate2 ? 'accent' : 'primary'}}" (click)="toggleState2()">{{ Sstate2 ? 'ON' : 'OFF'}}</button></div> | |||
| <div>Công tắc 1 <button [disabled]="!isConnected" mat-flat-button color="{{Sstate1 ? 'accent' : 'primary'}}" (click)="toggleState1()">{{ Sstate1 ? 'DISARM' : 'ARM'}}</button></div> | |||
| <div>Công tắc 2 <button [disabled]="!isConnected" mat-flat-button color="{{Sstate2 ? 'accent' : 'primary'}}" (click)="toggleState2()">{{ Sstate2 ? 'TẮT CẢNH BÁO' : 'BẬT CẢNH BÁO'}}</button></div> | |||
| <div>Live Camera <button mat-stroked-button color="primary" [routerLink]="'/overview/camera-stream'"> Xem chi tiết </button></div> | |||
| </div> | |||
| </div> | |||
| @@ -1,90 +1,96 @@ | |||
| import {ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; | |||
| import {SocketService} from "../../../shared/services/socket.service"; | |||
| import {Subscription} from "rxjs"; | |||
| import * as L from "leaflet"; | |||
| @Component({ | |||
| selector: 'app-overall-ground', | |||
| templateUrl: './overall-ground.component.html', | |||
| styleUrls: ['./overall-ground.component.scss'] | |||
| selector: 'app-overall-ground', | |||
| templateUrl: './overall-ground.component.html', | |||
| styleUrls: ['./overall-ground.component.scss'] | |||
| }) | |||
| export class OverallGroundComponent implements OnInit, OnDestroy{ | |||
| isClicked = false; | |||
| isConnected = false; | |||
| state1 = ''; | |||
| state2 = ''; | |||
| state3 = ''; | |||
| state4 = ''; | |||
| state5 = ''; | |||
| state6 = ''; | |||
| Sstate1 = false; | |||
| Sstate2 = false; | |||
| private statusSubscription?: Subscription; | |||
| private messageSubscription?: Subscription; | |||
| private intervalId: any; | |||
| export class OverallGroundComponent implements OnInit, OnDestroy { | |||
| isClicked = false; | |||
| isConnected = false; | |||
| states = Array(6).fill(0); | |||
| state1 = ''; | |||
| state2 = ''; | |||
| state3 = ''; | |||
| state4 = ''; | |||
| state5 = ''; | |||
| state6 = ''; | |||
| Sstate1 = false; | |||
| Sstate2 = false; | |||
| imageIcon = 'assets/images/sensor-off.png'; | |||
| private statusSubscription?: Subscription; | |||
| private messageSubscription?: Subscription; | |||
| private intervalId: any; | |||
| constructor(private socketService$: SocketService) { | |||
| } | |||
| constructor(private socketService$: SocketService) { | |||
| } | |||
| ngOnInit() { | |||
| this.socketService$.connect(); | |||
| this.statusSubscription = this.socketService$.status$.subscribe(isConnected => { | |||
| this.isConnected = isConnected; | |||
| if (this.isConnected) { | |||
| this.intervalId = setInterval(() => this.getReadings(), 2000); | |||
| this.messageSubscription = this.socketService$.messages$.subscribe(message => { | |||
| this.onMessage(message); | |||
| }); | |||
| } | |||
| ngOnInit() { | |||
| // this.socketService$.connect(); | |||
| this.statusSubscription = this.socketService$.status$.subscribe(isConnected => { | |||
| this.isConnected = isConnected; | |||
| if (this.isConnected) { | |||
| this.intervalId = setInterval(() => this.getReadings(), 2000); | |||
| this.messageSubscription = this.socketService$.messages$.subscribe(message => { | |||
| this.onMessage(message); | |||
| }); | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| toggleColor(): void { | |||
| this.isClicked = !this.isClicked; | |||
| } | |||
| toggleColor(): void { | |||
| this.isClicked = !this.isClicked; | |||
| } | |||
| ngOnDestroy(): void { | |||
| if (this.statusSubscription) { | |||
| this.statusSubscription.unsubscribe(); | |||
| } | |||
| if (this.messageSubscription) { | |||
| this.messageSubscription.unsubscribe(); | |||
| } | |||
| if (this.intervalId) { | |||
| clearInterval(this.intervalId); | |||
| } | |||
| this.socketService$.close(); | |||
| ngOnDestroy(): void { | |||
| if (this.statusSubscription) { | |||
| this.statusSubscription.unsubscribe(); | |||
| } | |||
| getReadings(){ | |||
| let str = { id: '0', type: 'get' }; | |||
| this.socketService$.sendMessage(str); | |||
| if (this.messageSubscription) { | |||
| this.messageSubscription.unsubscribe(); | |||
| } | |||
| toggleState1() { | |||
| this.Sstate1 = !this.Sstate1; | |||
| let str = { id: '0', type: 'cmd', state1: this.Sstate1.toString() }; | |||
| this.socketService$.sendMessage(str); | |||
| if (this.intervalId) { | |||
| clearInterval(this.intervalId); | |||
| } | |||
| this.socketService$.close(); | |||
| } | |||
| toggleState2() { | |||
| this.Sstate2 = !this.Sstate2; | |||
| let str = { id: '0', type: 'cmd', state2: this.Sstate2.toString() }; | |||
| this.socketService$.sendMessage(str); | |||
| } | |||
| getReadings() { | |||
| let str = {id: '0', type: 'get'}; | |||
| this.socketService$.sendMessage(str); | |||
| } | |||
| getImageSource(state: string): string { | |||
| return state === 'ON' ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png'; | |||
| } | |||
| onMessage(message: any) { | |||
| if (message.id == '0' && message.type === 'get') { | |||
| this.state1 = message.state1 === '1' ? 'ON' : 'OFF'; | |||
| this.state2 = message.state2 === '1' ? 'ON' : 'OFF'; | |||
| this.state3 = message.state3 === '1' ? 'ON' : 'OFF'; | |||
| this.state4 = message.state4 === '1' ? 'ON' : 'OFF'; | |||
| this.state5 = message.state5 === '1' ? 'ON' : 'OFF'; | |||
| this.state6 = message.state6 === '1' ? 'ON' : 'OFF'; | |||
| } | |||
| this.Sstate1 = this.state5 === 'ON'; | |||
| this.Sstate2 = this.state6 === 'ON'; | |||
| toggleState1() { | |||
| this.Sstate1 = !this.Sstate1; | |||
| let str = {id: '0', type: 'cmd', state1: this.Sstate1.toString()}; | |||
| this.socketService$.sendMessage(str); | |||
| } | |||
| toggleState2() { | |||
| this.Sstate2 = !this.Sstate2; | |||
| let str = {id: '0', type: 'cmd', state2: this.Sstate2.toString()}; | |||
| this.socketService$.sendMessage(str); | |||
| } | |||
| getImageSource(): string { | |||
| return (this.Sstate1 && this.Sstate2) || this.Sstate1 ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png'; | |||
| } | |||
| onMessage(message: any) { | |||
| if (message.id == '0' && message.type === 'get') { | |||
| this.state1 = message.state1 === '1' ? 'ON' : 'OFF'; | |||
| this.state2 = message.state2 === '1' ? 'ON' : 'OFF'; | |||
| this.state3 = message.state3 === '1' ? 'ON' : 'OFF'; | |||
| this.state4 = message.state4 === '1' ? 'ON' : 'OFF'; | |||
| this.state5 = message.state5 === '1' ? 'ON' : 'OFF'; | |||
| this.state6 = message.state6 === '1' ? 'ON' : 'OFF'; | |||
| } | |||
| this.Sstate1 = this.state5 === 'ON'; | |||
| this.Sstate2 = this.state6 === 'ON'; | |||
| } | |||
| } | |||
| @@ -7,17 +7,20 @@ import {overviewRoutes} from "./overview.routing"; | |||
| import {MapComponent} from "./map/map.component"; | |||
| import {SharedMaterialModule} from "../../shared/shared-material.module"; | |||
| import {MatIconModule} from "@angular/material/icon"; | |||
| import { CameraStreamComponent } from './camera-stream/camera-stream.component'; | |||
| import {FormsModule} from "@angular/forms"; | |||
| @NgModule({ | |||
| declarations: [ | |||
| OverallGroundComponent, | |||
| MapComponent | |||
| MapComponent, | |||
| CameraStreamComponent | |||
| ], | |||
| imports: [ | |||
| CommonModule, | |||
| RouterModule.forChild(overviewRoutes), | |||
| SharedMaterialModule, | |||
| MatIconModule | |||
| ] | |||
| }) | |||
| export class OverviewModule { } | |||
| @@ -1,6 +1,7 @@ | |||
| import {Routes} from "@angular/router"; | |||
| import {MapComponent} from "./map/map.component"; | |||
| import {OverallGroundComponent} from "./overall-ground/overall-ground.component"; | |||
| import {CameraStreamComponent} from "./camera-stream/camera-stream.component"; | |||
| export const overviewRoutes: Routes = [ | |||
| { | |||
| @@ -10,6 +11,10 @@ export const overviewRoutes: Routes = [ | |||
| { | |||
| path: 'overall-ground', | |||
| component: OverallGroundComponent | |||
| }, | |||
| { | |||
| path: 'camera-stream', | |||
| component: CameraStreamComponent | |||
| } | |||
| ]; | |||
| @@ -1,13 +1,16 @@ | |||
| import { Injectable } from '@angular/core'; | |||
| import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; | |||
| import { BehaviorSubject, Subject } from "rxjs"; | |||
| import { config } from "../../../config"; | |||
| import { config } from "../../../assets/config/config"; | |||
| @Injectable({ | |||
| providedIn: 'root' | |||
| }) | |||
| export class SocketService { | |||
| gateway = config.gateway; | |||
| websocket$!: WebSocketSubject<any> ; | |||
| private isConnected: boolean = false; | |||
| private messagesSubject$ = new Subject(); | |||
| @@ -17,7 +20,6 @@ export class SocketService { | |||
| constructor() { | |||
| } | |||
| public connect(cfg: { reconnect: boolean } = {reconnect: false}): void { | |||
| if (!this.websocket$ || this.websocket$.closed) { | |||
| console.log('Trying to open a WebSocket connection…'); | |||
| @@ -0,0 +1,8 @@ | |||
| export const config = { | |||
| gateway: 'wss:/socket.aztrace.vn/ws' | |||
| }; | |||
| // export function loadConfig() { | |||
| // return { | |||
| // gateway: 'wss:/socket.aztrace.vn/ws' | |||
| // }; | |||
| // } | |||
| @@ -0,0 +1,23 @@ | |||
| const WebSocket = require('ws'); | |||
| const http = require('http'); | |||
| const server = http.createServer(); | |||
| const wss = new WebSocket.Server({ server }); | |||
| wss.on('connection', function connection(ws) { | |||
| ws.on('message', function incoming(message) { | |||
| // Log tin nhắn nhận được | |||
| console.log('Nhận được: %s', message); | |||
| }); | |||
| // Bắt sự kiện khi kết nối đóng | |||
| ws.on('close', function close() { | |||
| console.log('Client đã ngắt kết nối'); | |||
| }); | |||
| }); | |||
| server.listen(8081, function listening() { | |||
| console.log('WebSocket server đang lắng nghe trên cổng 8081'); | |||
| }); | |||
| @@ -0,0 +1,4 @@ | |||
| ffmpeg -rtsp_transport tcp -i rtsp://admin:hd543211@@xuanphuong32.dyndns.org:8001/cam/realmonitor?channel=7&subtype=0 ^ | |||
| -f mpegts -codec:v mpeg1video -s 640x480 -b:v 800k -r 30 ^ | |||
| -codec:a mp2 -b:a 128k ^ | |||
| http://localhost:8081 | |||