use device and area names in service call description (#13532)

This commit is contained in:
Bram Kragten 2022-08-31 17:30:44 +02:00 committed by GitHub
parent 93debac19a
commit d041bd9fd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 111 additions and 18 deletions

View File

@ -61,6 +61,7 @@ class HaDemo extends HomeAssistantAppEl {
area_id: null, area_id: null,
disabled_by: null, disabled_by: null,
entity_id: "sensor.co2_intensity", entity_id: "sensor.co2_intensity",
unique_id: "sensor.co2_intensity",
name: null, name: null,
icon: null, icon: null,
platform: "co2signal", platform: "co2signal",
@ -74,6 +75,7 @@ class HaDemo extends HomeAssistantAppEl {
area_id: null, area_id: null,
disabled_by: null, disabled_by: null,
entity_id: "sensor.grid_fossil_fuel_percentage", entity_id: "sensor.grid_fossil_fuel_percentage",
unique_id: "sensor.co2_intensity",
name: null, name: null,
icon: null, icon: null,
platform: "co2signal", platform: "co2signal",

View File

@ -191,6 +191,7 @@ const createEntityRegistryEntries = (
hidden_by: null, hidden_by: null,
entity_category: null, entity_category: null,
entity_id: "binary_sensor.updater", entity_id: "binary_sensor.updater",
unique_id: "binary_sensor.updater",
name: null, name: null,
icon: null, icon: null,
platform: "updater", platform: "updater",

View File

@ -2,6 +2,12 @@ import secondsToDuration from "../common/datetime/seconds_to_duration";
import { computeStateName } from "../common/entity/compute_state_name"; import { computeStateName } from "../common/entity/compute_state_name";
import type { HomeAssistant } from "../types"; import type { HomeAssistant } from "../types";
import { Condition, Trigger } from "./automation"; import { Condition, Trigger } from "./automation";
import {
DeviceCondition,
DeviceTrigger,
localizeDeviceAutomationCondition,
localizeDeviceAutomationTrigger,
} from "./device_automation";
import { formatAttributeName } from "./entity_attributes"; import { formatAttributeName } from "./entity_attributes";
export const describeTrigger = ( export const describeTrigger = (
@ -292,6 +298,19 @@ export const describeTrigger = (
if (trigger.platform === "webhook") { if (trigger.platform === "webhook") {
return "When a Webhook payload has been received"; return "When a Webhook payload has been received";
} }
if (trigger.platform === "device") {
const config = trigger as DeviceTrigger;
const localized = localizeDeviceAutomationTrigger(hass, config);
if (localized) {
return localized;
}
const stateObj = hass.states[config.entity_id as string];
return `${stateObj ? computeStateName(stateObj) : config.entity_id} ${
config.type
}`;
}
return `${trigger.platform || "Unknown"} trigger`; return `${trigger.platform || "Unknown"} trigger`;
}; };
@ -467,5 +486,17 @@ export const describeCondition = (
}`; }`;
} }
if (condition.condition === "device") {
const config = condition as DeviceCondition;
const localized = localizeDeviceAutomationCondition(hass, config);
if (localized) {
return localized;
}
const stateObj = hass.states[config.entity_id as string];
return `${stateObj ? computeStateName(stateObj) : config.entity_id} ${
config.type
}`;
}
return `${condition.condition} condition`; return `${condition.condition} condition`;
}; };

View File

@ -1,5 +1,6 @@
import { Connection, createCollection } from "home-assistant-js-websocket"; import { Connection, createCollection } from "home-assistant-js-websocket";
import { Store } from "home-assistant-js-websocket/dist/store"; import { Store } from "home-assistant-js-websocket/dist/store";
import memoizeOne from "memoize-one";
import { computeStateName } from "../common/entity/compute_state_name"; import { computeStateName } from "../common/entity/compute_state_name";
import { caseInsensitiveStringCompare } from "../common/string/compare"; import { caseInsensitiveStringCompare } from "../common/string/compare";
import { debounce } from "../common/util/debounce"; import { debounce } from "../common/util/debounce";
@ -7,6 +8,7 @@ import { HomeAssistant } from "../types";
export interface EntityRegistryEntry { export interface EntityRegistryEntry {
entity_id: string; entity_id: string;
unique_id: string;
name: string | null; name: string | null;
icon: string | null; icon: string | null;
platform: string; platform: string;
@ -21,7 +23,6 @@ export interface EntityRegistryEntry {
} }
export interface ExtEntityRegistryEntry extends EntityRegistryEntry { export interface ExtEntityRegistryEntry extends EntityRegistryEntry {
unique_id: string;
capabilities: Record<string, unknown>; capabilities: Record<string, unknown>;
original_icon?: string; original_icon?: string;
device_class?: string; device_class?: string;
@ -161,6 +162,16 @@ export const sortEntityRegistryByName = (entries: EntityRegistryEntry[]) =>
caseInsensitiveStringCompare(entry1.name || "", entry2.name || "") caseInsensitiveStringCompare(entry1.name || "", entry2.name || "")
); );
export const entityRegistryByUniqueId = memoizeOne(
(entries: HomeAssistant["entities"]) => {
const entities: HomeAssistant["entities"] = {};
for (const entity of Object.values(entries)) {
entities[entity.unique_id] = entity;
}
return entities;
}
);
export const getEntityPlatformLookup = ( export const getEntityPlatformLookup = (
entities: EntityRegistryEntry[] entities: EntityRegistryEntry[]
): Record<string, string> => { ): Record<string, string> => {

View File

@ -5,6 +5,13 @@ import { isTemplate } from "../common/string/has-template";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
import { Condition } from "./automation"; import { Condition } from "./automation";
import { describeCondition, describeTrigger } from "./automation_i18n"; import { describeCondition, describeTrigger } from "./automation_i18n";
import { localizeDeviceAutomationAction } from "./device_automation";
import { computeDeviceName } from "./device_registry";
import {
computeEntityRegistryName,
entityRegistryByUniqueId,
} from "./entity_registry";
import { domainToName } from "./integration";
import { import {
ActionType, ActionType,
ActionTypes, ActionTypes,
@ -47,7 +54,11 @@ export const describeAction = <T extends ActionType>(
) { ) {
base = "Call a service based on a template"; base = "Call a service based on a template";
} else if (config.service) { } else if (config.service) {
base = `Call service ${config.service}`; const [domain, serviceName] = config.service.split(".", 2);
const service = hass.services[domain][serviceName];
base = service
? `${domainToName(hass.localize, domain)}: ${service.name}`
: `Call service: ${config.service}`;
} else { } else {
return actionType; return actionType;
} }
@ -66,26 +77,51 @@ export const describeAction = <T extends ActionType>(
? config.target[key] ? config.target[key]
: [config.target[key]]; : [config.target[key]];
const values: string[] = [];
let renderValues = true;
for (const targetThing of keyConf) { for (const targetThing of keyConf) {
if (isTemplate(targetThing)) { if (isTemplate(targetThing)) {
targets.push(`templated ${label}`); targets.push(`templated ${label}`);
renderValues = false;
break; break;
} else if (key === "entity_id") {
if (targetThing.includes(".")) {
const state = hass.states[targetThing];
if (state) {
targets.push(computeStateName(state));
} else {
targets.push(targetThing);
}
} else {
const entityReg = entityRegistryByUniqueId(hass.entities)[
targetThing
];
if (entityReg) {
targets.push(
computeEntityRegistryName(hass, entityReg) || targetThing
);
} else {
targets.push(targetThing);
}
}
} else if (key === "device_id") {
const device = hass.devices[targetThing];
if (device) {
targets.push(computeDeviceName(device, hass));
} else {
targets.push(targetThing);
}
} else if (key === "area_id") {
const area = hass.areas[targetThing];
if (area?.name) {
targets.push(area.name);
} else {
targets.push(targetThing);
}
} else { } else {
values.push(targetThing); targets.push(targetThing);
} }
} }
if (renderValues) {
targets.push(`${label} ${values.join(", ")}`);
}
} }
if (targets.length > 0) { if (targets.length > 0) {
base += ` on ${targets.join(", ")}`; base += ` ${targets.join(", ")}`;
} }
} }
@ -175,11 +211,15 @@ export const describeAction = <T extends ActionType>(
if (actionType === "if") { if (actionType === "if") {
const config = action as IfAction; const config = action as IfAction;
return `Perform an action if: ${ return `Perform an action if: ${
typeof config.if === "string" !config.if
? ""
: typeof config.if === "string"
? config.if ? config.if
: ensureArray(config.if).length > 1 : ensureArray(config.if).length > 1
? `${ensureArray(config.if).length} conditions` ? `${ensureArray(config.if).length} conditions`
: describeCondition(ensureArray(config.if)[0], hass) : ensureArray(config.if).length
? describeCondition(ensureArray(config.if)[0], hass)
: ""
}${config.else ? " (or else!)" : ""}`; }${config.else ? " (or else!)" : ""}`;
} }
@ -219,6 +259,10 @@ export const describeAction = <T extends ActionType>(
if (actionType === "device_action") { if (actionType === "device_action") {
const config = action as DeviceAction; const config = action as DeviceAction;
const localized = localizeDeviceAutomationAction(hass, config);
if (localized) {
return localized;
}
const stateObj = hass.states[config.entity_id as string]; const stateObj = hass.states[config.entity_id as string];
return `${config.type || "Perform action with"} ${ return `${config.type || "Perform action with"} ${
stateObj ? computeStateName(stateObj) : config.entity_id stateObj ? computeStateName(stateObj) : config.entity_id

View File

@ -68,9 +68,10 @@ import type { HomeAssistant, Route } from "../../../types";
import { configSections } from "../ha-panel-config"; import { configSections } from "../ha-panel-config";
import "../integrations/ha-integration-overflow-menu"; import "../integrations/ha-integration-overflow-menu";
export interface StateEntity extends EntityRegistryEntry { export interface StateEntity extends Omit<EntityRegistryEntry, "unique_id"> {
readonly?: boolean; readonly?: boolean;
selectable?: boolean; selectable?: boolean;
unique_id?: string;
} }
export interface EntityRow extends StateEntity { export interface EntityRow extends StateEntity {
@ -302,7 +303,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
private _filteredEntitiesAndDomains = memoize( private _filteredEntitiesAndDomains = memoize(
( (
entities: EntityRegistryEntry[], entities: StateEntity[],
devices: DeviceRegistryEntry[] | undefined, devices: DeviceRegistryEntry[] | undefined,
areas: AreaRegistryEntry[] | undefined, areas: AreaRegistryEntry[] | undefined,
stateEntities: StateEntity[], stateEntities: StateEntity[],
@ -392,7 +393,10 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
result.push({ result.push({
...entry, ...entry,
entity, entity,
name: computeEntityRegistryName(this.hass!, entry), name: computeEntityRegistryName(
this.hass!,
entry as EntityRegistryEntry
),
unavailable, unavailable,
restored, restored,
area: area ? area.name : "—", area: area ? area.name : "—",