configurable last_seen (#874)

* configurable last_seen

* Refactor last_seen.
This commit is contained in:
Laurent
2019-01-18 20:31:55 +01:00
committed by Koen Kanters
parent 34a3e3c00b
commit 7cd30a3a05
6 changed files with 70 additions and 32 deletions
+3
View File
@@ -55,4 +55,7 @@ advanced:
soft_reset_timeout: 0
# Optional: network encryption key, changing requires repairing of all devices.
network_key: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
# Optional: Add a last_seen attribute to MQTT messages, contains date/time of last Zigbee message
# possible values are: disable (default), ISO_8601, epoch
last_seen: 'disable'
```
+8 -2
View File
@@ -103,8 +103,14 @@ class DeviceReceive {
}
// Add last seen timestamp
const now = new Date();
payload.last_seen = now.toISOString();
switch (settings.get().advanced.last_seen) {
case 'ISO_8601':
payload.last_seen = new Date().toISOString();
break;
case 'epoch':
payload.last_seen = Date.now();
break;
}
this.publishDeviceState(device, payload, cache);
};
+8
View File
@@ -31,6 +31,14 @@ const defaults = {
*/
cache_state: true,
/**
* Add a last_seen attribute to mqtt messages, contains date/time of zigbee message arrival
* "ISO_8601": ISO 8601 format
* "epoch": milliseconds elapsed since the UNIX epoch
* "disable": no last_seen attribute (default)
*/
last_seen: 'disable',
/**
* https://github.com/Koenkk/zigbee2mqtt/issues/685#issuecomment-449112250
*
+2 -2
View File
@@ -30,7 +30,7 @@ describe('Controller', () => {
controller.onZigbeeMessage(message);
chai.assert.isTrue(mqttPublish.calledOnce);
chai.assert.strictEqual(
utils.withoutLastSeen(mqttPublish.getCall(0).args[1]),
mqttPublish.getCall(0).args[1],
JSON.stringify({state: 'ON'})
);
});
@@ -52,7 +52,7 @@ describe('Controller', () => {
controller.onZigbeeMessage(message);
chai.assert.isTrue(mqttPublish.calledOnce);
chai.assert.strictEqual(
utils.withoutLastSeen(mqttPublish.getCall(0).args[1]),
mqttPublish.getCall(0).args[1],
`{"state":"ON","device":{"ieeeAddr":"0x12345678","friendlyName":"test",` +
`"modelId":"TRADFRI bulb E27 CWS opal 600lm"}}`
);
+49 -13
View File
@@ -37,7 +37,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(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {click: 'single'});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {click: 'single'});
});
it('Should handle a zigbee message which uses ep (left)', () => {
@@ -45,7 +45,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(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {click: 'left'});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {click: 'left'});
});
it('Should handle a zigbee message which uses ep (right)', () => {
@@ -53,7 +53,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(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {click: 'right'});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {click: 'right'});
});
it('Should handle a zigbee message with default precision', () => {
@@ -63,7 +63,7 @@ describe('DeviceReceive', () => {
);
deviceReceive.onZigbeeMessage(message, device, WSDCGQ11LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {temperature: -0.85});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {temperature: -0.85});
});
it('Should handle a zigbee message with 1 precision', () => {
@@ -76,7 +76,7 @@ describe('DeviceReceive', () => {
);
deviceReceive.onZigbeeMessage(message, device, WSDCGQ11LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {temperature: -0.8});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {temperature: -0.8});
});
it('Should handle a zigbee message with 0 precision', () => {
@@ -89,7 +89,7 @@ describe('DeviceReceive', () => {
);
deviceReceive.onZigbeeMessage(message, device, WSDCGQ11LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {temperature: -1});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {temperature: -1});
});
it('Should handle a zigbee message with 1 precision when set via device_options', () => {
@@ -99,6 +99,9 @@ describe('DeviceReceive', () => {
device_options: {
temperature_precision: 1,
},
advanced: {
last_seen: 'disable',
},
};
});
sandbox.stub(settings, 'getDevice').callsFake(() => {
@@ -109,7 +112,7 @@ describe('DeviceReceive', () => {
);
deviceReceive.onZigbeeMessage(message, device, WSDCGQ11LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {temperature: -0.8});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {temperature: -0.8});
});
it('Should handle a zigbee message with 2 precision when overrides device_options', () => {
@@ -119,6 +122,9 @@ describe('DeviceReceive', () => {
device_options: {
temperature_precision: 1,
},
advanced: {
last_seen: 'disable',
},
};
});
sandbox.stub(settings, 'getDevice').callsFake(() => {
@@ -131,7 +137,7 @@ describe('DeviceReceive', () => {
);
deviceReceive.onZigbeeMessage(message, device, WSDCGQ11LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), {temperature: -0.85});
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], {temperature: -0.85});
});
it('Should handle a zigbee message with voltage 3010', () => {
@@ -140,7 +146,7 @@ describe('DeviceReceive', () => {
deviceReceive.onZigbeeMessage(message, device, WXKG02LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
const expected = {battery: 100, voltage: 3010};
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), expected);
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], expected);
});
it('Should handle a zigbee message with voltage 2850', () => {
@@ -149,7 +155,7 @@ describe('DeviceReceive', () => {
deviceReceive.onZigbeeMessage(message, device, WXKG02LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
const expected = {battery: 35, voltage: 2850};
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), expected);
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], expected);
});
it('Should handle a zigbee message with voltage 2650', () => {
@@ -158,7 +164,7 @@ describe('DeviceReceive', () => {
deviceReceive.onZigbeeMessage(message, device, WXKG02LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
const expected = {battery: 14, voltage: 2650};
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), expected);
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], expected);
});
it('Should handle a zigbee message with voltage 2000', () => {
@@ -167,7 +173,7 @@ describe('DeviceReceive', () => {
deviceReceive.onZigbeeMessage(message, device, WXKG02LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
const expected = {battery: 0, voltage: 2000};
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), expected);
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], expected);
});
it('Should publish 1 message when converted twice', () => {
@@ -179,7 +185,7 @@ describe('DeviceReceive', () => {
deviceReceive.onZigbeeMessage(message, device, RTCGQ11LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
const expected = {'battery': 100, 'illuminance': 381, 'voltage': 3045};
chai.assert.deepEqual(utils.withoutLastSeen(publishDeviceState.getCall(0).args[1]), expected);
chai.assert.deepEqual(publishDeviceState.getCall(0).args[1], expected);
});
it('Should publish no message when converted without result', () => {
@@ -189,5 +195,35 @@ describe('DeviceReceive', () => {
deviceReceive.onZigbeeMessage(message, device, RTCGQ11LM);
chai.assert.isTrue(publishDeviceState.notCalled);
});
it('Should publish last_seen epoch', () => {
const device = {ieeeAddr: '0x12345678'};
const message = utils.zigbeeMessage(device, 'genOnOff', 'attReport', {onOff: 1}, 1);
sandbox.stub(settings, 'get').callsFake(() => {
return {
advanced: {
last_seen: 'epoch',
},
};
});
deviceReceive.onZigbeeMessage(message, device, WXKG02LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
chai.assert.equal(typeof publishDeviceState.getCall(0).args[1].last_seen, 'number');
});
it('Should publish last_seen ISO_8601', () => {
const device = {ieeeAddr: '0x12345678'};
const message = utils.zigbeeMessage(device, 'genOnOff', 'attReport', {onOff: 1}, 1);
sandbox.stub(settings, 'get').callsFake(() => {
return {
advanced: {
last_seen: 'ISO_8601',
},
};
});
deviceReceive.onZigbeeMessage(message, device, WXKG02LM);
chai.assert.isTrue(publishDeviceState.calledOnce);
chai.assert.equal(typeof publishDeviceState.getCall(0).args[1].last_seen, 'string');
});
});
});
-15
View File
@@ -10,19 +10,4 @@ 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;
},
};