diff --git a/lib/controller.js b/lib/controller.js index 4e546f27d3..d1983178fb 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -274,7 +274,14 @@ class Controller { } // Call extensions - this.callExtensionMethod('onZigbeeEvent', [type, data, resolvedEntity]); + const result = await this.callExtensionMethod('onZigbeeEvent', [type, data, resolvedEntity]); + + // In case this message is not handled by the receive extension and last_seen is enabled, publish + // a message to update the last_seen. + if (name && !result[ExtensionReceive.prototype.constructor.name] && + settings.get().advanced.last_seen !== 'disable' && type !== 'deviceLeave') { + this.publishEntityState(name, {}); + } } onMQTTMessage(payload) { @@ -391,10 +398,11 @@ class Controller { } async callExtensionMethod(method, parameters, extensions=null) { + const result = {}; for (const extension of extensions || this.extensions) { if (extension[method]) { try { - await extension[method](...parameters); + result[extension.constructor.name] = await extension[method](...parameters); } catch (error) { /* istanbul ignore next */ logger.error(`Failed to call '${extension.constructor.name}' '${method}' (${error.stack})`); @@ -405,6 +413,7 @@ class Controller { } } } + return result; } } diff --git a/lib/extension/receive.js b/lib/extension/receive.js index baddf0a6af..abb46c0322 100755 --- a/lib/extension/receive.js +++ b/lib/extension/receive.js @@ -166,6 +166,7 @@ class Receive extends Extension { if (Object.keys(payload).length) { publish(payload); + return true; } } } diff --git a/test/receive.test.js b/test/receive.test.js index 7d5dc49b9c..878417aebd 100755 --- a/test/receive.test.js +++ b/test/receive.test.js @@ -327,6 +327,20 @@ describe('Receive', () => { expect(MQTT.publish).toHaveBeenCalledTimes(0); }); + it('Should publish last_seen for unhandled messages', async () => { + const device = zigbeeHerdsman.devices.WXKG02LM_rev1; + settings.set(['advanced', 'last_seen'], 'epoch'); + const data = {onOff: 1}; + const payload = {data, cluster: 'genRssiLocation', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; + await zigbeeHerdsman.events.message(payload); + await flushPromises(); + console.log(MQTT.publish.mock.calls); + expect(MQTT.publish).toHaveBeenCalledTimes(1); + expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/button_double_key'); + expect(typeof JSON.parse(MQTT.publish.mock.calls[0][1]).last_seen).toBe('number') + expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false}); + }); + it('Should publish last_seen epoch', async () => { const device = zigbeeHerdsman.devices.WXKG02LM_rev1; settings.set(['advanced', 'last_seen'], 'epoch');