Clear outdated Home Assistant configs

This commit is contained in:
Koen Kanters
2020-08-17 17:24:57 +02:00
parent ffe810a471
commit 5f75c9c9f8
3 changed files with 72 additions and 5 deletions
+33 -4
View File
@@ -6,6 +6,7 @@ const zigbee2mqttVersion = require('../../package.json').version;
const Extension = require('./extension');
const objectAssignDeep = require(`object-assign-deep`);
const stringify = require('json-stable-stringify');
const discoveryRegex = new RegExp(`homeassistant/(.*)/(.*)/(.*)/config`);
const cfg = {
// Binary sensor
@@ -2049,6 +2050,7 @@ class HomeAssistant extends Extension {
async onMQTTConnected() {
this.mqtt.subscribe(this.statusTopic);
this.mqtt.subscribe(defaultStatusTopic);
this.mqtt.subscribe(`${this.discoveryTopic}/#`);
// MQTT discovery of all paired devices on startup.
for (const device of this.zigbee.getClients()) {
@@ -2252,11 +2254,38 @@ class HomeAssistant extends Extension {
}
onMQTTMessage(topic, message) {
if (topic !== this.statusTopic && topic !== defaultStatusTopic) {
return false;
}
const discoveryMatch = topic.match(discoveryRegex);
if (discoveryMatch) {
// Clear outdated discovery configs.
try {
message = JSON.parse(message);
if (!message || !message.availability_topic ||
!message.availability_topic.startsWith(settings.get().mqtt.base_topic + '/')) {
// Base topic is different, probably different Zigbee2MQTT instance.
return;
}
} catch (e) {
return;
}
if (message.toLowerCase() === 'online') {
const ieeeAddr = discoveryMatch[2];
const resolvedEntity = this.zigbee.resolveEntity(ieeeAddr);
let clear = !resolvedEntity || !resolvedEntity.definition;
if (!clear) {
const deviceSettings = {...settings.get().device_options, ...resolvedEntity.settings};
const configs = this.getConfigs(resolvedEntity.definition, deviceSettings);
const type = discoveryMatch[1];
const objectID = discoveryMatch[3];
clear = !configs.find((c) => c.type === type && c.object_id === objectID);
}
if (clear) {
logger.debug(`Clearing Home Assistant config '${topic}'`);
topic = topic.substring(this.discoveryTopic.length + 1);
this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic);
}
} else if ((topic === this.statusTopic || topic === defaultStatusTopic) && message.toLowerCase() === 'online') {
const timer = setTimeout(async () => {
// Publish all device states.
for (const device of this.zigbee.getClients()) {
+38
View File
@@ -1033,4 +1033,42 @@ describe('HomeAssistant extension', () => {
};
expect(ha._getMapping()['external_converters_device']).toStrictEqual([homeassistantSwitch]);
});
it('onlythis Should clear outdated configs', async () => {
controller = new Controller(false);
await controller.start();
await flushPromises();
// Non-existing device -> clear
MQTT.publish.mockClear();
await MQTT.events.message('homeassistant/sensor/0x123/temperature/config', stringify({availability_topic: 'zigbee2mqtt/0x123/availability'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/sensor/0x123/temperature/config', null, {qos: 0, retain: true}, expect.any(Function));
// Existing device -> don't clear
MQTT.publish.mockClear();
await MQTT.events.message('homeassistant/binary_sensor/0x000b57fffec6a5b2/update_available/config', stringify({availability_topic: 'zigbee2mqtt/0x000b57fffec6a5b2/availability'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(0);
// Non-existing device of different instance -> don't clear
MQTT.publish.mockClear();
await MQTT.events.message('homeassistant/sensor/0x123/temperature/config', stringify({availability_topic: 'zigbee2mqtt_different/0x123/availability'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(0);
// Existing device but non-existing config -> don't clear
MQTT.publish.mockClear();
await MQTT.events.message('homeassistant/sensor/0x000b57fffec6a5b2/update_available/config', stringify({availability_topic: 'zigbee2mqtt/0x000b57fffec6a5b2/availability'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/sensor/0x000b57fffec6a5b2/update_available/config', null, {qos: 0, retain: true}, expect.any(Function));
// Non-existing device but invalid payload -> clear
MQTT.publish.mockClear();
await MQTT.events.message('homeassistant/sensor/0x123/temperature/config', '1}3');
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(0);
});
});
+1 -1
View File
@@ -972,7 +972,7 @@ describe('Publish', () => {
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({state: 'ON', color: {x: 0.280632719756407, y: 0.288286029784579}, color_temp: 100});
});
it('onlythis Home Assistant: should not set state when color is also set', async () => {
it('Home Assistant: should not set state when color is also set', async () => {
settings.set(['homeassistant'], true);
const device = zigbeeHerdsman.devices.bulb_color;
controller.state.set(device.ieeeAddr, {state: 'ON'})