From 1ea2734369d75a6ddc540582be10810687773d98 Mon Sep 17 00:00:00 2001 From: Yip Rui Fung Date: Sun, 27 Aug 2023 09:30:43 +0800 Subject: [PATCH 1/2] Use QOS1 for rarely sent messages Specifically discovery and availability depending on the set up, it's possible for these messages to be silently discarded by the broker. Sending them as QOS1 means the mqtt library used will resend them until it gets an ACK. Ensuring delivery is particularly important for messages that are rarely sent like discovery or availability as they are only sent when there are changes, and nondelivery or dropped messages for them impede proper functioning in home assistant. --- lib/extension/availability.ts | 4 ++-- lib/extension/homeassistant.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/extension/availability.ts b/lib/extension/availability.ts index f34dce64d6..e711576df7 100644 --- a/lib/extension/availability.ts +++ b/lib/extension/availability.ts @@ -105,7 +105,7 @@ export default class Availability extends Extension { override async start(): Promise { this.eventBus.onEntityRenamed(this, (data) => { if (utils.isAvailabilityEnabledForEntity(data.entity, settings.get())) { - this.mqtt.publish(`${data.from}/availability`, null, {retain: true, qos: 0}); + this.mqtt.publish(`${data.from}/availability`, null, {retain: true, qos: 1}); this.publishAvailability(data.entity, false, true); } }); @@ -164,7 +164,7 @@ export default class Availability extends Extension { const topic = `${entity.name}/availability`; const payload = utils.availabilityPayload(available ? 'online' : 'offline', settings.get()); this.availabilityCache[entity.ID] = available; - this.mqtt.publish(topic, payload, {retain: true, qos: 0}); + this.mqtt.publish(topic, payload, {retain: true, qos: 1}); if (!skipGroups && entity.isDevice()) { this.zigbee.groups().filter((g) => g.hasMember(entity)) diff --git a/lib/extension/homeassistant.ts b/lib/extension/homeassistant.ts index 35f14ba4ff..89c9aa2cc0 100644 --- a/lib/extension/homeassistant.ts +++ b/lib/extension/homeassistant.ts @@ -931,7 +931,7 @@ export default class HomeAssistant extends Extension { @bind onDeviceRemoved(data: eventdata.DeviceRemoved): void { logger.debug(`Clearing Home Assistant discovery topic for '${data.name}'`); this.discovered[data.ieeeAddr]?.topics.forEach((topic) => { - this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic, false, false); + this.mqtt.publish(topic, null, {retain: true, qos: 1}, this.discoveryTopic, false, false); }); delete this.discovered[data.ieeeAddr]; @@ -1012,7 +1012,7 @@ export default class HomeAssistant extends Extension { if (data.homeAssisantRename) { for (const config of this.getConfigs(data.entity)) { const topic = this.getDiscoveryTopic(config, data.entity); - this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic, false, false); + this.mqtt.publish(topic, null, {retain: true, qos: 1}, this.discoveryTopic, false, false); } // Make sure Home Assistant deletes the old entity first otherwise another one (_2) is created @@ -1381,7 +1381,7 @@ export default class HomeAssistant extends Extension { } const topic = this.getDiscoveryTopic(config, entity); - this.mqtt.publish(topic, stringify(payload), {retain: true, qos: 0}, this.discoveryTopic, false, false); + this.mqtt.publish(topic, stringify(payload), {retain: true, qos: 1}, this.discoveryTopic, false, false); this.discovered[discoverKey].topics.add(topic); this.discovered[discoverKey].objectIDs.add(config.object_id); config.mockProperties?.forEach((mockProperty) => @@ -1441,7 +1441,7 @@ export default class HomeAssistant extends Extension { if (clear) { logger.debug(`Clearing Home Assistant config '${data.topic}'`); const topic = data.topic.substring(this.discoveryTopic.length + 1); - this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic, false, false); + this.mqtt.publish(topic, null, {retain: true, qos: 1}, this.discoveryTopic, false, false); } } else if ((data.topic === this.statusTopic || data.topic === defaultStatusTopic) && data.message.toLowerCase() === 'online') { @@ -1561,7 +1561,7 @@ export default class HomeAssistant extends Extension { device: this.getDevicePayload(device), }; - await this.mqtt.publish(topic, stringify(payload), {retain: true, qos: 0}, this.discoveryTopic, false, false); + await this.mqtt.publish(topic, stringify(payload), {retain: true, qos: 1}, this.discoveryTopic, false, false); this.discoveredTriggers[device.ieeeAddr].add(discoveredKey); } From 6247614e53877a6523b83001d00ae1151c03c89e Mon Sep 17 00:00:00 2001 From: Yip Rui Fung Date: Sun, 27 Aug 2023 09:40:34 +0800 Subject: [PATCH 2/2] Fix tests for discovery and availability using QOS1 --- test/availability.test.js | 34 +++++------ test/homeassistant.test.js | 112 ++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/test/availability.test.js b/test/availability.test.js index cb4584db34..80dc191829 100644 --- a/test/availability.test.js +++ b/test/availability.test.js @@ -60,11 +60,11 @@ describe('Availability', () => { it('Should publish availabilty on startup for device where it is enabled for', async () => { expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_color/availability', - 'online', {retain: true, qos: 0}, expect.any(Function)); + 'online', {retain: true, qos: 1}, expect.any(Function)); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/remote/availability', - 'online', {retain: true, qos: 0}, expect.any(Function)); + 'online', {retain: true, qos: 1}, expect.any(Function)); expect(MQTT.publish).not.toHaveBeenCalledWith('zigbee2mqtt/bulb_color_2/availability', - 'online', {retain: true, qos: 0}, expect.any(Function)); + 'online', {retain: true, qos: 1}, expect.any(Function)); }); it('Should publish offline for active device when not seen for 10 minutes', async () => { @@ -77,7 +77,7 @@ describe('Availability', () => { expect(devices.bulb_color.ping).toHaveBeenCalledTimes(1); expect(devices.bulb_color.ping).toHaveBeenNthCalledWith(1, true); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_color/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); }); it('Shouldnt do anything for a device when availability: false is set for device', async () => { @@ -93,7 +93,7 @@ describe('Availability', () => { await advancedTime(utils.hours(26)); expect(devices.remote.ping).toHaveBeenCalledTimes(0); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/remote/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); }); it('Should reset ping timer when device last seen changes for active device', async () => { @@ -111,7 +111,7 @@ describe('Availability', () => { expect(devices.bulb_color.ping).toHaveBeenCalledTimes(1); expect(devices.bulb_color.ping).toHaveBeenNthCalledWith(1, true); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_color/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); }); it('Should ping again when first ping fails', async () => { @@ -132,7 +132,7 @@ describe('Availability', () => { expect(devices.bulb_color.ping).toHaveBeenNthCalledWith(1, true); expect(devices.bulb_color.ping).toHaveBeenNthCalledWith(2, false); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_color/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); }); it('Should reset ping timer when device last seen changes for passive device', async () => { @@ -150,7 +150,7 @@ describe('Availability', () => { await advancedTime(utils.hours(3)); expect(devices.remote.ping).toHaveBeenCalledTimes(0); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/remote/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); }); it('Should immediately mark device as online when it lastSeen changes', async () => { @@ -158,13 +158,13 @@ describe('Availability', () => { await advancedTime(utils.minutes(15)); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_color/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); devices.bulb_color.lastSeen = Date.now(); await zigbeeHerdsman.events.lastSeenChanged({device: devices.bulb_color}); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_color/availability', - 'online', {retain: true, qos: 0}, expect.any(Function)); + 'online', {retain: true, qos: 1}, expect.any(Function)); }); it('Should allow to change availability timeout via device options', async () => { @@ -283,12 +283,12 @@ describe('Availability', () => { await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_color/availability', - null, {retain: true, qos: 0}, expect.any(Function)); + null, {retain: true, qos: 1}, expect.any(Function)); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_new_name/availability', - 'online', {retain: true, qos: 0}, expect.any(Function)); + 'online', {retain: true, qos: 1}, expect.any(Function)); await advancedTime(utils.hours(12)); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bulb_new_name/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); }); it('Should publish availabiltiy payload in JSON format', async () => { @@ -298,7 +298,7 @@ describe('Availability', () => { await advancedTime(utils.hours(26)); expect(devices.remote.ping).toHaveBeenCalledTimes(0); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/remote/availability', - stringify({state: 'offline'}), {retain: true, qos: 0}, expect.any(Function)); + stringify({state: 'offline'}), {retain: true, qos: 1}, expect.any(Function)); }); it('Deprecated - should allow to block via advanced.availability_blocklist', async () => { @@ -332,16 +332,16 @@ describe('Availability', () => { settings.set(['devices', devices.bulb_color_2.ieeeAddr, 'availability'], true); await resetExtension(); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/group_tradfri_remote/availability', - 'online', {retain: true, qos: 0}, expect.any(Function)); + 'online', {retain: true, qos: 1}, expect.any(Function)); MQTT.publish.mockClear(); await advancedTime(utils.minutes(12)); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/group_tradfri_remote/availability', - 'offline', {retain: true, qos: 0}, expect.any(Function)); + 'offline', {retain: true, qos: 1}, expect.any(Function)); MQTT.publish.mockClear(); devices.bulb_color_2.lastSeen = Date.now(); await zigbeeHerdsman.events.lastSeenChanged({device: devices.bulb_color_2}); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/group_tradfri_remote/availability', - 'online', {retain: true, qos: 0}, expect.any(Function)); + 'online', {retain: true, qos: 1}, expect.any(Function)); }); }); diff --git a/test/homeassistant.test.js b/test/homeassistant.test.js index e14ce43b5f..6ce2d93258 100644 --- a/test/homeassistant.test.js +++ b/test/homeassistant.test.js @@ -117,7 +117,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/1221051039810110150109113116116_9/light/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -141,7 +141,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/switch/1221051039810110150109113116116_9/switch/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -168,7 +168,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -195,7 +195,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/humidity/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -222,7 +222,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/pressure/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -250,7 +250,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/battery/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -278,7 +278,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/linkquality/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -306,7 +306,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/switch/0x0017880104e45542/switch_left/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -334,7 +334,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/switch/0x0017880104e45542/switch_right/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -375,7 +375,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/0x000b57fffec6a5b2/light/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -417,7 +417,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -444,7 +444,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/humidity/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -471,7 +471,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/pressure/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -530,7 +530,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -558,7 +558,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/humidity/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -600,7 +600,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -627,7 +627,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/humidity/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -676,7 +676,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/0x0017880104e45541/light/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -749,7 +749,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/fan/0x0017880104e45548/fan/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -811,7 +811,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/climate/0x0017882104a44559/climate/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -847,7 +847,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/cover/0x0017880104e45551/cover/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -881,7 +881,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/cover/0xf4ce368a38be56a1/cover_l6/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -915,7 +915,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'my_custom_discovery_topic/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1042,7 +1042,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payloadHA), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1179,7 +1179,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1192,31 +1192,31 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/humidity/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/pressure/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/battery/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/linkquality/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1260,14 +1260,14 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -1289,7 +1289,7 @@ describe('HomeAssistant extension', () => { "manufacturer":"Xiaomi" } }), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1341,14 +1341,14 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/1221051039810110150109113116116_9/light/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/1221051039810110150109113116116_9/light/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1361,7 +1361,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).not.toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', null, - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -1388,7 +1388,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1420,7 +1420,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/binary_sensor/0x000b57fffec6a5b2/update_available/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1458,7 +1458,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/device_automation/0x0017880104e45520/action_single/config', stringify(discoverPayloadAction), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -1482,7 +1482,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/device_automation/0x0017880104e45520/click_single/config', stringify(discoverPayloadClick), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -1528,14 +1528,14 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).not.toHaveBeenCalledWith( 'homeassistant/device_automation/0x0017880104e45520/action_single/config', stringify(discoverPayloadAction), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); expect(MQTT.publish).not.toHaveBeenCalledWith( 'homeassistant/device_automation/0x0017880104e45520/click_single/config', stringify(discoverPayloadClick), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -1646,7 +1646,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/device_automation/0x0017880104e45520/action_single/config', stringify(discoverPayload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); @@ -1711,7 +1711,7 @@ describe('HomeAssistant extension', () => { await MQTT.events.message('homeassistant/light/1221051039810110150109113116116_91231/light/config', stringify({availability: [{topic: 'zigbee2mqtt/bridge/state'}]})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledTimes(1); - expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/light/1221051039810110150109113116116_91231/light/config', null, {qos: 0, retain: true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/light/1221051039810110150109113116116_91231/light/config', null, {qos: 1, retain: true}, expect.any(Function)); // Existing group -> dont clear MQTT.publish.mockClear(); @@ -1724,21 +1724,21 @@ describe('HomeAssistant extension', () => { await MQTT.events.message('homeassistant/light/9/light/config', stringify({availability: [{topic: 'zigbee2mqtt/bridge/state'}]})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledTimes(1); - expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/light/9/light/config', null, {qos: 0, retain: true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/light/9/light/config', null, {qos: 1, retain: true}, expect.any(Function)); // Existing group, non existing config -> clear MQTT.publish.mockClear(); await MQTT.events.message('homeassistant/light/1221051039810110150109113116116_9/switch/config', stringify({availability: [{topic: 'zigbee2mqtt/bridge/state'}]})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledTimes(1); - expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/light/1221051039810110150109113116116_9/switch/config', null, {qos: 0, retain: true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/light/1221051039810110150109113116116_9/switch/config', null, {qos: 1, retain: true}, expect.any(Function)); // Non-existing device -> clear MQTT.publish.mockClear(); await MQTT.events.message('homeassistant/sensor/0x123/temperature/config', stringify({availability: [{topic: 'zigbee2mqtt/bridge/state'}]})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledTimes(1); - expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/sensor/0x123/temperature/config', null, {qos: 0, retain: true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/sensor/0x123/temperature/config', null, {qos: 1, retain: true}, expect.any(Function)); // Existing device -> don't clear MQTT.publish.mockClear(); @@ -1757,7 +1757,7 @@ describe('HomeAssistant extension', () => { await MQTT.events.message('homeassistant/sensor/0x000b57fffec6a5b2/update_available/config', stringify({availability: [{topic: 'zigbee2mqtt/bridge/state'}]})); 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)); + expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/sensor/0x000b57fffec6a5b2/update_available/config', null, {qos: 1, retain: true}, expect.any(Function)); // Non-existing device but invalid payload -> clear MQTT.publish.mockClear(); @@ -1784,11 +1784,11 @@ describe('HomeAssistant extension', () => { await MQTT.events.message('homeassistant/sensor/0x000b57fffec6a5b2/update_available/config', stringify({availability: [{topic: 'zigbee2mqtt/bridge/state'}]})); await flushPromises(); - expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/sensor/0x000b57fffec6a5b2/update_available/config', null, {qos: 0, retain: true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/sensor/0x000b57fffec6a5b2/update_available/config', null, {qos: 1, retain: true}, expect.any(Function)); MQTT.publish.mockClear(); await MQTT.events.message('homeassistant/device_automation/0x000b57fffec6a5b2/action_button_3_single/config', stringify({topic: 'zigbee2mqtt/0x000b57fffec6a5b2/availability'})); await flushPromises(); - expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/device_automation/0x000b57fffec6a5b2/action_button_3_single/config', null, {qos: 0, retain: true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith('homeassistant/device_automation/0x000b57fffec6a5b2/action_button_3_single/config', null, {qos: 1, retain: true}, expect.any(Function)); }); it('Should not have Home Assistant legacy entity attributes when disabled', async () => { @@ -1820,7 +1820,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1870,7 +1870,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/1221051039810110150109113116116_9/light/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1919,7 +1919,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/1221051039810110150109113116116_9/light/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -1973,7 +1973,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/light/0x000b57fffec6a5b2/light/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -2011,7 +2011,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x000b57fffec6a5b2/last_seen/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); }); @@ -2048,7 +2048,7 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/sensor/0x0017880104e45522/temperature/config', stringify(payload), - { retain: true, qos: 0 }, + { retain: true, qos: 1 }, expect.any(Function), ); });