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

View File

@ -191,6 +191,7 @@ const createEntityRegistryEntries = (
hidden_by: null,
entity_category: null,
entity_id: "binary_sensor.updater",
unique_id: "binary_sensor.updater",
name: null,
icon: null,
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 type { HomeAssistant } from "../types";
import { Condition, Trigger } from "./automation";
import {
DeviceCondition,
DeviceTrigger,
localizeDeviceAutomationCondition,
localizeDeviceAutomationTrigger,
} from "./device_automation";
import { formatAttributeName } from "./entity_attributes";
export const describeTrigger = (
@ -292,6 +298,19 @@ export const describeTrigger = (
if (trigger.platform === "webhook") {
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`;
};
@ -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`;
};

View File

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

View File

@ -5,6 +5,13 @@ import { isTemplate } from "../common/string/has-template";
import { HomeAssistant } from "../types";
import { Condition } from "./automation";
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 {
ActionType,
ActionTypes,
@ -47,7 +54,11 @@ export const describeAction = <T extends ActionType>(
) {
base = "Call a service based on a template";
} 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 {
return actionType;
}
@ -66,26 +77,51 @@ export const describeAction = <T extends ActionType>(
? config.target[key]
: [config.target[key]];
const values: string[] = [];
let renderValues = true;
for (const targetThing of keyConf) {
if (isTemplate(targetThing)) {
targets.push(`templated ${label}`);
renderValues = false;
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 {
values.push(targetThing);
targets.push(targetThing);
}
}
if (renderValues) {
targets.push(`${label} ${values.join(", ")}`);
}
}
if (targets.length > 0) {
base += ` on ${targets.join(", ")}`;
base += ` ${targets.join(", ")}`;
}
}
@ -175,11 +211,15 @@ export const describeAction = <T extends ActionType>(
if (actionType === "if") {
const config = action as IfAction;
return `Perform an action if: ${
typeof config.if === "string"
!config.if
? ""
: typeof config.if === "string"
? config.if
: ensureArray(config.if).length > 1
? `${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!)" : ""}`;
}
@ -219,6 +259,10 @@ export const describeAction = <T extends ActionType>(
if (actionType === "device_action") {
const config = action as DeviceAction;
const localized = localizeDeviceAutomationAction(hass, config);
if (localized) {
return localized;
}
const stateObj = hass.states[config.entity_id as string];
return `${config.type || "Perform action with"} ${
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 "../integrations/ha-integration-overflow-menu";
export interface StateEntity extends EntityRegistryEntry {
export interface StateEntity extends Omit<EntityRegistryEntry, "unique_id"> {
readonly?: boolean;
selectable?: boolean;
unique_id?: string;
}
export interface EntityRow extends StateEntity {
@ -302,7 +303,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
private _filteredEntitiesAndDomains = memoize(
(
entities: EntityRegistryEntry[],
entities: StateEntity[],
devices: DeviceRegistryEntry[] | undefined,
areas: AreaRegistryEntry[] | undefined,
stateEntities: StateEntity[],
@ -392,7 +393,10 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
result.push({
...entry,
entity,
name: computeEntityRegistryName(this.hass!, entry),
name: computeEntityRegistryName(
this.hass!,
entry as EntityRegistryEntry
),
unavailable,
restored,
area: area ? area.name : "—",