#5 features/getway

Merged
trungnd merged 4 commits from features/getway into master 1 year ago
  1. +308
    -0
      src/app/app.constants.ts
  2. +18
    -2
      src/app/app.module.ts
  3. +6
    -0
      src/app/modules/overview/camera-stream/camera-stream.component.html
  4. +22
    -0
      src/app/modules/overview/camera-stream/camera-stream.component.scss
  5. +21
    -0
      src/app/modules/overview/camera-stream/camera-stream.component.spec.ts
  6. +30
    -0
      src/app/modules/overview/camera-stream/camera-stream.component.ts
  7. +2
    -1
      src/app/modules/overview/map/map.component.html
  8. +5
    -1
      src/app/modules/overview/map/map.component.scss
  9. +79
    -79
      src/app/modules/overview/map/map.component.ts
  10. +76
    -21
      src/app/modules/overview/overall-ground/overall-ground.component.html
  11. +33
    -8
      src/app/modules/overview/overall-ground/overall-ground.component.scss
  12. +18
    -8
      src/app/modules/overview/overall-ground/overall-ground.component.ts
  13. +5
    -2
      src/app/modules/overview/overview.module.ts
  14. +5
    -0
      src/app/modules/overview/overview.routing.ts
  15. +18
    -0
      src/app/shared/services/app-init.service.ts
  16. +4
    -2
      src/app/shared/services/socket.service.ts
  17. +0
    -0
      src/assets/config/config.ts
  18. BIN
      src/assets/images/camera.png
  19. BIN
      src/assets/video/video.mp4
  20. +23
    -0
      src/server/server.js
  21. +4
    -0
      src/server/stream.sh

+ 308
- 0
src/app/app.constants.ts View File

export const ICON = {
sensorOff: `<div style="display: flex;
flex-direction: column;
align-items: center">
<div style="display: flex; flex-direction: row; gap: 5px">
<div class="tooltip">
<img style="width: 30px; height: 30px;" src="assets/images/sensor-off.png">
<div class="tooltiptext">
<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>
</div>
</div>

<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
</div>
<style>
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 300px;
padding: 10px;
background-color: #fff;
color: black;
border-radius: 6px;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
margin-left: -60px;
}

.tooltip:hover .tooltiptext {
visibility: visible;
}
</style>`,
sensorOn: `<div style="display: flex;
flex-direction: column;
align-items: center">
<div style="display: flex; flex-direction: row; gap: 5px">
<div class="tooltip">
<img style="width: 30px; height: 30px;" src="assets/images/sensor-on.png">
<div class="tooltiptext">
<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>
</div>
</div>

<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
<!-- <div style="font-size: 11px"><b>ALARM: SMOKE ALERT</b></div>-->
</div>
<style>
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 300px;
padding: 10px;
background-color: #fff;
color: black;
border-radius: 6px;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
margin-left: -60px;
}

.tooltip:hover .tooltiptext {
visibility: visible;
}
</style>`,
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" target="_blank">
<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>`,

sensorActiveSmoke: `
<div style="display: flex;
flex-direction: column;
align-items: center">
<div style="display: flex; flex-direction: row; gap: 39px;width: 100%; justify-content: center;">
<div class="tooltip">
<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>

<div class="tooltiptext">
<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>
</div>
</div>

<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
<div style="background: #F11E1E; color: #FFF; padding: 2px 3px; font-size: 11px"><b>ALARM: SMOKE ALERT</b></div>
</div>
<style>
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 300px;
padding: 10px;
background-color: #fff;
color: black;
border-radius: 6px;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
margin-left: -60px;
}

.tooltip:hover .tooltiptext {
visibility: visible;
}
@keyframes sensor-on {
100% {
transform: scale(2);
opacity: 0;
}
}
</style>`,
sensorActiveVib: `
<div style="display: flex;
flex-direction: column;
align-items: center">
<div style="display: flex; flex-direction: row; gap: 39px;width: 100%; justify-content: center;">
<div class="tooltip">
<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>

<div class="tooltiptext">
<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>
</div>
</div>

<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
<div style="background: #F11E1E; color: #FFF; padding: 2px 3px; font-size: 11px"><b>ALARM: VIBRATION ALERT</b></div>
</div>
<style>
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 300px;
padding: 10px;
background-color: #fff;
color: black;
border-radius: 6px;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
margin-left: -60px;
}

.tooltip:hover .tooltiptext {
visibility: visible;
}
@keyframes sensor-on {
100% {
transform: scale(2);
opacity: 0;
}
}
</style>`,
}

+ 18
- 2
src/app/app.module.ts View File

import { NgModule } from '@angular/core';
import {APP_INITIALIZER, NgModule} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';


import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {SharedModule} from "./shared/shared.module"; import {SharedModule} from "./shared/shared.module";
import {HttpClientModule} from "@angular/common/http";
import {AppInitService} from "./shared/services/app-init.service";

export function appInitializerFactory(appInitializerService: AppInitService): () => Promise<any> {
return () => appInitializerService.initializeApp();
}



@NgModule({ @NgModule({
declarations: [ declarations: [
AppRoutingModule, AppRoutingModule,
BrowserAnimationsModule, BrowserAnimationsModule,
SharedModule, SharedModule,
HttpClientModule
],
providers: [

{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps: [AppInitService],
multi: true
}
], ],
providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule { }

+ 6
- 0
src/app/modules/overview/camera-stream/camera-stream.component.html View File

<h3>Camera Stream</h3>
<!--<canvas #videoPlayer></canvas>-->

<video width="700" controls style="display: block; margin-left: auto; margin-right: auto">
<source src="assets/video/video.mp4" type="video/mp4">
</video>

+ 22
- 0
src/app/modules/overview/camera-stream/camera-stream.component.scss View File

.tooltip {
position: relative;
display: inline-block;
}

.tooltip .tooltiptext {
visibility: hidden;
width: 300px;
padding: 10px;
background-color: #fff;
color: black;
border-radius: 6px;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
margin-left: -60px;
}

.tooltip:hover .tooltiptext {
visibility: visible;
}

+ 21
- 0
src/app/modules/overview/camera-stream/camera-stream.component.spec.ts View File

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();
});
});

+ 30
- 0
src/app/modules/overview/camera-stream/camera-stream.component.ts View File

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);
}


}

+ 2
- 1
src/app/modules/overview/map/map.component.html View File

<div class="map-container"> <div class="map-container">
<h2>ATMs Security Monitoring and Control</h2>
<div class="map-frame"> <div class="map-frame">
<div id="map"></div> <!-- Ensure no extra space after "map" -->
<div id="map"></div>
</div> </div>
</div> </div>



+ 5
- 1
src/app/modules/overview/map/map.component.scss View File



.map-frame { .map-frame {
border: 2px solid black; border: 2px solid black;
height: 100%;
height: 90%;
} }


#map { #map {
padding: 3px 2px; padding: 3px 2px;
background-color: rbg(243,49,82,0.1); background-color: rbg(243,49,82,0.1);
} }
.hidden-background{
background: transparent;
border: none;
}

+ 79
- 79
src/app/modules/overview/map/map.component.ts View File

import {AfterViewInit, Component, OnDestroy, OnInit} from '@angular/core';
import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
import * as L from 'leaflet'; 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({ @Component({
selector: 'app-map', selector: 'app-map',
styleUrls: ['./map.component.scss'] styleUrls: ['./map.component.scss']
}) })
export class MapComponent implements OnInit, AfterViewInit, OnDestroy { export class MapComponent implements OnInit, AfterViewInit, OnDestroy {
private map: any;
houseIcon = L.icon({
iconUrl: '../../../../assets/images/icon.png',
iconSize: [38, 48],
shadowSize: [50, 64],
private map!: L.Map;
private featureGroup!: L.FeatureGroup;
private statusSubscription?: Subscription;
private messageSubscription?: Subscription;
sensorOff = ICON.sensorOff;
sensorOn = ICON.sensorOn;
sensorSmoke = ICON.sensorActiveSmoke;
sensorVib = ICON.sensorActiveVib;

sensorSmokeIcon = L.divIcon({
html: this.sensorSmoke,
iconSize: [170, 48],
className: 'hidden-background'
});

sensorVibIcon = L.divIcon({
html: this.sensorVib,
iconSize: [170, 48],
className: 'hidden-background'
});

sensorOffIcon = L.divIcon({
html: this.sensorOff,
iconSize: [150, 38],
className: 'hidden-background'
}); });
fireIcon = L.icon({
iconUrl: '../../../../assets/images/fire.gif',
iconSize: [38, 48],
})

sensorOnIcon = L.divIcon({ 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]
html: this.sensorOn,
iconSize: [150, 38],
className: 'hidden-background'
}); });
// sensorOffIcon = L.icon({
// iconUrl: '../../../../assets/images/sensor-off.png',
// iconSize: [38, 38],
// });

// sensorOnIcon = L.icon({
// iconUrl: '../../../../assets/images/sensor-on.png',
// iconSize: [38, 38],
// });


sensorOffIcon = L.icon({
iconUrl: '../../../../assets/images/sensor-off.png',
iconSize: [38, 38],
})


state5 = false; state5 = false;
state6 = false; state6 = false;


private statusSubscription?: Subscription;
private messageSubscription?: Subscription;

constructor(private socketService$: SocketService) {}

constructor(private socketService$: SocketService) { }


ngOnInit() { ngOnInit() {
this.statusSubscription = this.socketService$.status$.subscribe(isConnected => { this.statusSubscription = this.socketService$.status$.subscribe(isConnected => {
} }
}); });
} }
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 { ngAfterViewInit(): void {
this.initMap(); this.initMap();
} }


ngOnDestroy(): void {
this.statusSubscription?.unsubscribe();
this.messageSubscription?.unsubscribe();
this.socketService$.close();
}

private initMap(): void { private initMap(): void {
const mapContainer = document.getElementById('map'); const mapContainer = document.getElementById('map');
if (mapContainer) { if (mapContainer) {
this.map = L.map('map', { this.map = L.map('map', {
center: [10.8494, 106.7537 ],
center: [10.8494, 106.7537],
zoom: 12 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, maxZoom: 18,
minZoom: 3, minZoom: 3,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' attribution: '&copy; <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 { } else {
console.error('Map container not found'); 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() { addIconToMap() {
//add marker
let popupContent = `<div>Vinhome quận 9</div>
const popupContent = `<div>Vinhome quận 9</div>
<a href="/overview/overall-ground" target="_blank">Xem chi tiết</a>`; <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 fireContent = ICON.fireContent;

L.marker([10.8356, 106.8300], {icon: this.applyIcon(this.state5, this.state6, 'smoke')})
.addTo(this.map) .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, 'vib')})
.addTo(this.map) .addTo(this.map)
.bindPopup(fireContent);

} }


updateIcons(): void { updateIcons(): void {


this.addIconToMap(); this.addIconToMap();
} }

applyIcon(state1: boolean, state2: boolean, type:any): L.Icon | L.DivIcon {
if (state1 && state2) {
return type==='smoke' ? this.sensorSmokeIcon : this.sensorVibIcon;
}
if (state1) {
return this.sensorOnIcon;
}
return this.sensorOffIcon;
}
} }

+ 76
- 21
src/app/modules/overview/overall-ground/overall-ground.component.html View File

<div class="p-3" fxLayout="row" fxLayoutAlign="space-around center" fxLayoutGap="20px">
<div class="px-3 py-5" fxLayout="row" fxLayoutAlign="space-around center" fxLayoutGap="20px">
<div fxFlex="50" class="map-image"> <div fxFlex="50" class="map-image">
<div class="card-state"> <div class="card-state">
<img src="assets/images/ground.png"> <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 class="state t1" id="State1">
<div>
<img src="assets/images/sensor-off.png" style="width: 30px; height: 30px">
<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
</div>

<div class="state t2" id="State2">
<div>
<img src="assets/images/sensor-off.png" style="width: 30px; height: 30px">
<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
</div>

<div class="state t3" id="State3">
<div>
<img src="assets/images/sensor-off.png" style="width: 30px; height: 30px">
<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
</div>
<div class="state t4" id="State4">
<div>
<img src="assets/images/sensor-off.png" style="width: 30px; height: 30px">
<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
</div>
<div class="state t5" id="State5" >
<div>
<div [ngClass]="{'sensor-on': Sstate1 && Sstate2,
'sensor-off': !(Sstate1 && Sstate2)}">
<img [src]="getImageSource()" style="width: 30px; height: 30px">
</div>
<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
<ng-template [ngIf]="Sstate1 && Sstate2">
<div class="alarm-text"
[ngClass]="{'alarm-text-on': Sstate1 && Sstate2 }">ALARM: <br>VIBRATION ALERT</div>
</ng-template>

</div>
<div class="state t6 " id="State6">
<div>
<div [ngClass]="{'sensor-on': Sstate1 && Sstate2,
'sensor-off': !(Sstate1 && Sstate2)}">
<img [src]="getImageSource()" style="width: 30px; height: 30px">
</div>
<a href="/overview/camera-stream" target="_blank">
<img style="width: 30px; height: 30px;" src="assets/images/camera.png">
</a>
</div>
<ng-template [ngIf]="Sstate1 && Sstate2">
<div class="alarm-text"
[ngClass]="{'alarm-text-on': Sstate1 && Sstate2 }">ALARM: <br>SMOKE ALERT</div>
</ng-template>

</div>


<!-- <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> </div>
<div fxFlex="30" fxLayout="column" fxLayoutGap="50px"> <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>
<button [disabled]="!isConnected" mat-flat-button color="{{Sstate1 ? 'accent' : 'primary'}}" (click)="toggleState1()">{{ Sstate1 ? 'DISARM' : 'ARM'}}</button>
<button [disabled]="!isConnected" mat-flat-button color="{{Sstate2 ? 'accent' : 'primary'}}" (click)="toggleState2()">{{ Sstate2 ? 'TURN OFF WARNING' : 'TURN ON WARNING'}}</button>
<button mat-stroked-button color="primary" [routerLink]="'/overview/camera-stream'" target="_blank"> LIVE CAMERA </button>
</div> </div>
</div> </div>

+ 33
- 8
src/app/modules/overview/overall-ground/overall-ground.component.scss View File

position: absolute; position: absolute;
color: red; color: red;
&.t1{ &.t1{
top: 8%;
top: 5%;
left: 10%; left: 10%;
} }
&.t2{ &.t2{
top: 8%;
left: 47%;
top: 5%;
left: 42%;
} }
&.t3{ &.t3{
top: 8%;
top: 5%;
right: 12%; right: 12%;
} }
&.t4{ &.t4{
} }
&.t5{ &.t5{
top: 88%; top: 88%;
left: 47%;
left: 42%;
width: 100px;
.alarm-text-off{
width: 100px !important;
}
} }
&.t6{ &.t6{
top: 47%; top: 47%;
left: 10%;
left: 5%;
width: 100px;
.alarm-text-off{
width: 100px !important;
}
} }
} }


height: 30px; height: 30px;
position: absolute; position: absolute;
background: linear-gradient(#ff0000, #C70039); background: linear-gradient(#ff0000, #C70039);
display: flex;
display: flex !important;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-radius: 50%; border-radius: 50%;
animation: sensor-on 2s 1s ease-out infinite; animation: sensor-on 2s 1s ease-out infinite;
} }
} }
.sensor-off{
display: inline-block;
}
@keyframes sensor-on{ @keyframes sensor-on{
100%{ 100%{
transform: scale(2); transform: scale(2);
} }
} }
} }
.button-on {
.alarm-text{
font-size: 10px;
padding: 2px 4px;
width: 100px;
margin-top: 10px;
margin-left: -22px;
border-radius: 2px;
&-off {
background: #bfe9f4;
color: #004aad;
}
&-on{
background: #F11E1E;
color: #FFF;
}


} }

+ 18
- 8
src/app/modules/overview/overall-ground/overall-ground.component.ts View File

import {ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; import {ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core';
import {SocketService} from "../../../shared/services/socket.service"; import {SocketService} from "../../../shared/services/socket.service";
import {Subscription} from "rxjs"; import {Subscription} from "rxjs";
import * as L from "leaflet";


@Component({ @Component({
selector: 'app-overall-ground', selector: 'app-overall-ground',
templateUrl: './overall-ground.component.html', templateUrl: './overall-ground.component.html',
styleUrls: ['./overall-ground.component.scss'] styleUrls: ['./overall-ground.component.scss']
}) })
export class OverallGroundComponent implements OnInit, OnDestroy{
export class OverallGroundComponent implements OnInit, OnDestroy {
isClicked = false; isClicked = false;
isConnected = false; isConnected = false;
states = Array(6).fill(0);
state1 = ''; state1 = '';
state2 = ''; state2 = '';
state3 = ''; state3 = '';
state6 = ''; state6 = '';
Sstate1 = false; Sstate1 = false;
Sstate2 = false; Sstate2 = false;
imageIcon = 'assets/images/sensor-off.png';
title = 'ALARM: SMOKE ALERT'
private statusSubscription?: Subscription; private statusSubscription?: Subscription;
private messageSubscription?: Subscription; private messageSubscription?: Subscription;
private intervalId: any; private intervalId: any;
} }


ngOnInit() { ngOnInit() {
this.socketService$.connect();
// this.socketService$.connect();
this.statusSubscription = this.socketService$.status$.subscribe(isConnected => { this.statusSubscription = this.socketService$.status$.subscribe(isConnected => {
this.isConnected = isConnected; this.isConnected = isConnected;
if (this.isConnected) { if (this.isConnected) {
this.socketService$.close(); this.socketService$.close();
} }


getReadings(){
let str = { id: '0', type: 'get' };
getReadings() {
let str = {id: '0', type: 'get'};
this.socketService$.sendMessage(str); this.socketService$.sendMessage(str);
} }

toggleState1() { toggleState1() {
this.Sstate1 = !this.Sstate1; this.Sstate1 = !this.Sstate1;
let str = { id: '0', type: 'cmd', state1: this.Sstate1.toString() };
let str = {id: '0', type: 'cmd', state1: this.Sstate1.toString()};
this.socketService$.sendMessage(str); this.socketService$.sendMessage(str);
} }


toggleState2() { toggleState2() {
this.Sstate2 = !this.Sstate2; this.Sstate2 = !this.Sstate2;
let str = { id: '0', type: 'cmd', state2: this.Sstate2.toString() };
let str = {id: '0', type: 'cmd', state2: this.Sstate2.toString()};
this.socketService$.sendMessage(str); this.socketService$.sendMessage(str);
} }


getImageSource(state: string): string {
return state === 'ON' ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png';
getImageSource(): string {
return (this.Sstate1 && this.Sstate2) || this.Sstate1 ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png';
} }

onMessage(message: any) { onMessage(message: any) {
if (message.id == '0' && message.type === 'get') { if (message.id == '0' && message.type === 'get') {
this.state1 = message.state1 === '1' ? 'ON' : 'OFF'; this.state1 = message.state1 === '1' ? 'ON' : 'OFF';
} }
this.Sstate1 = this.state5 === 'ON'; this.Sstate1 = this.state5 === 'ON';
this.Sstate2 = this.state6 === 'ON'; this.Sstate2 = this.state6 === 'ON';
if(this.Sstate1 && this.Sstate2)
this.title = 'ALARM: VIBRATION ALERT'

} }

} }

+ 5
- 2
src/app/modules/overview/overview.module.ts View File

import {MapComponent} from "./map/map.component"; import {MapComponent} from "./map/map.component";
import {SharedMaterialModule} from "../../shared/shared-material.module"; import {SharedMaterialModule} from "../../shared/shared-material.module";
import {MatIconModule} from "@angular/material/icon"; import {MatIconModule} from "@angular/material/icon";
import { CameraStreamComponent } from './camera-stream/camera-stream.component';
import {FormsModule} from "@angular/forms";


@NgModule({ @NgModule({
declarations: [ declarations: [
OverallGroundComponent, OverallGroundComponent,
MapComponent
MapComponent,
CameraStreamComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild(overviewRoutes), RouterModule.forChild(overviewRoutes),
SharedMaterialModule, SharedMaterialModule,
MatIconModule
] ]
}) })
export class OverviewModule { } export class OverviewModule { }

+ 5
- 0
src/app/modules/overview/overview.routing.ts View File

import {Routes} from "@angular/router"; import {Routes} from "@angular/router";
import {MapComponent} from "./map/map.component"; import {MapComponent} from "./map/map.component";
import {OverallGroundComponent} from "./overall-ground/overall-ground.component"; import {OverallGroundComponent} from "./overall-ground/overall-ground.component";
import {CameraStreamComponent} from "./camera-stream/camera-stream.component";


export const overviewRoutes: Routes = [ export const overviewRoutes: Routes = [
{ {
{ {
path: 'overall-ground', path: 'overall-ground',
component: OverallGroundComponent component: OverallGroundComponent
},
{
path: 'camera-stream',
component: CameraStreamComponent
} }


]; ];

+ 18
- 0
src/app/shared/services/app-init.service.ts View File

import { Injectable } from '@angular/core';
import {config} from "../../../assets/config/config";

@Injectable({
providedIn: 'root'
})
export class AppInitService {
appConfig = config;

constructor() {}

initializeApp(): Promise<any> {
return new Promise((resolve, reject) => {
console.log('Loaded:', this.appConfig);
resolve(true);
});
}
}

+ 4
- 2
src/app/shared/services/socket.service.ts View File

import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
import { BehaviorSubject, Subject } from "rxjs"; import { BehaviorSubject, Subject } from "rxjs";
import { config } from "../../../config";
import { config } from "../../../assets/config/config";



@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class SocketService { export class SocketService {
gateway = config.gateway; gateway = config.gateway;


websocket$!: WebSocketSubject<any> ; websocket$!: WebSocketSubject<any> ;
private isConnected: boolean = false; private isConnected: boolean = false;
private messagesSubject$ = new Subject(); private messagesSubject$ = new Subject();


constructor() { constructor() {
} }

public connect(cfg: { reconnect: boolean } = {reconnect: false}): void { public connect(cfg: { reconnect: boolean } = {reconnect: false}): void {
if (!this.websocket$ || this.websocket$.closed) { if (!this.websocket$ || this.websocket$.closed) {
console.log('Trying to open a WebSocket connection…'); console.log('Trying to open a WebSocket connection…');

src/config.ts → src/assets/config/config.ts View File


BIN
src/assets/images/camera.png View File

Before After
Width: 576  |  Height: 570  |  Size: 19KB

BIN
src/assets/video/video.mp4 View File


+ 23
- 0
src/server/server.js View File

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');
});

+ 4
- 0
src/server/stream.sh View File

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

Loading…
Cancel
Save