@@ -4,12 +4,16 @@ import { SerialConnector } from './serial-connector';
44import fs from 'fs' ;
55import Path from 'path' ;
66import EiSerialProtocol , {
7- EiSerialDeviceConfig
7+ EiSerialDeviceConfig , EiSerialSensor
88} from '../shared/daemon/ei-serial-protocol' ;
99import { Config } from './config' ;
1010import { findSerial } from './find-serial' ;
1111import checkNewVersions from './check-new-version' ;
1212import { getCliVersion } from './init-cli-app' ;
13+ import express = require ( 'express' ) ;
14+ import http from 'http' ;
15+ import socketIO from 'socket.io' ;
16+ import { ips } from './get-ips' ;
1317
1418const SERIAL_PREFIX = '\x1b[33m[SER]\x1b[0m' ;
1519
@@ -23,6 +27,8 @@ const whichDeviceArgv = whichDeviceArgvIx !== -1 ? Number(process.argv[whichDevi
2327
2428let stdinAttached = false ;
2529let serial : SerialConnector | undefined ;
30+ let startedWebserver = false ;
31+ let inferenceStarted = false ;
2632
2733const configFactory = new Config ( ) ;
2834// tslint:disable-next-line:no-floating-promises
@@ -111,10 +117,10 @@ async function connectToSerial(deviceId: string) {
111117 process . on ( 'SIGHUP' , onSignal ) ;
112118 process . on ( 'SIGINT' , onSignal ) ;
113119
114- let inferenceStarted = false ;
120+ let logMessages = true ;
115121
116122 serial . on ( 'data' , data => {
117- if ( ( serial && serial . isConnected ( ) && inferenceStarted ) || rawArgv ) {
123+ if ( ( ( serial && serial . isConnected ( ) && inferenceStarted ) || rawArgv ) && logMessages ) {
118124 process . stdout . write ( data . toString ( 'ascii' ) ) ;
119125 }
120126 } ) ;
@@ -168,6 +174,23 @@ async function connectToSerial(deviceId: string) {
168174 mode = 'debug' ;
169175 }
170176
177+ if ( config . inference . sensor === EiSerialSensor . EI_CLASSIFIER_SENSOR_CAMERA ) {
178+ if ( mode !== 'debug' ) {
179+ console . log ( '' ) ;
180+ console . log ( SERIAL_PREFIX ,
181+ 'To get a live feed of the camera and live classification in your browser, run with --debug' ) ;
182+ console . log ( '' ) ;
183+ }
184+ else {
185+ let webserverPort = await startWebServer ( config ) ;
186+ console . log ( '' ) ;
187+ console . log ( 'Want to see a feed of the camera and live classification in your browser? ' +
188+ 'Go to http://' + ( ips . length > 0 ? ips [ 0 ] . address : 'localhost' ) + ':' + webserverPort ) ;
189+ console . log ( '' ) ;
190+ logMessages = false ;
191+ }
192+ }
193+
171194 await serialProtocol . startInference ( mode ) ;
172195
173196 console . log ( SERIAL_PREFIX , 'Started inferencing, press CTRL+C to stop...' ) ;
@@ -204,3 +227,134 @@ async function connectToSerial(deviceId: string) {
204227 // tslint:disable-next-line:no-floating-promises
205228 serial_connect ( ) ;
206229}
230+
231+ async function startWebServer ( config : EiSerialDeviceConfig ) {
232+ if ( ! serial ) return ;
233+ if ( startedWebserver ) return ;
234+
235+ startedWebserver = true ;
236+
237+ const app = express ( ) ;
238+ app . use ( express . static ( Path . join ( __dirname , '..' , '..' , 'public' ) ) ) ;
239+
240+ const server = new http . Server ( app ) ;
241+ const io = socketIO ( server ) ;
242+
243+ server . listen ( Number ( process . env . PORT ) || 4915 , process . env . HOST || '0.0.0.0' , async ( ) => {
244+ // noop
245+ } ) ;
246+
247+ let currentMsg : string | undefined ;
248+ serial . on ( 'data' , ( data : Buffer ) => {
249+ let s = data . toString ( 'utf-8' ) ;
250+ if ( s . indexOf ( 'End output' ) > - 1 ) {
251+ if ( typeof currentMsg === 'string' ) {
252+ currentMsg += s . substr ( 0 , s . indexOf ( 'End output' ) ) ;
253+
254+ let lines = currentMsg . split ( '\n' ) ;
255+ let fb = lines . find ( x => x . startsWith ( 'Framebuffer: ' ) ) ;
256+
257+ let printMsg = '' ;
258+
259+ let classifyTime = 0 ;
260+ let timingLine = lines . find ( x => x . startsWith ( 'Predictions' ) ) ;
261+ if ( timingLine ) {
262+ let m = timingLine . match ( / C l a s s i f i c a t i o n : ( \d + ) / ) ;
263+ if ( m ) {
264+ classifyTime = Number ( m [ 1 ] ) ;
265+ }
266+ printMsg += timingLine + '\n' ;
267+ }
268+
269+ if ( fb ) {
270+ fb = fb . replace ( 'Framebuffer: ' , '' ) . trim ( ) ;
271+
272+ let snapshot = Buffer . from ( fb , 'base64' ) ;
273+ io . emit ( 'image' , {
274+ img : 'data:image/jpeg;base64,' + snapshot . toString ( 'base64' )
275+ } ) ;
276+ }
277+
278+ let mode : 'classification' | 'object_detection' ;
279+ let firstClassifyLine = lines . find ( x => x . startsWith ( ' ' ) ) ;
280+ if ( firstClassifyLine && ! isNaN ( Number ( firstClassifyLine . split ( ':' ) [ 1 ] ) ) ) {
281+ mode = 'classification' ;
282+ }
283+ else {
284+ mode = 'object_detection' ;
285+ }
286+
287+ if ( mode === 'object_detection' ) {
288+ let cubes = [ ] ;
289+ // parse object detection
290+ for ( let l of lines . filter ( x => x . startsWith ( ' ' ) && x . indexOf ( 'width:' ) > - 1 ) ) {
291+ let m = l . trim ( )
292+ . match ( / ^ ( \w + ) \( ( [ \w \. ] + ) \) \[ x : ( \d + ) , y : ( \d + ) , w i d t h : ( \d + ) , h e i g h t : ( \d + ) / ) ;
293+ if ( ! m ) continue ;
294+ let cube = {
295+ label : m [ 1 ] ,
296+ value : Number ( m [ 2 ] ) ,
297+ x : Number ( m [ 3 ] ) ,
298+ y : Number ( m [ 4 ] ) ,
299+ width : Number ( m [ 5 ] ) ,
300+ height : Number ( m [ 6 ] ) ,
301+ } ;
302+ cubes . push ( cube ) ;
303+ printMsg += l + '\n' ;
304+ }
305+
306+ io . emit ( 'classification' , {
307+ result : {
308+ bounding_boxes : cubes
309+ } ,
310+ timeMs : classifyTime ,
311+ } ) ;
312+ }
313+ else {
314+ let results : { [ k : string ] : number } = { } ;
315+ // parse object detection
316+ for ( let l of lines . filter ( x => x . startsWith ( ' ' ) ) ) {
317+ let m = l . split ( ':' ) . map ( x => x . trim ( ) ) ;
318+ if ( m . length !== 2 ) continue ;
319+ results [ m [ 0 ] ] = Number ( m [ 1 ] ) ;
320+ printMsg += l + '\n' ;
321+ }
322+
323+ io . emit ( 'classification' , {
324+ result : {
325+ classification : results
326+ } ,
327+ timeMs : classifyTime ,
328+ } ) ;
329+ }
330+
331+ if ( inferenceStarted ) {
332+ console . log ( printMsg . trim ( ) ) ;
333+ }
334+ }
335+
336+ currentMsg = undefined ;
337+ s = s . substr ( s . indexOf ( 'End output' ) ) ;
338+ }
339+
340+ if ( s . indexOf ( 'Begin output' ) > - 1 ) {
341+ s = s . substr ( s . indexOf ( 'Begin output' ) + 'Begin output' . length ) ;
342+ currentMsg = s ;
343+ return ;
344+ }
345+
346+ if ( currentMsg ) {
347+ currentMsg += s ;
348+ }
349+
350+ // console.log('data', data.toString('utf-8');
351+ } ) ;
352+
353+ io . on ( 'connection' , socket => {
354+ socket . emit ( 'hello' , {
355+ projectName : 'Live classification on ' + config . info . type
356+ } ) ;
357+ } ) ;
358+
359+ return Number ( process . env . PORT ) || 4915 ;
360+ }
0 commit comments