mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-10-23 14:22:38 +00:00
feat: Use labels in Home Assistant entity naming (#18678)
* feat: Use labels in Home Assistant entity naming * tweak comment
This commit is contained in:
1 parent
71c4211d13
commit
e33e335c0c
3 files changed
+88
-17
No files matched your search
@@ -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
|
||||
|
||||
Vendored
+2
-2
@@ -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}
|
||||
|
||||
Reference in new issue
Block a user