diff --git a/lib/extension/homeassistant.ts b/lib/extension/homeassistant.ts index 8770810dec..3e1b54f313 100644 --- a/lib/extension/homeassistant.ts +++ b/lib/extension/homeassistant.ts @@ -375,6 +375,7 @@ export default class HomeAssistant extends Extension { const tilt = exposes.find((expose) => expose.features.find((e) => e.name === 'tilt')); const motorState = definitionExposes?.find((e) => e.type === 'enum' && e.name === 'motor_state' && e.access === ACCESS_STATE); + const running = definitionExposes?.find((e) => e.type === 'binary' && e.name === 'running'); const discoveryEntry: DiscoveryEntry = { type: 'cover', @@ -382,48 +383,38 @@ export default class HomeAssistant extends Extension { object_id: endpoint ? `cover_${endpoint}` : 'cover', discovery_payload: { command_topic_prefix: endpoint, + command_topic: true, + state_topic: true, }, }; - // For covers only supporting tilt don't discover the command/state_topic, otherwise - // HA does not correctly reflect the state - // - https://github.com/home-assistant/core/issues/51793 - // - https://github.com/Koenkk/zigbee-herdsman-converters/pull/2663 - if (!tilt || (tilt && position)) { - discoveryEntry.discovery_payload.command_topic = true; - discoveryEntry.discovery_payload.state_topic = !position; - discoveryEntry.discovery_payload.command_topic_prefix = endpoint; - - // For curtains that have `motor_state` lookup a possible state names and make this - // available for discovery. If the curtains only support the `running` value, - // then we use it anyway. The movement direction is calculated (assumed) in this case. - if (motorState) { - const openingLookup = ['opening', 'open', 'forward', 'up', 'rising']; - const closingLookup = ['closing', 'close', 'backward', 'back', 'reverse', 'down', 'declining']; - const stoppedLookup = ['stopped', 'stop', 'pause', 'paused']; - - const openingState = motorState.values.find((s) => openingLookup.includes(s.toLowerCase())); - const closingState = motorState.values.find((s) => closingLookup.includes(s.toLowerCase())); - const stoppedState = motorState.values.find((s) => stoppedLookup.includes(s.toLowerCase())); - - if (openingState && closingState && stoppedState) { - discoveryEntry.discovery_payload.state_topic = true; - discoveryEntry.discovery_payload.state_opening = openingState; - discoveryEntry.discovery_payload.state_closing = closingState; - discoveryEntry.discovery_payload.state_stopped = stoppedState; - discoveryEntry.discovery_payload.value_template = `{% if not value_json.motor_state %} ` + - `${stoppedState} {% else %} {{ value_json.motor_state }} {% endif %}`; - } - } else { - const running = definitionExposes?.find((e) => e.type === 'binary' && e.name === 'running'); - - if (running) { - discoveryEntry.discovery_payload.state_topic = true; - discoveryEntry.discovery_payload.value_template = `{% if not value_json.running %} ` + - `stopped {% else %} {% if value_json.position > 0 %} closing {% else %} ` + - `opening {% endif %} {% endif %}`; - } + // For curtains that have `motor_state` lookup a possible state names and make this + // available for discovery. If the curtains only support the `running` value, + // then we use it anyway. The movement direction is calculated (assumed) in this case. + if (motorState) { + const openingLookup = ['opening', 'open', 'forward', 'up', 'rising']; + const closingLookup = ['closing', 'close', 'backward', 'back', 'reverse', 'down', 'declining']; + const stoppedLookup = ['stopped', 'stop', 'pause', 'paused']; + + const openingState = motorState.values.find((s) => openingLookup.includes(s.toLowerCase())); + const closingState = motorState.values.find((s) => closingLookup.includes(s.toLowerCase())); + const stoppedState = motorState.values.find((s) => stoppedLookup.includes(s.toLowerCase())); + + if (openingState && closingState && stoppedState) { + discoveryEntry.discovery_payload.state_opening = openingState; + discoveryEntry.discovery_payload.state_closing = closingState; + discoveryEntry.discovery_payload.state_stopped = stoppedState; + discoveryEntry.discovery_payload.value_template = `{% if not value_json.motor_state %} ` + + `${stoppedState} {% else %} {{ value_json.motor_state }} {% endif %}`; } + } else if (running) { + discoveryEntry.discovery_payload.value_template = `{% if not value_json.running %} ` + + `stopped {% else %} {% if value_json.position > 0 %} closing {% else %} ` + + `opening {% endif %} {% endif %}`; + } else { + discoveryEntry.discovery_payload.value_template = `{{ value_json.state }}`; + discoveryEntry.discovery_payload.state_open = 'OPEN'; + discoveryEntry.discovery_payload.state_closed = 'CLOSE'; } if (!position && !tilt) { diff --git a/test/homeassistant.test.js b/test/homeassistant.test.js index 068d24cde9..e0564049fa 100644 --- a/test/homeassistant.test.js +++ b/test/homeassistant.test.js @@ -811,6 +811,10 @@ describe('HomeAssistant extension', () => { set_position_topic: 'zigbee2mqtt/smart vent/set', set_position_template: '{ "position": {{ position }} }', position_template: '{{ value_json.position }}', + state_topic: 'zigbee2mqtt/smart vent', + value_template: `{{ value_json.state }}`, + state_open: 'OPEN', + state_closed: 'CLOSE', json_attributes_topic: 'zigbee2mqtt/smart vent', name: 'smart vent', unique_id: '0x0017880104e45551_cover_zigbee2mqtt',