From 5d3461c4c620a3935f3f301e15f5535b7fc8fc31 Mon Sep 17 00:00:00 2001 From: Gergely Markics <5822419+ugrug@users.noreply.github.com> Date: Wed, 26 Dec 2018 17:33:39 +0100 Subject: [PATCH] Add the timestamp of last received zigbee message visible in HASS (#739) * Add timestamp on receiving message from Zigbee Add last_message to the payload * Discovery on HASS restart and last_message attribute added - On restarting Home Assistant, resending device discovery information - Add timestamp on receiving message from Zigbee * Add option: add_timestamp in settings * Add option: add_timestamp in settings * Add option: add_timestamp in settings * typo * Update homeassistant.js * Update homeassistant.js * Update homeassistant.js * Update deviceReceive.js * Update deviceReceive.js * Update homeassistant.js * Update settings.js * Update deviceReceive.js * Update deviceReceive.js * Update deviceReceive.js * Update deviceReceive.js * Fix tests * Fix lint * Fix lint --- docs/integration/home_assistant.md | 40 ++++++++++++++++++++++++++++++ lib/extension/deviceReceive.js | 4 +++ lib/extension/homeassistant.js | 23 +++++++++-------- test/controller.test.js | 7 ++++-- test/deviceReceive.test.js | 6 ++--- test/utils.js | 15 +++++++++++ 6 files changed, 80 insertions(+), 15 deletions(-) diff --git a/docs/integration/home_assistant.md b/docs/integration/home_assistant.md index 48502b7f0..b86f5d86d 100644 --- a/docs/integration/home_assistant.md +++ b/docs/integration/home_assistant.md @@ -239,6 +239,7 @@ sensor: - "voltage" - "action" - "duration" + - "last_seen" force_update: true ``` {% endraw %} @@ -258,6 +259,7 @@ sensor: - "voltage" - "action" - "duration" + - "last_seen" force_update: true ``` {% endraw %} @@ -277,6 +279,7 @@ sensor: - "voltage" - "action" - "duration" + - "last_seen" force_update: true ``` {% endraw %} @@ -296,6 +299,7 @@ sensor: - "voltage" - "action" - "duration" + - "last_seen" force_update: true ``` {% endraw %} @@ -315,6 +319,7 @@ sensor: - "voltage" - "action" - "duration" + - "last_seen" force_update: true ``` {% endraw %} @@ -359,6 +364,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} @@ -432,6 +438,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} @@ -449,6 +456,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" sensor: - platform: "mqtt" @@ -461,6 +469,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" ``` {% endraw %} @@ -478,6 +487,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" sensor: - platform: "mqtt" @@ -490,6 +500,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" sensor: - platform: "mqtt" @@ -502,6 +513,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" ``` {% endraw %} @@ -528,6 +540,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -554,6 +567,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" sensor: - platform: "mqtt" @@ -566,6 +580,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -592,6 +607,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -618,6 +634,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -644,6 +661,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -671,6 +689,7 @@ sensor: - "angle_y" - "angle_x" - "unknown_data" + - "last_seen" force_update: true ``` {% endraw %} @@ -701,6 +720,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} @@ -730,6 +750,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} @@ -756,6 +777,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -782,6 +804,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -798,6 +821,7 @@ sensor: - "linkquality" - "forgotten" - "keyerror" + - "last_seen" ``` {% endraw %} @@ -825,6 +849,7 @@ sensor: - "angle_y" - "angle_x" - "unknown_data" + - "last_seen" force_update: true ``` {% endraw %} @@ -963,6 +988,7 @@ sensor: value_template: "{{ value_json.brightness }}" json_attributes: - "linkquality" + - "last_seen" ``` {% endraw %} @@ -1313,6 +1339,7 @@ sensor: - "angle_y" - "angle_x" - "unknown_data" + - "last_seen" force_update: true ``` {% endraw %} @@ -1340,6 +1367,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" sensor: - platform: "mqtt" @@ -1352,6 +1380,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" sensor: - platform: "mqtt" @@ -1364,6 +1393,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -1406,6 +1436,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} @@ -1430,6 +1461,7 @@ sensor: - "description" - "type" - "rssi" + - "last_seen" ``` {% endraw %} @@ -1835,6 +1867,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" ``` {% endraw %} @@ -2119,6 +2152,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} @@ -2367,6 +2401,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} @@ -2464,6 +2499,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -2490,6 +2526,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -2584,6 +2621,7 @@ sensor: - "voltage" - "action" - "sensitivity" + - "last_seen" ``` {% endraw %} @@ -2624,6 +2662,7 @@ sensor: - "linkquality" - "battery" - "voltage" + - "last_seen" ``` {% endraw %} @@ -2723,6 +2762,7 @@ sensor: - "consumption" - "current" - "power_factor" + - "last_seen" ``` {% endraw %} diff --git a/lib/extension/deviceReceive.js b/lib/extension/deviceReceive.js index 168347b71..3b87ed10c 100644 --- a/lib/extension/deviceReceive.js +++ b/lib/extension/deviceReceive.js @@ -99,6 +99,10 @@ class DeviceReceive { payload.linkquality = message.linkquality; } + // Add last seen timestamp + const now = new Date(); + payload.last_seen = now.toISOString(); + this.publishDeviceState(device, payload, cache); }; diff --git a/lib/extension/homeassistant.js b/lib/extension/homeassistant.js index d29361763..e42db24d4 100644 --- a/lib/extension/homeassistant.js +++ b/lib/extension/homeassistant.js @@ -84,7 +84,7 @@ const configurations = { unit_of_measurement: 'lx', device_class: 'illuminance', value_template: '{{ value_json.illuminance }}', - json_attributes: ['linkquality', 'battery', 'voltage'], + json_attributes: ['linkquality', 'battery', 'voltage', 'last_seen'], }, }, 'sensor_humidity': { @@ -94,7 +94,7 @@ const configurations = { unit_of_measurement: '%', device_class: 'humidity', value_template: '{{ value_json.humidity }}', - json_attributes: ['linkquality', 'battery', 'voltage'], + json_attributes: ['linkquality', 'battery', 'voltage', 'last_seen'], }, }, 'sensor_temperature': { @@ -104,7 +104,7 @@ const configurations = { unit_of_measurement: '°C', device_class: 'temperature', value_template: '{{ value_json.temperature }}', - json_attributes: ['linkquality', 'battery', 'voltage'], + json_attributes: ['linkquality', 'battery', 'voltage', 'last_seen'], }, }, 'sensor_pressure': { @@ -114,7 +114,7 @@ const configurations = { unit_of_measurement: 'hPa', device_class: 'pressure', value_template: '{{ value_json.pressure }}', - json_attributes: ['linkquality', 'battery', 'voltage'], + json_attributes: ['linkquality', 'battery', 'voltage', 'last_seen'], }, }, 'sensor_click': { @@ -123,7 +123,7 @@ const configurations = { discovery_payload: { icon: 'mdi:toggle-switch', value_template: '{{ value_json.click }}', - json_attributes: ['linkquality', 'battery', 'voltage', 'action', 'duration'], + json_attributes: ['linkquality', 'battery', 'voltage', 'action', 'duration', 'last_seen'], force_update: true, }, }, @@ -134,7 +134,9 @@ const configurations = { unit_of_measurement: 'Watt', icon: 'mdi:flash', value_template: '{{ value_json.power }}', - json_attributes: ['linkquality', 'voltage', 'temperature', 'consumption', 'current', 'power_factor'], + json_attributes: [ + 'linkquality', 'voltage', 'temperature', 'consumption', 'current', 'power_factor', 'last_seen', + ], }, }, 'sensor_action': { @@ -146,6 +148,7 @@ const configurations = { json_attributes: [ 'linkquality', 'battery', 'voltage', 'angle', 'side', 'from_side', 'to_side', 'brightness', 'angle_x_absolute', 'angle_y_absolute', 'angle_z', 'angle_y', 'angle_x', 'unknown_data', + 'last_seen', ], force_update: true, }, @@ -157,7 +160,7 @@ const configurations = { unit_of_measurement: 'brightness', icon: 'mdi:brightness-5', value_template: '{{ value_json.brightness }}', - json_attributes: ['linkquality'], + json_attributes: ['linkquality', 'last_seen'], }, }, 'sensor_lock': { @@ -166,7 +169,7 @@ const configurations = { discovery_payload: { icon: 'mdi:lock', value_template: '{{ value_json.inserted }}', - json_attributes: ['linkquality', 'forgotten', 'keyerror'], + json_attributes: ['linkquality', 'forgotten', 'keyerror', 'last_seen'], }, }, 'sensor_battery': { @@ -175,7 +178,7 @@ const configurations = { discovery_payload: { device_class: 'battery', value_template: '{{ value_json.battery }}', - json_attributes: ['linkquality', 'voltage', 'action', 'sensitivity'], + json_attributes: ['linkquality', 'voltage', 'action', 'sensitivity', 'last_seen'], }, }, 'sensor_linkquality': { @@ -183,7 +186,7 @@ const configurations = { object_id: 'linkquality', discovery_payload: { value_template: '{{ value_json.linkquality }}', - json_attributes: ['description', 'type', 'rssi'], + json_attributes: ['description', 'type', 'rssi', 'last_seen'], }, }, diff --git a/test/controller.test.js b/test/controller.test.js index 0b03b4450..3ec3785b6 100644 --- a/test/controller.test.js +++ b/test/controller.test.js @@ -29,7 +29,10 @@ describe('Controller', () => { const message = utils.zigbeeMessage(device, 'genOnOff', 'devChange', {onOff: 1}, 1); controller.onZigbeeMessage(message); chai.assert.isTrue(mqttPublish.calledOnce); - chai.assert.strictEqual(mqttPublish.getCall(0).args[1], JSON.stringify({state: 'ON'})); + chai.assert.strictEqual( + utils.withoutLastSeen(mqttPublish.getCall(0).args[1]), + JSON.stringify({state: 'ON'}) + ); }); it('Should handle a zigbee message when include_device_information is set', () => { @@ -49,7 +52,7 @@ describe('Controller', () => { controller.onZigbeeMessage(message); chai.assert.isTrue(mqttPublish.calledOnce); chai.assert.strictEqual( - mqttPublish.getCall(0).args[1], + utils.withoutLastSeen(mqttPublish.getCall(0).args[1]), `{"state":"ON","device":{"ieeeAddr":"0x12345678","friendlyName":"test",` + `"modelId":"TRADFRI bulb E27 CWS opal 600lm"}}` ); diff --git a/test/deviceReceive.test.js b/test/deviceReceive.test.js index d587ff3c6..50d11dadd 100644 --- a/test/deviceReceive.test.js +++ b/test/deviceReceive.test.js @@ -36,7 +36,7 @@ describe('DeviceReceive', () => { const message = utils.zigbeeMessage(device, 'genOnOff', 'attReport', {onOff: 1}, 1); deviceReceive.onZigbeeMessage(message, device, WXKG11LM); chai.assert.isTrue(publishDeviceState.calledOnce); - chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {click: 'single'}); + chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {click: 'single'}); }); it('Should handle a zigbee message which uses ep (left)', () => { @@ -44,7 +44,7 @@ describe('DeviceReceive', () => { const message = utils.zigbeeMessage(device, 'genOnOff', 'attReport', {onOff: 1}, 1); deviceReceive.onZigbeeMessage(message, device, WXKG02LM); chai.assert.isTrue(publishDeviceState.calledOnce); - chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {click: 'left'}); + chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {click: 'left'}); }); it('Should handle a zigbee message which uses ep (right)', () => { @@ -52,7 +52,7 @@ describe('DeviceReceive', () => { const message = utils.zigbeeMessage(device, 'genOnOff', 'attReport', {onOff: 1}, 2); deviceReceive.onZigbeeMessage(message, device, WXKG02LM); chai.assert.isTrue(publishDeviceState.calledOnce); - chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {click: 'right'}); + chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {click: 'right'}); }); it('Should handle a zigbee message with default precision', () => { diff --git a/test/utils.js b/test/utils.js index 086ce58b4..bab522d0e 100644 --- a/test/utils.js +++ b/test/utils.js @@ -10,4 +10,19 @@ module.exports = { zigbeeMessage: (device, cid, type, data, epId) => { return {data: {cid: cid, data: data}, type: type, endpoints: [{device: device, epId: epId}]}; }, + withoutLastSeen: (obj) => { + const isString = typeof obj === 'string'; + + if (isString) { + obj = JSON.parse(obj); + } + + delete obj.last_seen; + + if (isString) { + obj = JSON.stringify(obj); + } + + return obj; + }, };