Browse Source

Merge branch 'features/camera' of trungnd/iot-web-ui into master

pull/12/head
trungnd 1 year ago
parent
commit
e122313eff
13 changed files with 66 additions and 101 deletions
  1. +1
    -1
      README.md
  2. +2
    -1
      angular.json
  3. +4
    -1
      package.json
  4. +3
    -14
      src/app/app.module.ts
  5. +2
    -6
      src/app/modules/overview/camera-stream/camera-stream.component.html
  6. +4
    -21
      src/app/modules/overview/camera-stream/camera-stream.component.scss
  7. +15
    -11
      src/app/modules/overview/camera-stream/camera-stream.component.ts
  8. +1
    -0
      src/app/modules/overview/overall-ground/overall-ground.component.ts
  9. +1
    -0
      src/app/modules/overview/overview.module.ts
  10. +0
    -18
      src/app/shared/services/app-init.service.ts
  11. +11
    -8
      src/app/shared/services/socket.service.ts
  12. +22
    -16
      src/server/server.js
  13. +0
    -4
      src/server/stream.sh

+ 1
- 1
README.md View File

# LotWebUi
# iotWebUi


This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.2.14. This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.2.14.



+ 2
- 1
angular.json View File

"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"assets": [ "assets": [
"src/favicon.ico", "src/favicon.ico",
"src/assets"
"src/assets",
"src/server"
], ],
"styles": [ "styles": [
"@angular/material/prebuilt-themes/indigo-pink.css", "@angular/material/prebuilt-themes/indigo-pink.css",

+ 4
- 1
package.json View File

"start": "ng serve -o", "start": "ng serve -o",
"build": "ng build", "build": "ng build",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test"
"test": "ng test",
"camera-server": "node dist/lot-web-ui/server/server.js"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/router": "^16.2.0", "@angular/router": "^16.2.0",
"@asymmetrik/ngx-leaflet": "^16.0.1", "@asymmetrik/ngx-leaflet": "^16.0.1",
"@asymmetrik/ngx-leaflet-markercluster": "^16.0.0", "@asymmetrik/ngx-leaflet-markercluster": "^16.0.0",
"express": "^4.19.2",
"express-ws": "^5.0.2",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"ngx-toastr": "^17.0.2", "ngx-toastr": "^17.0.2",
"rtsp-relay": "^1.8.0", "rtsp-relay": "^1.8.0",

+ 3
- 14
src/app/app.module.ts View File

import {APP_INITIALIZER, NgModule} from '@angular/core';
import { 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 { 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 {HttpClientModule} from "@angular/common/http";
import {AppInitService} from "./shared/services/app-init.service";
import { ToastrModule } from 'ngx-toastr'; import { ToastrModule } from 'ngx-toastr';


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





@NgModule({ @NgModule({
autoDismiss: true autoDismiss: true
}), // ToastrModule added }), // ToastrModule added
], ],
providers: [

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

+ 2
- 6
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>
<h3 style="text-align: center">Camera Stream</h3>
<canvas class="video" #videoPlayer></canvas>

+ 4
- 21
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;
.video {
width: 78% !important;
display: block;
margin: 0 auto
} }

+ 15
- 11
src/app/modules/overview/camera-stream/camera-stream.component.ts View File

export class CameraStreamComponent implements OnInit, AfterViewInit{ export class CameraStreamComponent implements OnInit, AfterViewInit{
player?: Player; player?: Player;


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

constructor(private el: ElementRef, private renderer: Renderer2) {}


ngOnInit() { ngOnInit() {
} }
constructor(private el: ElementRef, private renderer: Renderer2) {}
async ngAfterViewInit() { async ngAfterViewInit() {
// this.player = await loadPlayer({
// url: 'ws://localhost:8081',
// canvas: this.videoPlayer!.nativeElement,
//
// onDisconnect: () => console.log('Connection lost!'),
// });
//
// console.log('Connected!', this.player);
const connect = async () => {
this.player = await loadPlayer({
url: 'ws://localhost:8080/stream',
canvas: this.videoPlayer!.nativeElement,
onDisconnect: () => {
setTimeout(connect, 5000); // reconnect after 5 seconds
},
});
};
connect();
} }





+ 1
- 0
src/app/modules/overview/overall-ground/overall-ground.component.ts View File

import {Subscription} from "rxjs"; import {Subscription} from "rxjs";
import {ToastrService} from "ngx-toastr"; import {ToastrService} from "ngx-toastr";



@Component({ @Component({
selector: 'app-overall-ground', selector: 'app-overall-ground',
templateUrl: './overall-ground.component.html', templateUrl: './overall-ground.component.html',

+ 1
- 0
src/app/modules/overview/overview.module.ts View File

import {SharedMaterialModule} from "../../shared/shared-material.module"; import {SharedMaterialModule} from "../../shared/shared-material.module";
import { CameraStreamComponent } from './camera-stream/camera-stream.component'; import { CameraStreamComponent } from './camera-stream/camera-stream.component';



@NgModule({ @NgModule({
declarations: [ declarations: [
OverallGroundComponent, OverallGroundComponent,

+ 0
- 18
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);
});
}
}

+ 11
- 8
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 "../../../assets/config/config"; import { config } from "../../../assets/config/config";




export class SocketService { export class SocketService {
gateway = config.gateway; gateway = config.gateway;



websocket$!: WebSocketSubject<any> ;
websocket$: WebSocketSubject<any> | undefined ;
private isConnected: boolean = false; private isConnected: boolean = false;
private messagesSubject$ = new Subject(); private messagesSubject$ = new Subject();
public messages$ = this.messagesSubject$.asObservable(); public messages$ = this.messagesSubject$.asObservable();


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

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

} }


close() { close() {
this.websocket$.complete();
this.websocket$?.complete();
this.websocket$ = undefined;
} }


sendMessage(msg: any) { sendMessage(msg: any) {
this.websocket$.next(msg);
this.websocket$?.next(msg);
} }


private getNewWebSocket() { private getNewWebSocket() {
closeObserver: { closeObserver: {
next: () => { next: () => {
console.log('Connection closed'); console.log('Connection closed');
this.websocket$ = undefined;
this.isConnected = false; this.isConnected = false;
this.connect({reconnect: true}); this.connect({reconnect: true});
this.statusSubject.next(this.isConnected); this.statusSubject.next(this.isConnected);

+ 22
- 16
src/server/server.js View File

const WebSocket = require('ws');
const http = require('http');
const express = require('express');
const expressWs = require('express-ws');
const app = express();
expressWs(app);


const server = http.createServer();
const { proxy, scriptUrl } = require('rtsp-relay')(app);


const wss = new WebSocket.Server({ server });
const port = 8080;
const urlCamera = 'rtsp://admin:[email protected]:88/cam/realmonitor?channel=1&subtype=0';


wss.on('connection', function connection(ws) {
app.ws('/api/stream/:cameraIP', (ws, req) =>
proxy({
url: `rtsp://${req.params.cameraIP}:554/feed`,
})(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');
});
const handler = proxy({
url: urlCamera,
verbose: false,
transport: 'tcp'
}); });


server.listen(8081, function listening() {
console.log('WebSocket server đang lắng nghe trên cổng 8081');

app.ws('/stream', handler);

const server = app.listen(port, () => {
console.log(`RTSP Relay Server is listening on port ${port}`);
}); });


+ 0
- 4
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