diff --git a/lib/extension/homeassistant.js b/lib/extension/homeassistant.js index 84061e436..a8577e50c 100644 --- a/lib/extension/homeassistant.js +++ b/lib/extension/homeassistant.js @@ -1992,8 +1992,8 @@ class HomeAssistant extends Extension { * https://github.com/Koenkk/zigbee2mqtt/issues/959#issuecomment-480341347 */ if (settings.get().advanced.homeassistant_legacy_triggers) { - const key = ['action', 'click'].find((k) => data.payload.hasOwnProperty(k) && data.payload[k] !== ''); - if (key) { + const keys = ['action', 'click'].filter((k) => data.payload.hasOwnProperty(k) && data.payload[k] !== ''); + for (const key of keys) { this.publishEntityState(data.entity.device.ieeeAddr, {[key]: ''}); } } @@ -2004,33 +2004,35 @@ class HomeAssistant extends Extension { * Whenever a device publish an {action: *} we discover an MQTT device trigger sensor * and republish it to zigbee2mqtt/my_devic/action */ - const key = ['action', 'click'].find((k) => data.payload[k] && data.payload[k] !== ''); - if (data.entity.definition && key) { - const device = data.entity.device; - if (!this.discoveredTriggers[device.ieeeAddr]) { - this.discoveredTriggers[device.ieeeAddr] = new Set(); + const keys = ['action', 'click'].filter((k) => data.payload[k] && data.payload[k] !== ''); + for (const key of keys) { + if (data.entity.definition) { + const device = data.entity.device; + if (!this.discoveredTriggers[device.ieeeAddr]) { + this.discoveredTriggers[device.ieeeAddr] = new Set(); + } + + const value = data.payload[key].toString(); + const discoveredKey = `${key}_${value}`; + + if (!this.discoveredTriggers[device.ieeeAddr].has(discoveredKey)) { + const config = cfg[`trigger_${key}`]; + config.object_id = `${key}_${value}`; + const topic = this.getDiscoveryTopic(config, device); + const payload = { + ...config.discovery_payload, + subtype: value, + payload: value, + topic: `${settings.get().mqtt.base_topic}/${data.entity.name}/${key}`, + device: this.getDevicePayload(data.entity), + }; + + await this.mqtt.publish(topic, stringify(payload), {retain: true, qos: 0}, this.discoveryTopic); + this.discoveredTriggers[device.ieeeAddr].add(discoveredKey); + } + + await this.mqtt.publish(`${data.entity.name}/${key}`, value, {}); } - - const value = data.payload[key].toString(); - const discoveredKey = `${key}_${value}`; - - if (!this.discoveredTriggers[device.ieeeAddr].has(discoveredKey)) { - const config = cfg[`trigger_${key}`]; - config.object_id = `${key}_${value}`; - const topic = this.getDiscoveryTopic(config, device); - const payload = { - ...config.discovery_payload, - subtype: value, - payload: value, - topic: `${settings.get().mqtt.base_topic}/${data.entity.name}/${key}`, - device: this.getDevicePayload(data.entity), - }; - - await this.mqtt.publish(topic, stringify(payload), {retain: true, qos: 0}, this.discoveryTopic); - this.discoveredTriggers[device.ieeeAddr].add(discoveredKey); - } - - await this.mqtt.publish(`${data.entity.name}/${key}`, value, {}); } /** diff --git a/test/homeassistant.test.js b/test/homeassistant.test.js index 531559b65..ead2c9bd3 100644 --- a/test/homeassistant.test.js +++ b/test/homeassistant.test.js @@ -884,12 +884,11 @@ describe('HomeAssistant extension', () => { MQTT.publish.mockClear(); const device = zigbeeHerdsman.devices.WXKG11LM; - settings.set(['devices', device.ieeeAddr, 'legacy'], false); const payload = {data: {onOff: 1}, cluster: 'genOnOff', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; await zigbeeHerdsman.events.message(payload); await flushPromises(); - const discoverPayload = { + const discoverPayloadAction = { "automation_type":"trigger", "type":"action", "subtype":"single", @@ -908,7 +907,31 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledWith( 'homeassistant/device_automation/0x0017880104e45520/action_single/config', - stringify(discoverPayload), + stringify(discoverPayloadAction), + { retain: true, qos: 0 }, + expect.any(Function), + ); + + const discoverPayloadClick = { + "automation_type":"trigger", + "type":"click", + "subtype":"single", + "payload":"single", + "topic":"zigbee2mqtt/button/click", + "device":{ + "identifiers":[ + "zigbee2mqtt_0x0017880104e45520" + ], + "name":"button", + "sw_version": this.version, + "model":"Aqara wireless switch (WXKG11LM)", + "manufacturer":"Xiaomi" + } + }; + + expect(MQTT.publish).toHaveBeenCalledWith( + 'homeassistant/device_automation/0x0017880104e45520/click_single/config', + stringify(discoverPayloadClick), { retain: true, qos: 0 }, expect.any(Function), ); @@ -920,9 +943,16 @@ describe('HomeAssistant extension', () => { expect.any(Function), ); + expect(MQTT.publish).toHaveBeenCalledWith( + 'zigbee2mqtt/button/click', + 'single', + { retain: false, qos: 0 }, + expect.any(Function), + ); + expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/button', - stringify({action: "single", linkquality: 10}), + stringify({action: "single", linkquality: 10, click: "single"}), { retain: false, qos: 0 }, expect.any(Function), ); @@ -934,13 +964,27 @@ describe('HomeAssistant extension', () => { expect.any(Function), ); + expect(MQTT.publish).toHaveBeenCalledWith( + 'zigbee2mqtt/button', + stringify({linkquality: 10, click: ""}), + { retain: false, qos: 0 }, + expect.any(Function), + ); + // Should only discover it once MQTT.publish.mockClear(); await zigbeeHerdsman.events.message(payload); await flushPromises(); expect(MQTT.publish).not.toHaveBeenCalledWith( 'homeassistant/device_automation/0x0017880104e45520/action_single/config', - stringify(discoverPayload), + stringify(discoverPayloadAction), + { retain: true, qos: 0 }, + expect.any(Function), + ); + + expect(MQTT.publish).not.toHaveBeenCalledWith( + 'homeassistant/device_automation/0x0017880104e45520/click_single/config', + stringify(discoverPayloadClick), { retain: true, qos: 0 }, expect.any(Function), ); @@ -951,6 +995,13 @@ describe('HomeAssistant extension', () => { { retain: false, qos: 0 }, expect.any(Function), ); + + expect(MQTT.publish).toHaveBeenCalledWith( + 'zigbee2mqtt/button/click', + 'single', + { retain: false, qos: 0 }, + expect.any(Function), + ); }); it('Should not discover sensor_click when legacy: false is set', async () => {