diff --git a/lib/eventBus.ts b/lib/eventBus.ts index d0b5adfda0..6f78d0d1a8 100644 --- a/lib/eventBus.ts +++ b/lib/eventBus.ts @@ -27,6 +27,7 @@ interface EventBusMap { scenesChanged: [data: eventdata.ScenesChanged]; reconfigure: [data: eventdata.Reconfigure]; stateChange: [data: eventdata.StateChange]; + sourceRoute: [data: eventdata.SourceRouteChanged]; } type EventBusListener = K extends keyof EventBusMap ? EventBusMap[K] extends unknown[] @@ -194,6 +195,13 @@ export default class EventBus { this.emitExposesChanged({device}); } + public emitSourceRoute(data: eventdata.SourceRouteChanged): void { + this.emitter.emit('sourceRoute', data); + } + public onSourceRoute(key: ListenerKey, callback: (data: eventdata.SourceRouteChanged) => void): void { + this.on('sourceRoute', callback, key); + } + private on(event: K, callback: EventBusListener, key: ListenerKey): void { if (!this.callbacksByExtension[key.constructor.name]) { this.callbacksByExtension[key.constructor.name] = []; diff --git a/lib/extension/receive.ts b/lib/extension/receive.ts index 5cb3584e86..c14e35c4a4 100755 --- a/lib/extension/receive.ts +++ b/lib/extension/receive.ts @@ -22,6 +22,7 @@ export default class Receive extends Extension { async start(): Promise { this.eventBus.onPublishEntityState(this, this.onPublishEntityState); this.eventBus.onDeviceMessage(this, this.onDeviceMessage); + this.eventBus.onSourceRoute(this, this.onSourceRouteChanged); } @bind async onPublishEntityState(data: eventdata.PublishEntityState): Promise { @@ -183,4 +184,14 @@ export default class Receive extends Extension { await utils.publishLastSeen({device: data.device, reason: 'messageEmitted'}, settings.get(), true, this.publishEntityState); } } + + @bind async onSourceRouteChanged(data: eventdata.SourceRouteChanged): Promise { + const device = this.zigbee.resolveEntity(data.device.ieeeAddr); + if (!device) { + logger.warning(`Source route indication received for unknown device '${data.device.ieeeAddr}'`); + return; + } + logger.debug(`Source route indication received for '${device.name}'`); + this.state.set(device, {source_route: data.relaylist}); + } } diff --git a/lib/types/types.d.ts b/lib/types/types.d.ts index 9db2ea0bda..06d094b6c0 100644 --- a/lib/types/types.d.ts +++ b/lib/types/types.d.ts @@ -91,6 +91,12 @@ declare global { meta: {zclTransactionSequenceNumber?: number; manufacturerCode?: number; frameControl?: ZHFrameControl}; }; type ScenesChanged = {entity: Device | Group}; + type SourceRouteChanged = { + device: zh.Device; + dstaddr: number; + relaycount: number; + relaylist: number[]; + }; } // Settings diff --git a/lib/zigbee.ts b/lib/zigbee.ts index 1579d8ac9b..9397c85247 100644 --- a/lib/zigbee.ts +++ b/lib/zigbee.ts @@ -123,6 +123,15 @@ export default class Zigbee { if (device.zh.type === 'Coordinator') return; this.eventBus.emitDeviceMessage({...data, device}); }); + this.herdsman.on('sourceRoute', (data: ZHEvents.SrcRouteIndPayload) => { + logger.debug(`Source route indication received: ${stringify(data)}`); + const device = this.herdsman.getDeviceByNetworkAddress(data.dstaddr); + if (!device) { + logger.warning(`Source route indication received for unknown device '${data.dstaddr}'`); + return; + } + this.eventBus.emitSourceRoute({device: device, ...data}); + }); logger.info(`zigbee-herdsman started (${startResult})`); logger.info(`Coordinator firmware version: '${stringify(await this.getCoordinatorVersion())}'`);