| @@ -25,6 +25,7 @@ | |||
| "@asymmetrik/ngx-leaflet-markercluster": "^16.0.0", | |||
| "leaflet": "^1.9.4", | |||
| "rxjs": "~7.8.0", | |||
| "rxjs-websockets": "^9.0.0", | |||
| "tslib": "^2.3.0", | |||
| "zone.js": "~0.13.0" | |||
| }, | |||
| @@ -10,3 +10,24 @@ | |||
| </div> | |||
| </div> | |||
| <div class="topnav"> | |||
| <h1>Test Socket</h1> | |||
| </div> | |||
| <div class="content"> | |||
| <div class="card-grid"> | |||
| <div class="card"> | |||
| <p>Connect</p> | |||
| <p class="state"><span id="Connect">{{ isConnected ? 'Online' : 'Offline' }}</span></p> | |||
| </div> | |||
| <div class="card"> | |||
| <p class="state" id="State1">{{ state1 == '' ? '%STATE%' : state1}}</p> | |||
| <p class="state" id="State2">{{ state2 == '' ? '%STATE%' : state2}}</p> | |||
| <p class="state" id="State3">{{ state3 == '' ? '%STATE%' : state3}}</p> | |||
| <p class="state" id="State4">{{ state4 == '' ? '%STATE%' : state4}}</p> | |||
| <p class="state" id="State5">{{ state5 == '' ? '%STATE%' : state5}}</p> | |||
| <p class="state" id="State6">{{ state6 == '' ? '%STATE%' : state6}}</p> | |||
| <p><button (click)="toggleState1()" id="SetState1" class="button">Set State 1 On</button></p> | |||
| <p><button (click)="toggleState2()" id="SetState2" class="button">Set State 2 On</button></p> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -10,3 +10,92 @@ button { | |||
| background-color: green !important; | |||
| color: white !important; | |||
| } | |||
| h1 { | |||
| font-size: 1.8rem; | |||
| color: white; | |||
| } | |||
| .topnav { | |||
| overflow: hidden; | |||
| background-color: #0A1128; | |||
| } | |||
| body { | |||
| margin: 0; | |||
| } | |||
| p { | |||
| text-align: center; | |||
| } | |||
| .content { | |||
| padding: 50px; | |||
| } | |||
| .card-grid { | |||
| max-width: 800px; | |||
| margin: 0 auto; | |||
| display: grid; | |||
| grid-gap: 2rem; | |||
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |||
| } | |||
| .card { | |||
| background-color: white; | |||
| box-shadow: 2px 2px 12px 1px rgba(140, 140, 140, .5); | |||
| } | |||
| .card-title { | |||
| font-size: 1.2rem; | |||
| font-weight: bold; | |||
| color: #034078 | |||
| } | |||
| .reading { | |||
| font-size: 1.2rem; | |||
| color: #1282A2; | |||
| } | |||
| .button { | |||
| padding: 15px 50px; | |||
| font-size: 24px; | |||
| text-align: center; | |||
| outline: none; | |||
| color: #fff; | |||
| background-color: #0f8b8d; | |||
| border: none; | |||
| border-radius: 5px; | |||
| -webkit-touch-callout: none; | |||
| -webkit-user-select: none; | |||
| -khtml-user-select: none; | |||
| -moz-user-select: none; | |||
| -ms-user-select: none; | |||
| user-select: none; | |||
| -webkit-tap-highlight-color: rgba(0, 0, 0, 0); | |||
| } | |||
| /*.button:hover {background-color: #0f8b8d}*/ | |||
| .button:active { | |||
| background-color: #0f8b8d; | |||
| box-shadow: 2 2px #CDCDCD; | |||
| transform: translateY(2px); | |||
| } | |||
| .state { | |||
| font-size: 1.5rem; | |||
| color: #8c8c8c; | |||
| font-weight: bold; | |||
| text-align: center; | |||
| } | |||
| .content { | |||
| padding: 30px; | |||
| max-width: 600px; | |||
| margin: 0 auto; | |||
| } | |||
| .card { | |||
| background-color: #F8F7F9;; | |||
| box-shadow: 2px 2px 12px 1px rgba(140, 140, 140, .5); | |||
| padding-top: 10px; | |||
| padding-bottom: 20px; | |||
| } | |||
| @@ -1,14 +1,87 @@ | |||
| import { Component } from '@angular/core'; | |||
| import {ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; | |||
| import {SocketService} from "../../../shared/services/socket.service"; | |||
| import {Subscription} from "rxjs"; | |||
| @Component({ | |||
| selector: 'app-overall-ground', | |||
| templateUrl: './overall-ground.component.html', | |||
| styleUrls: ['./overall-ground.component.scss'] | |||
| }) | |||
| export class OverallGroundComponent { | |||
| 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; | |||
| 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); | |||
| }); | |||
| } | |||
| }); | |||
| } | |||
| 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(); | |||
| } | |||
| getReadings(){ | |||
| let str = { id: '0', type: 'get' }; | |||
| this.socketService$.sendMessage(str); | |||
| } | |||
| 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); | |||
| } | |||
| 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'; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,58 @@ | |||
| import { Injectable } from '@angular/core'; | |||
| import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; | |||
| import {BehaviorSubject, catchError, delayWhen, Observable, retryWhen, Subject, tap, timer} from "rxjs"; | |||
| @Injectable({ | |||
| providedIn: 'root' | |||
| }) | |||
| export class SocketService { | |||
| gateway = 'ws:/socket.aztrace.vn/ws'; | |||
| websocket$!: WebSocketSubject<any> ; | |||
| private isConnected: boolean = false; | |||
| private messagesSubject$ = new Subject(); | |||
| public messages$ = this.messagesSubject$.asObservable(); | |||
| private statusSubject = new BehaviorSubject<boolean>(this.isConnected); | |||
| public status$ = this.statusSubject.asObservable(); | |||
| constructor() { | |||
| } | |||
| public connect(cfg: { reconnect: boolean } = {reconnect: false}): void { | |||
| if (!this.websocket$ || this.websocket$.closed) { | |||
| console.log('Trying to open a WebSocket connection…'); | |||
| this.websocket$ = this.getNewWebSocket(); | |||
| this.websocket$.subscribe((messages) => { | |||
| this.messagesSubject$.next(messages); | |||
| }); | |||
| } | |||
| } | |||
| close() { | |||
| this.websocket$.complete(); | |||
| } | |||
| sendMessage(msg: any) { | |||
| this.websocket$.next(msg); | |||
| } | |||
| private getNewWebSocket() { | |||
| return webSocket({ | |||
| url: this.gateway, | |||
| openObserver: { | |||
| next: () => { | |||
| console.log('Connection ok'); | |||
| this.isConnected = true; | |||
| this.statusSubject.next(this.isConnected); | |||
| } | |||
| }, | |||
| closeObserver: { | |||
| next: () => { | |||
| console.log('Connection closed'); | |||
| this.isConnected = false; | |||
| this.connect({reconnect: true}); | |||
| this.statusSubject.next(this.isConnected); | |||
| } | |||
| }, | |||
| }); | |||
| } | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| import { NgModule } from "@angular/core"; | |||
| import { FlexLayoutModule } from "@angular/flex-layout"; | |||
| import {MatButtonModule} from "@angular/material/button"; | |||
| import { MatButtonModule } from "@angular/material/button"; | |||
| @NgModule({ | |||
| exports: [ | |||