@@ -223,6 +223,29 @@ function toDetailedObject(peripheral, RED) {
223223
224224export default function ( RED ) {
225225
226+ function toCharacteristic ( c ) {
227+ let obj = {
228+ uuid : c . uuid ,
229+ name : c . name || RED . _ ( 'generic-ble.label.unnamedChr' ) ,
230+ type : c . type || RED . _ ( 'generic-ble.label.customType' ) ,
231+ notifiable : c . properties . indexOf ( 'notify' ) >= 0 ,
232+ readable : c . properties . indexOf ( 'read' ) >= 0 ,
233+ writable : c . properties . indexOf ( 'write' ) >= 0 ,
234+ writeWithoutResponse : c . properties . indexOf ( 'writeWithoutResponse' ) >= 0 ,
235+ object : c ,
236+ addDataListener : ( func ) => {
237+ if ( obj . dataListener ) {
238+ return false ;
239+ }
240+ obj . dataListener = func ;
241+ obj . object . removeAllListeners ( 'data' ) ;
242+ obj . object . on ( 'data' , func ) ;
243+ return true ;
244+ } ,
245+ } ;
246+ return obj ;
247+ }
248+
226249 class GenericBLENode {
227250 constructor ( n ) {
228251 RED . nodes . createNode ( this , n ) ;
@@ -241,6 +264,7 @@ export default function(RED) {
241264 preparePeripheral : ( ) => {
242265 let peripheral = noble . _peripherals [ this . uuid ] ;
243266 if ( ! peripheral ) {
267+ this . emit ( 'disconnected' ) ;
244268 return Promise . resolve ( ) ;
245269 }
246270 switch ( peripheral . state ) {
@@ -260,19 +284,7 @@ export default function(RED) {
260284 this . emit ( 'connected' ) ;
261285 this . characteristics = services . reduce ( ( prev , curr ) => {
262286 return prev . concat ( curr . characteristics ) ;
263- } , [ ] ) . map ( ( c ) => {
264- let characteristic = {
265- uuid : c . uuid ,
266- name : c . name || RED . _ ( 'generic-ble.label.unnamedChr' ) ,
267- type : c . type || RED . _ ( 'generic-ble.label.customType' ) ,
268- notifiable : c . properties . indexOf ( 'notify' ) >= 0 ,
269- readable : c . properties . indexOf ( 'read' ) >= 0 ,
270- writable : c . properties . indexOf ( 'write' ) >= 0 ,
271- writeWithoutResponse : c . properties . indexOf ( 'writeWithoutResponse' ) >= 0 ,
272- object : c
273- } ;
274- return characteristic ;
275- } ) ;
287+ } , [ ] ) . map ( ( c ) => toCharacteristic ( c ) ) ;
276288 } ) ;
277289 } ) ;
278290 peripheral . connect ( ) ; // peripheral.state => connecting
@@ -282,19 +294,7 @@ export default function(RED) {
282294 if ( peripheral . services ) {
283295 this . characteristics = peripheral . services . reduce ( ( prev , curr ) => {
284296 return prev . concat ( curr . characteristics ) ;
285- } , [ ] ) . map ( ( c ) => {
286- let characteristic = {
287- uuid : c . uuid ,
288- name : c . name || RED . _ ( 'generic-ble.label.unnamedChr' ) ,
289- type : c . type || RED . _ ( 'generic-ble.label.customType' ) ,
290- notifiable : c . properties . indexOf ( 'notify' ) >= 0 ,
291- readable : c . properties . indexOf ( 'read' ) >= 0 ,
292- writable : c . properties . indexOf ( 'write' ) >= 0 ,
293- writeWithoutResponse : c . properties . indexOf ( 'writeWithoutResponse' ) >= 0 ,
294- object : c
295- } ;
296- return characteristic ;
297- } ) ;
297+ } , [ ] ) . map ( ( c ) => toCharacteristic ( c ) ) ;
298298 }
299299 if ( ! peripheral . _disconnectedHandlerSet ) {
300300 peripheral . _disconnectedHandlerSet = true ;
@@ -319,6 +319,7 @@ export default function(RED) {
319319 } else if ( retry < 10 ) {
320320 setTimeout ( connectedHandler , 500 ) ;
321321 } else {
322+ this . emit ( 'timeout' ) ;
322323 return resolve ( peripheral . state ) ;
323324 }
324325 } ;
@@ -449,37 +450,67 @@ export default function(RED) {
449450 } ) ;
450451 } ) ;
451452 } ,
452- subscribe : ( uuids = '' , period = 3000 ) => {
453- // FIXME
454- uuids = uuids . split ( ',' ) . map ( ( uuid ) => uuid . trim ( ) ) . filter ( ( uuid ) => uuid ) ;
455- let notifiables = this . characteristics . filter ( c => {
456- if ( c . notifiable ) {
457- if ( uuids . length === 0 ) {
458- return true ;
453+ subscribe : ( uuids = '' , period = 0 ) => {
454+ return this . operations . preparePeripheral ( ) . then ( ( state ) => {
455+ if ( state !== 'connected' ) {
456+ this . log ( `[subscribe] Peripheral:${ this . uuid } is NOT ready. state=>${ state } ` ) ;
457+ return Promise . resolve ( ) ;
458+ }
459+ uuids = uuids . split ( ',' ) . map ( ( uuid ) => uuid . trim ( ) ) . filter ( ( uuid ) => uuid ) ;
460+ let notifiables = this . characteristics . filter ( c => {
461+ if ( c . notifiable ) {
462+ if ( uuids . length === 0 ) {
463+ return true ;
464+ }
465+ return uuids . indexOf ( c . uuid ) >= 0 ;
459466 }
460- return uuids . indexOf ( c . uuid ) >= 0 ;
467+ } ) ;
468+ if ( TRACE ) {
469+ this . log ( `characteristics => ${ JSON . stringify ( this . characteristics . map ( ( c ) => {
470+ let obj = Object . assign ( { } , c ) ;
471+ delete obj . obj ;
472+ return obj ;
473+ } ) ) } `) ;
474+ this . log ( `notifiables.length => ${ notifiables . length } ` ) ;
461475 }
476+ if ( notifiables . length === 0 ) {
477+ return false ;
478+ }
479+ return Promise . all ( notifiables . map ( ( r ) => {
480+ r . addDataListener ( ( data , isNotification ) => {
481+ if ( isNotification ) {
482+ let readObj = {
483+ notification : true
484+ } ;
485+ readObj [ r . uuid ] = data ;
486+ this . emit ( 'ble-notify' , this . uuid , readObj ) ;
487+ }
488+ } ) ;
489+ r . object . subscribe ( ( err ) => {
490+ if ( err ) {
491+ this . emit ( 'error' , err ) ;
492+ this . log ( `subscription error: ${ err . message } ` ) ;
493+ } else {
494+ this . emit ( 'subscribed' ) ;
495+ }
496+ } ) ;
497+ if ( period > 0 ) {
498+ setTimeout ( ( ) => {
499+ r . object . unsubscribe ( ( err ) => {
500+ if ( err ) {
501+ this . emit ( 'error' , err ) ;
502+ this . log ( `unsubscription error: ${ err . message } ` ) ;
503+ } else {
504+ this . emit ( 'connected' ) ;
505+ }
506+ } ) ;
507+ } , 5000 ) ;
508+ }
509+ } ) ) ;
462510 } ) ;
463- if ( TRACE ) {
464- this . log ( `characteristics => ${ JSON . stringify ( this . characteristics . map ( ( c ) => {
465- let obj = Object . assign ( { } , c ) ;
466- delete obj . obj ;
467- return obj ;
468- } ) ) } `) ;
469- this . log ( `notifiables.length => ${ notifiables . length } ` ) ;
470- }
471- if ( notifiables . length === 0 ) {
472- return false ;
473- }
474- // TODO perform subscribe here right now
475- notifiables . map ( ( r ) => {
476- // {uuid:'characteristic-uuid-to-subscribe', period:subscription period}
477- return { uuid : r . uuid , period : period } ;
478- } ) ;
479- return true ;
480511 }
481512 } ;
482- [ 'connected' , 'disconnected' , 'subscribed' , 'unsubscribed' , ' error', 'timeout' ] . forEach ( ev => {
513+ [ 'connected' , 'disconnected' , 'subscribed' , 'error' , 'timeout' ] . forEach ( ev => {
483514 this . on ( ev , ( ) => {
484515 try {
485516 Object . keys ( this . nodes ) . forEach ( id => {
@@ -505,7 +536,6 @@ export default function(RED) {
505536 this . genericBleNodeId = n . genericBle ;
506537 this . genericBleNode = RED . nodes . getNode ( this . genericBleNodeId ) ;
507538 if ( this . genericBleNode ) {
508- // FIXME
509539 if ( this . notification ) {
510540 this . genericBleNode . on ( 'ble-notify' , ( uuid , readObj , err ) => {
511541 if ( err ) {
@@ -531,9 +561,6 @@ export default function(RED) {
531561 this . on ( 'subscribed' , ( ) => {
532562 this . status ( { fill :'green' , shape :'dot' , text :`generic-ble.status.subscribed` } ) ;
533563 } ) ;
534- this . on ( 'unsubscribed' , ( ) => {
535- this . status ( { fill :'red' , shape :'ring' , text :`generic-ble.status.unsubscribed` } ) ;
536- } ) ;
537564 }
538565 this . on ( 'connected' , ( ) => {
539566 this . status ( { fill :'green' , shape :'dot' , text :`generic-ble.status.connected` } ) ;
@@ -556,22 +583,28 @@ export default function(RED) {
556583 }
557584 } catch ( _ ) {
558585 }
559- this . genericBleNode . operations . read ( msg . topic ) . then ( ( readObj ) => {
560- if ( ! readObj ) {
561- this . log ( `Nothing to read` ) ;
562- return ;
563- }
564- let payload = {
565- uuid : this . genericBleNode . uuid ,
566- characteristics : readObj
567- } ;
568- if ( this . useString ) {
569- payload = JSON . stringify ( payload ) ;
570- }
571- this . send ( {
572- payload : payload
586+ let p ;
587+ if ( obj . notify ) {
588+ p = this . genericBleNode . operations . subscribe ( msg . topic , obj . period ) ;
589+ } else {
590+ p = this . genericBleNode . operations . read ( msg . topic ) . then ( ( readObj ) => {
591+ if ( ! readObj ) {
592+ this . log ( `Nothing to read` ) ;
593+ return ;
594+ }
595+ let payload = {
596+ uuid : this . genericBleNode . uuid ,
597+ characteristics : readObj
598+ } ;
599+ if ( this . useString ) {
600+ payload = JSON . stringify ( payload ) ;
601+ }
602+ this . send ( {
603+ payload : payload
604+ } ) ;
573605 } ) ;
574- } ) . catch ( ( err ) => {
606+ }
607+ p . catch ( ( err ) => {
575608 this . error ( `<${ this . uuid } > read: (err:${ err } )` ) ;
576609 } ) ;
577610 } ) ;
0 commit comments