mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-07-14 15:48:53 +00:00
Clear outdated Home Assistant configs
This commit is contained in:
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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'})
|
||||
|
||||
Reference in New Issue
Block a user