11import type { Events as ZHEvents } from 'zigbee-herdsman' ;
2+ import type { StartResult } from 'zigbee-herdsman/dist/adapter/tstype' ;
23
34import { randomInt } from 'node:crypto' ;
45
@@ -14,20 +15,20 @@ import logger from './util/logger';
1415import * as settings from './util/settings' ;
1516import utils from './util/utils' ;
1617
17- const entityIDRegex = new RegExp ( ` ^(.+?)(?:/([^/]+))?$` ) ;
18+ const entityIDRegex = / ^ ( .+ ?) (?: \ /( [ ^ / ] + ) ) ? $ / ;
1819
1920export default class Zigbee {
2021 // @ts -expect-error initialized in start
2122 private herdsman : Controller ;
2223 private eventBus : EventBus ;
23- private groupLookup : { [ s : number ] : Group } = { } ;
24- private deviceLookup : { [ s : string ] : Device } = { } ;
24+ private groupLookup : Map < number /* group ID */ , Group > = new Map ( ) ;
25+ private deviceLookup : Map < string /* IEEE address */ , Device > = new Map ( ) ;
2526
2627 constructor ( eventBus : EventBus ) {
2728 this . eventBus = eventBus ;
2829 }
2930
30- async start ( ) : Promise < 'reset' | 'resumed' | 'restored' > {
31+ async start ( ) : Promise < StartResult > {
3132 const infoHerdsman = await utils . getDependencyVersion ( 'zigbee-herdsman' ) ;
3233 logger . info ( `Starting zigbee-herdsman (${ infoHerdsman . version } )` ) ;
3334 const panId = settings . get ( ) . advanced . pan_id ;
@@ -63,12 +64,12 @@ export default class Zigbee {
6364 `Using zigbee-herdsman with settings: '${ stringify ( JSON . stringify ( herdsmanSettings ) . replaceAll ( JSON . stringify ( herdsmanSettings . network . networkKey ) , '"HIDDEN"' ) ) } '` ,
6465 ) ;
6566
66- let startResult ;
67+ let startResult : StartResult ;
6768 try {
6869 this . herdsman = new Controller ( herdsmanSettings ) ;
6970 startResult = await this . herdsman . start ( ) ;
7071 } catch ( error ) {
71- logger . error ( ` Error while starting zigbee-herdsman` ) ;
72+ logger . error ( ' Error while starting zigbee-herdsman' ) ;
7273 throw error ;
7374 }
7475
@@ -109,18 +110,17 @@ export default class Zigbee {
109110 this . herdsman . on ( 'deviceLeave' , ( data : ZHEvents . DeviceLeavePayload ) => {
110111 const name = settings . getDevice ( data . ieeeAddr ) ?. friendly_name || data . ieeeAddr ;
111112 logger . warning ( `Device '${ name } ' left the network` ) ;
112- this . eventBus . emitDeviceLeave ( { ieeeAddr : data . ieeeAddr , name} ) ;
113+ this . eventBus . emitDeviceLeave ( { ieeeAddr : data . ieeeAddr , name, device : this . deviceLookup . get ( data . ieeeAddr ) } ) ;
113114 } ) ;
114115 this . herdsman . on ( 'message' , async ( data : ZHEvents . MessagePayload ) => {
115116 const device = this . resolveDevice ( data . device . ieeeAddr ) ! ;
116117 await device . resolveDefinition ( ) ;
117- logger . debug (
118- ( ) =>
119- `Received Zigbee message from '${ device . name } ', type '${ data . type } ', ` +
120- `cluster '${ data . cluster } ', data '${ stringify ( data . data ) } ' from endpoint ${ data . endpoint . ID } ` +
121- ( data [ 'groupID' ] !== undefined ? ` with groupID ${ data . groupID } ` : `` ) +
122- ( device . zh . type === 'Coordinator' ? `, ignoring since it is from coordinator` : `` ) ,
123- ) ;
118+ logger . debug ( ( ) => {
119+ const groupId = data . groupID !== undefined ? ` with groupID ${ data . groupID } ` : '' ;
120+ const fromCoord = device . zh . type === 'Coordinator' ? ', ignoring since it is from coordinator' : '' ;
121+
122+ return `Received Zigbee message from '${ device . name } ', type '${ data . type } ', cluster '${ data . cluster } ', data '${ stringify ( data . data ) } ' from endpoint ${ data . endpoint . ID } ${ groupId } ${ fromCoord } ` ;
123+ } ) ;
124124 if ( device . zh . type === 'Coordinator' ) return ;
125125 this . eventBus . emitDeviceMessage ( { ...data , device} ) ;
126126 } ) ;
@@ -165,9 +165,7 @@ export default class Zigbee {
165165 logger . info ( `Device '${ name } ' is supported, identified as: ${ vendor } ${ description } (${ model } )` ) ;
166166 } else {
167167 logger . warning (
168- `Device '${ name } ' with Zigbee model '${ data . device . zh . modelID } ' and manufacturer name ` +
169- `'${ data . device . zh . manufacturerName } ' is NOT supported, ` +
170- `please follow https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html` ,
168+ `Device '${ name } ' with Zigbee model '${ data . device . zh . modelID } ' and manufacturer name '${ data . device . zh . manufacturerName } ' is NOT supported, please follow https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html` ,
171169 ) ;
172170 }
173171 } else if ( data . status === 'failed' ) {
@@ -241,55 +239,57 @@ export default class Zigbee {
241239 await this . herdsman . permitJoin ( time , device ?. zh ) ;
242240 }
243241
244- async resolveDevicesDefinitions ( ignoreCache : boolean = false ) : Promise < void > {
242+ async resolveDevicesDefinitions ( ignoreCache = false ) : Promise < void > {
245243 for ( const device of this . devicesIterator ( utils . deviceNotCoordinator ) ) {
246244 await device . resolveDefinition ( ignoreCache ) ;
247245 }
248246 }
249247
250248 @bind private resolveDevice ( ieeeAddr : string ) : Device | undefined {
251- if ( ! this . deviceLookup [ ieeeAddr ] ) {
249+ if ( ! this . deviceLookup . has ( ieeeAddr ) ) {
252250 const device = this . herdsman . getDeviceByIeeeAddr ( ieeeAddr ) ;
253251 if ( device ) {
254- this . deviceLookup [ ieeeAddr ] = new Device ( device ) ;
252+ this . deviceLookup . set ( ieeeAddr , new Device ( device ) ) ;
255253 }
256254 }
257255
258- const device = this . deviceLookup [ ieeeAddr ] ;
256+ const device = this . deviceLookup . get ( ieeeAddr ) ;
259257 if ( device && ! device . zh . isDeleted ) {
260258 device . ensureInSettings ( ) ;
261259 return device ;
262260 }
263261 }
264262
265- private resolveGroup ( groupID : number ) : Group {
263+ private resolveGroup ( groupID : number ) : Group | undefined {
266264 const group = this . herdsman . getGroupByID ( Number ( groupID ) ) ;
267- if ( group && ! this . groupLookup [ groupID ] ) {
268- this . groupLookup [ groupID ] = new Group ( group , this . resolveDevice ) ;
265+ if ( group && ! this . groupLookup . has ( groupID ) ) {
266+ this . groupLookup . set ( groupID , new Group ( group , this . resolveDevice ) ) ;
269267 }
270268
271- return this . groupLookup [ groupID ] ;
269+ return this . groupLookup . get ( groupID ) ;
272270 }
273271
274272 resolveEntity ( key : string | number | zh . Device ) : Device | Group | undefined {
275273 if ( typeof key === 'object' ) {
276274 return this . resolveDevice ( key . ieeeAddr ) ;
277- } else if ( typeof key === 'string' && key . toLowerCase ( ) === 'coordinator' ) {
275+ }
276+
277+ if ( typeof key === 'string' && key . toLowerCase ( ) === 'coordinator' ) {
278278 return this . resolveDevice ( this . herdsman . getDevicesByType ( 'Coordinator' ) [ 0 ] . ieeeAddr ) ;
279- } else {
280- const settingsDevice = settings . getDevice ( key . toString ( ) ) ;
279+ }
281280
282- if ( settingsDevice ) {
283- return this . resolveDevice ( settingsDevice . ID ) ;
284- }
281+ const settingsDevice = settings . getDevice ( key . toString ( ) ) ;
285282
286- const groupSettings = settings . getGroup ( key ) ;
283+ if ( settingsDevice ) {
284+ return this . resolveDevice ( settingsDevice . ID ) ;
285+ }
287286
288- if ( groupSettings ) {
289- const group = this . resolveGroup ( groupSettings . ID ) ;
290- // If group does not exist, create it (since it's already in configuration.yaml)
291- return group ? group : this . createGroup ( groupSettings . ID ) ;
292- }
287+ const groupSettings = settings . getGroup ( key ) ;
288+
289+ if ( groupSettings ) {
290+ const group = this . resolveGroup ( groupSettings . ID ) ;
291+ // If group does not exist, create it (since it's already in configuration.yaml)
292+ return group ? group : this . createGroup ( groupSettings . ID ) ;
293293 }
294294 }
295295
@@ -339,13 +339,13 @@ export default class Zigbee {
339339 }
340340
341341 for ( const group of this . herdsman . getGroupsIterator ( groupPredicate ) ) {
342- yield this . resolveGroup ( group . groupID ) ;
342+ yield this . resolveGroup ( group . groupID ) ! ;
343343 }
344344 }
345345
346346 * groupsIterator ( predicate ?: ( value : zh . Group ) => boolean ) : Generator < Group > {
347347 for ( const group of this . herdsman . getGroupsIterator ( predicate ) ) {
348- yield this . resolveGroup ( group . groupID ) ;
348+ yield this . resolveGroup ( group . groupID ) ! ;
349349 }
350350 }
351351
@@ -363,21 +363,22 @@ export default class Zigbee {
363363 if ( passlist . includes ( ieeeAddr ) ) {
364364 logger . info ( `Accepting joining device which is on passlist '${ ieeeAddr } '` ) ;
365365 return true ;
366- } else {
367- logger . info ( `Rejecting joining not in passlist device '${ ieeeAddr } '` ) ;
368- return false ;
369366 }
370- } else if ( blocklist . length > 0 ) {
367+
368+ logger . info ( `Rejecting joining not in passlist device '${ ieeeAddr } '` ) ;
369+ return false ;
370+ }
371+
372+ if ( blocklist . length > 0 ) {
371373 if ( blocklist . includes ( ieeeAddr ) ) {
372374 logger . info ( `Rejecting joining device which is on blocklist '${ ieeeAddr } '` ) ;
373375 return false ;
374- } else {
375- logger . info ( `Accepting joining not in blocklist device '${ ieeeAddr } '` ) ;
376- return true ;
377376 }
378- } else {
379- return true ;
377+
378+ logger . info ( `Accepting joining not in blocklist device ' ${ ieeeAddr } '` ) ;
380379 }
380+
381+ return true ;
381382 }
382383
383384 async touchlinkFactoryResetFirst ( ) : Promise < boolean > {
@@ -402,15 +403,15 @@ export default class Zigbee {
402403
403404 createGroup ( ID : number ) : Group {
404405 this . herdsman . createGroup ( ID ) ;
405- return this . resolveGroup ( ID ) ;
406+ return this . resolveGroup ( ID ) ! ;
406407 }
407408
408409 deviceByNetworkAddress ( networkAddress : number ) : Device | undefined {
409410 const device = this . herdsman . getDeviceByNetworkAddress ( networkAddress ) ;
410411 return device && this . resolveDevice ( device . ieeeAddr ) ;
411412 }
412413
413- groupByID ( ID : number ) : Group {
414+ groupByID ( ID : number ) : Group | undefined {
414415 return this . resolveGroup ( ID ) ;
415416 }
416417}
0 commit comments