feat: Use labels in Home Assistant entity naming (#18678)

* feat: Use labels in Home Assistant entity naming

* tweak comment
This commit is contained in:
Artem Draft authored and GitHub committed 2023-08-22 08:07:23 +02:00
1 parent 71c4211d13
commit e33e335c0c
3 files changed
+88 -17

No files matched your search

+45 -10
View File
@@ -16,6 +16,7 @@ const sensorClick: DiscoveryEntry = {
object_id: 'click',
mockProperties: [{property: 'click', value: null}],
discovery_payload: {
name: 'Click',
icon: 'mdi:toggle-switch',
value_template: '{{ value_json.click }}',
},
@@ -42,6 +43,7 @@ const legacyMapping = [
mockProperties: [{property: 'brightness', value: null}],
object_id: 'brightness',
discovery_payload: {
name: 'Brightness',
unit_of_measurement: 'brightness',
icon: 'mdi:brightness-5',
value_template: '{{ value_json.brightness }}',
@@ -142,6 +144,7 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `light_${endpoint}` : 'light',
mockProperties: [{property: state.property, value: null}],
discovery_payload: {
name: endpoint ? utils.capitalize(endpoint) : null,
brightness: !!hasBrightness,
schema: 'json',
command_topic: true,
@@ -187,6 +190,7 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `switch_${endpoint}` : 'switch',
mockProperties: [{property: property, value: null}],
discovery_payload: {
name: endpoint ? utils.capitalize(endpoint) : null,
payload_off: state.value_off,
payload_on: state.value_on,
value_template: `{{ value_json.${property} }}`,
@@ -197,6 +201,7 @@ export default class HomeAssistant extends Extension {
const different = ['valve_detection', 'window_detection', 'auto_lock', 'away_mode'];
if (different.includes(property)) {
discoveryEntry.discovery_payload.name = firstExpose.label;
discoveryEntry.discovery_payload.command_topic_postfix = property;
discoveryEntry.discovery_payload.state_off = state.value_off;
discoveryEntry.discovery_payload.state_on = state.value_on;
@@ -220,6 +225,7 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `climate_${endpoint}` : 'climate',
mockProperties: [],
discovery_payload: {
name: endpoint ? utils.capitalize(endpoint) : null,
// Static
state_topic: false,
temperature_unit: 'C',
@@ -308,6 +314,7 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `${tempCalibration.name}_${endpoint}` : `${tempCalibration.name}`,
mockProperties: [{property: tempCalibration.property, value: null}],
discovery_payload: {
name: endpoint ? `${tempCalibration.label} ${endpoint}` : tempCalibration.label,
value_template: `{{ value_json.${tempCalibration.property} }}`,
command_topic: true,
command_topic_prefix: endpoint,
@@ -334,6 +341,7 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `${piHeatingDemand.name}_${endpoint}` : `${piHeatingDemand.name}`,
mockProperties: [{property: piHeatingDemand.property, value: null}],
discovery_payload: {
name: endpoint ? `${piHeatingDemand.label} ${endpoint}` : piHeatingDemand.label,
value_template: `{{ value_json.${piHeatingDemand.property} }}`,
...(piHeatingDemand.unit && {unit_of_measurement: piHeatingDemand.unit}),
entity_category: 'diagnostic',
@@ -354,6 +362,7 @@ export default class HomeAssistant extends Extension {
object_id: 'lock',
mockProperties: [{property: state.property, value: null}],
discovery_payload: {
name: null,
command_topic: true,
value_template: `{{ value_json.${state.property} }}`,
},
@@ -361,12 +370,14 @@ export default class HomeAssistant extends Extension {
if (state.property === 'keypad_lockout') {
// deprecated: keypad_lockout is messy, but changing is breaking
discoveryEntry.discovery_payload.name = firstExpose.label;
discoveryEntry.discovery_payload.payload_lock = state.value_on;
discoveryEntry.discovery_payload.payload_unlock = state.value_off;
discoveryEntry.discovery_payload.state_topic = true;
discoveryEntry.object_id = 'keypad_lock';
} else if (state.property === 'child_lock') {
// deprecated: child_lock is messy, but changing is breaking
discoveryEntry.discovery_payload.name = firstExpose.label;
discoveryEntry.discovery_payload.payload_lock = state.value_on;
discoveryEntry.discovery_payload.payload_unlock = state.value_off;
discoveryEntry.discovery_payload.state_locked = 'LOCK';
@@ -399,6 +410,7 @@ export default class HomeAssistant extends Extension {
mockProperties: [{property: state.property, value: null}],
object_id: endpoint ? `cover_${endpoint}` : 'cover',
discovery_payload: {
name: endpoint ? utils.capitalize(endpoint) : null,
command_topic_prefix: endpoint,
command_topic: true,
state_topic: true,
@@ -473,6 +485,7 @@ export default class HomeAssistant extends Extension {
object_id: 'fan',
mockProperties: [{property: 'fan_state', value: null}],
discovery_payload: {
name: null,
state_topic: true,
state_value_template: '{{ value_json.fan_state }}',
command_topic: true,
@@ -584,6 +597,7 @@ export default class HomeAssistant extends Extension {
`switch_${firstExpose.name}_${endpoint}` :
`switch_${firstExpose.name}`,
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
value_template: typeof firstExpose.value_on === 'boolean' ?
`{% if value_json.${firstExpose.property} %} true {% else %} false {% endif %}` :
`{{ value_json.${firstExpose.property} }}`,
@@ -595,6 +609,10 @@ export default class HomeAssistant extends Extension {
...(lookup[firstExpose.name] || {}),
},
};
// Let Home Assistant generate entity name when device_class is present
if (discoveryEntry.discovery_payload.device_class) delete discoveryEntry.discovery_payload.name;
discoveryEntries.push(discoveryEntry);
} else {
const discoveryEntry: DiscoveryEntry = {
@@ -602,12 +620,17 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `${firstExpose.name}_${endpoint}` : `${firstExpose.name}`,
mockProperties: [{property: firstExpose.property, value: null}],
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
value_template: `{{ value_json.${firstExpose.property} }}`,
payload_on: firstExpose.value_on,
payload_off: firstExpose.value_off,
...(lookup[firstExpose.name] || {}),
},
};
// Let Home Assistant generate entity name when device_class is present
if (discoveryEntry.discovery_payload.device_class) delete discoveryEntry.discovery_payload.name;
discoveryEntries.push(discoveryEntry);
}
} else if (firstExpose.type === 'numeric') {
@@ -755,6 +778,7 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `${firstExpose.name}_${endpoint}` : `${firstExpose.name}`,
mockProperties: [{property: firstExpose.property, value: null}],
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
value_template: `{{ value_json.${firstExpose.property} }}`,
enabled_by_default: !allowsSet,
...(firstExpose.unit && {unit_of_measurement: firstExpose.unit}),
@@ -776,6 +800,9 @@ export default class HomeAssistant extends Extension {
delete discoveryEntry.discovery_payload.device_class;
}
// Let Home Assistant generate entity name when device_class is present
if (discoveryEntry.discovery_payload.device_class) delete discoveryEntry.discovery_payload.name;
discoveryEntries.push(discoveryEntry);
/**
@@ -789,6 +816,7 @@ export default class HomeAssistant extends Extension {
object_id: endpoint ? `${firstExpose.name}_${endpoint}` : `${firstExpose.name}`,
mockProperties: [{property: firstExpose.property, value: null}],
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
value_template: `{{ value_json.${firstExpose.property} }}`,
command_topic: true,
command_topic_prefix: endpoint,
@@ -805,6 +833,9 @@ export default class HomeAssistant extends Extension {
delete discoveryEntry.discovery_payload.device_class;
}
// Let Home Assistant generate entity name when device_class is present
if (discoveryEntry.discovery_payload.device_class) delete discoveryEntry.discovery_payload.name;
if (firstExpose.value_min != null) discoveryEntry.discovery_payload.min = firstExpose.value_min;
if (firstExpose.value_max != null) discoveryEntry.discovery_payload.max = firstExpose.value_max;
@@ -856,6 +887,7 @@ export default class HomeAssistant extends Extension {
object_id: firstExpose.property,
mockProperties: [{property: firstExpose.property, value: null}],
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
value_template: valueTemplate,
enabled_by_default: !(firstExpose.access & ACCESS_SET),
...lookup[firstExpose.name],
@@ -874,6 +906,7 @@ export default class HomeAssistant extends Extension {
object_id: firstExpose.property,
mockProperties: [], // Already mocked above in case access STATE is supported
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
value_template: valueTemplate,
state_topic: !!(firstExpose.access & ACCESS_STATE),
command_topic_prefix: endpoint,
@@ -899,6 +932,7 @@ export default class HomeAssistant extends Extension {
object_id: firstExpose.property,
mockProperties: [{property: firstExpose.property, value: null}],
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
value_template: `{{ value_json.${firstExpose.property} }}`,
enabled_by_default: !settableText,
...lookup[firstExpose.name],
@@ -912,6 +946,7 @@ export default class HomeAssistant extends Extension {
object_id: firstExpose.property,
mockProperties: [], // Already mocked above in case access STATE is supported
discovery_payload: {
name: endpoint ? `${firstExpose.label} ${endpoint}` : firstExpose.label,
state_topic: firstExpose.access & ACCESS_STATE,
value_template: `{{ value_json.${firstExpose.property} }}`,
command_topic_prefix: endpoint,
@@ -1087,6 +1122,7 @@ export default class HomeAssistant extends Extension {
object_id: 'last_seen',
mockProperties: [{property: 'last_seen', value: null}],
discovery_payload: {
name: 'Last seen',
value_template: '{{ value_json.last_seen }}',
icon: 'mdi:clock',
enabled_by_default: false,
@@ -1108,6 +1144,7 @@ export default class HomeAssistant extends Extension {
object_id: 'update_state',
mockProperties: [], // update is mocked below with updateSensor
discovery_payload: {
name: 'Update state',
icon: 'mdi:update',
value_template: `{{ value_json['update']['state'] }}`,
enabled_by_default: false,
@@ -1121,6 +1158,7 @@ export default class HomeAssistant extends Extension {
object_id: 'update_available',
mockProperties: [{property: 'update_available', value: null}],
discovery_payload: {
name: null,
payload_on: true,
payload_off: false,
value_template: `{{ value_json['update']['state'] == "available" }}`,
@@ -1135,6 +1173,7 @@ export default class HomeAssistant extends Extension {
object_id: 'update',
mockProperties: [{property: 'update', value: {state: null}}],
discovery_payload: {
name: null,
entity_picture: 'https://github.com/Koenkk/zigbee2mqtt/raw/master/images/logo.png',
latest_version_topic: true,
state_topic: true,
@@ -1223,16 +1262,12 @@ export default class HomeAssistant extends Extension {
const devicePayload = this.getDevicePayload(entity);
// Set (unique) name, separate by space if device name contains space.
if (!payload.device_class || ['timestamp'].includes(payload.device_class)) {
const nameSeparator = devicePayload.name.includes('_') ? '_' : ' ';
if (config.object_id.startsWith(config.type) && config.object_id.includes('_')) {
payload.name = `${config.object_id.split(/_(.+)/)[1]}`;
} else if (!config.object_id.startsWith(config.type)) {
payload.name = `${config.object_id.replace(/_/g, nameSeparator)}`;
} else {
payload.name = null;
}
// Suggest object_id (entity_id) for entity
payload.object_id = devicePayload.name.replace(/\s+/g, '_').toLowerCase();
if (config.object_id.startsWith(config.type) && config.object_id.includes('_')) {
payload.object_id += `_${config.object_id.split(/_(.+)/)[1]}`;
} else if (!config.object_id.startsWith(config.type)) {
payload.object_id += `_${config.object_id}`;
}
// Set unique_id
+2 -2
View File
@@ -98,12 +98,12 @@ declare global {
meta: {state: KeyValue, logger: Logger, device: zh.Device}) => Promise<KeyValue>,
}
interface DefinitionExposeFeature {name: string, endpoint?: string,
interface DefinitionExposeFeature {name: string, label: string, endpoint?: string,
property: string, value_max?: number, value_min?: number, unit?: string,
value_off?: string, value_on?: string, value_step?: number, values: string[], access: number}
interface DefinitionExpose {
type: string, name?: string, features?: DefinitionExposeFeature[],
type: string, name?: string, label?: string, features?: DefinitionExposeFeature[],
endpoint?: string, values?: string[], value_off?: string, value_on?: string, value_step?: number,
access: number, property: string, unit?: string,
value_min?: number, value_max?: number}