From 48dabee30695884e74e679ae82167e1560e6ca30 Mon Sep 17 00:00:00 2001 From: mundschenk_at Date: Sat, 2 Nov 2024 22:41:27 +0100 Subject: [PATCH] Only add event entities wen homeassistant/experimental_event_entities is true --- lib/extension/homeassistant.ts | 11 ++++++- lib/types/types.d.ts | 1 + lib/util/settings.schema.json | 6 ++++ lib/util/settings.ts | 8 +++++- test/homeassistant.test.js | 52 ++++++++++++++++++++++++++++++---- test/settings.test.js | 1 + 6 files changed, 71 insertions(+), 8 deletions(-) diff --git a/lib/extension/homeassistant.ts b/lib/extension/homeassistant.ts index ebf7cf84f9..c86b5e891b 100644 --- a/lib/extension/homeassistant.ts +++ b/lib/extension/homeassistant.ts @@ -441,6 +441,7 @@ export default class HomeAssistant extends Extension { private statusTopic: string; private entityAttributes: boolean; private legacyTrigger: boolean; + private experimentalEventEntities: boolean; // @ts-expect-error initialized in `start` private zigbee2MQTTVersion: string; // @ts-expect-error initialized in `start` @@ -472,6 +473,7 @@ export default class HomeAssistant extends Extension { this.statusTopic = haSettings.status_topic; this.entityAttributes = haSettings.legacy_entity_attributes; this.legacyTrigger = haSettings.legacy_triggers; + this.experimentalEventEntities = haSettings.experimental_event_entities; if (haSettings.discovery_topic === settings.get().mqtt.base_topic) { throw new Error(`'homeassistant.discovery_topic' cannot not be equal to the 'mqtt.base_topic' (got '${settings.get().mqtt.base_topic}')`); } @@ -1156,7 +1158,12 @@ export default class HomeAssistant extends Extension { * If enum attribute does not have SET access and is named 'action', then expose * as EVENT entity. Wildcard actions like `recall_*` are currently not supported. */ - if (firstExpose.access & ACCESS_STATE && !(firstExpose.access & ACCESS_SET) && firstExpose.property == 'action') { + if ( + this.experimentalEventEntities && + firstExpose.access & ACCESS_STATE && + !(firstExpose.access & ACCESS_SET) && + firstExpose.property == 'action' + ) { discoveryEntries.push({ type: 'event', object_id: firstExpose.property, @@ -2214,11 +2221,13 @@ export default class HomeAssistant extends Extension { private parseActionValue(action: string): ActionData { const buttons = action.match(ACTION_BUTTON_PATTERN); if (buttons?.groups?.action) { + //console.log('Recognized button actions', buttons.groups); return {...buttons.groups, action: buttons.groups.action}; } const scenes = action.match(ACTION_SCENE_PATTERN); if (scenes?.groups?.action) { + //console.log('Recognized scene actions', scenes.groups); return {...scenes.groups, action: scenes.groups.action}; } diff --git a/lib/types/types.d.ts b/lib/types/types.d.ts index 20656165ba..8aa313c7ff 100644 --- a/lib/types/types.d.ts +++ b/lib/types/types.d.ts @@ -118,6 +118,7 @@ declare global { status_topic: string; legacy_entity_attributes: boolean; legacy_triggers: boolean; + experimental_event_entities: boolean; }; permit_join: boolean; availability?: { diff --git a/lib/util/settings.schema.json b/lib/util/settings.schema.json index 0585d48e6a..afe0dbf96e 100644 --- a/lib/util/settings.schema.json +++ b/lib/util/settings.schema.json @@ -40,6 +40,12 @@ "description": "Home Assistant status topic", "requiresRestart": true, "examples": ["homeassistant/status"] + }, + "experimental_event_entities": { + "type": "boolean", + "title": "Home Assistant experimental event entities", + "description": "Home Assistant experimental event entities, when enabled Zigbee2MQTT will add event entities for exposed actions. The events and attributes are currently deemed experimental and subject to change.", + "default": false } } } diff --git a/lib/util/settings.ts b/lib/util/settings.ts index 9437dbd291..588fb98cf7 100644 --- a/lib/util/settings.ts +++ b/lib/util/settings.ts @@ -136,7 +136,13 @@ function loadSettingsWithDefaults(): void { } if (_settingsWithDefaults.homeassistant) { - const defaults = {discovery_topic: 'homeassistant', status_topic: 'hass/status', legacy_entity_attributes: true, legacy_triggers: true}; + const defaults = { + discovery_topic: 'homeassistant', + status_topic: 'hass/status', + legacy_entity_attributes: true, + legacy_triggers: true, + experimental_event_entities: false, + }; const sLegacy = {}; if (_settingsWithDefaults.advanced) { for (const key of [ diff --git a/test/homeassistant.test.js b/test/homeassistant.test.js index 6ac4fa8339..8b364d9e47 100644 --- a/test/homeassistant.test.js +++ b/test/homeassistant.test.js @@ -89,6 +89,9 @@ describe('HomeAssistant extension', () => { }); it('Should discover devices and groups', async () => { + settings.set(['homeassistant'], {experimental_event_entities: true}); + await resetExtension(); + let payload; payload = { @@ -1719,10 +1722,9 @@ describe('HomeAssistant extension', () => { it('Should discover trigger when click is published', async () => { const discovered = MQTT.publish.mock.calls.filter((c) => c[0].includes('0x0017880104e45520')).map((c) => c[0]); - expect(discovered.length).toBe(8); + expect(discovered.length).toBe(7); expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/click/config'); expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/action/config'); - expect(discovered).toContain('homeassistant/event/0x0017880104e45520/action/config'); MQTT.publish.mockClear(); @@ -1903,9 +1905,8 @@ describe('HomeAssistant extension', () => { await resetExtension(); const discovered = MQTT.publish.mock.calls.filter((c) => c[0].includes('0x0017880104e45520')).map((c) => c[0]); - expect(discovered.length).toBe(7); + expect(discovered.length).toBe(6); expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/action/config'); - expect(discovered).toContain('homeassistant/event/0x0017880104e45520/action/config'); expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/battery/config'); expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/linkquality/config'); }); @@ -1915,10 +1916,9 @@ describe('HomeAssistant extension', () => { await resetExtension(); const discovered = MQTT.publish.mock.calls.filter((c) => c[0].includes('0x0017880104e45520')).map((c) => c[0]); - expect(discovered.length).toBe(6); + expect(discovered.length).toBe(5); expect(discovered).not.toContain('homeassistant/sensor/0x0017880104e45520/click/config'); expect(discovered).not.toContain('homeassistant/sensor/0x0017880104e45520/action/config'); - expect(discovered).toContain('homeassistant/event/0x0017880104e45520/action/config'); MQTT.publish.mockClear(); @@ -1964,6 +1964,46 @@ describe('HomeAssistant extension', () => { expect(MQTT.publish).toHaveBeenCalledTimes(3); }); + it('Should enable experimental event entities', async () => { + settings.set(['homeassistant'], {experimental_event_entities: true}); + settings.set(['devices', '0x0017880104e45520'], { + legacy: false, + friendly_name: 'button', + retain: false, + }); + await resetExtension(); + + const payload = { + availability: [{topic: 'zigbee2mqtt/bridge/state'}], + device: { + identifiers: ['zigbee2mqtt_0x0017880104e45520'], + manufacturer: 'Aqara', + model: 'Wireless mini switch (WXKG11LM)', + name: 'button', + sw_version: null, + via_device: 'zigbee2mqtt_bridge_0x00124b00120144ae', + }, + event_types: ['single', 'double', 'triple', 'quadruple', 'hold', 'release'], + icon: 'mdi:gesture-double-tap', + json_attributes_topic: 'zigbee2mqtt/button', + name: 'Action', + object_id: 'button_action', + origin: origin, + state_topic: 'zigbee2mqtt/button', + unique_id: '0x0017880104e45520_action_zigbee2mqtt', + // Needs to be updated whenever one of the ACTION_*_PATTERN constants changes. + value_template: + '{%- set buttons = value_json.action|regex_findall_index(^(?P