Skip to content

Commit

Permalink
Home Assistant discovery: always expose cover state. zigbee2mqtt/hass…
Browse files Browse the repository at this point in the history
  • Loading branch information
Koenkk committed Aug 9, 2022
1 parent 5f778a7 commit 0aa29a0
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 38 deletions.
67 changes: 29 additions & 38 deletions lib/extension/homeassistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,55 +375,46 @@ 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',
mockProperties: [],
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) {
Expand Down
4 changes: 4 additions & 0 deletions test/homeassistant.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 0aa29a0

Please sign in to comment.