mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-08-24 03:30:04 +00:00
configurable last_seen (#874)
* configurable last_seen * Refactor last_seen.
This commit is contained in:
@@ -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'
|
||||
```
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user