Files
frontend/src/common/entity/compute_attribute_display.ts
2023-12-08 10:14:55 +01:00

174 lines
5.5 KiB
TypeScript

import { HassConfig, HassEntity } from "home-assistant-js-websocket";
import {
DOMAIN_ATTRIBUTES_FORMATERS,
DOMAIN_ATTRIBUTES_UNITS,
TEMPERATURE_ATTRIBUTES,
} from "../../data/entity_attributes";
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
import { FrontendLocaleData } from "../../data/translation";
import { WeatherEntity, getWeatherUnit } from "../../data/weather";
import { HomeAssistant } from "../../types";
import checkValidDate from "../datetime/check_valid_date";
import { formatDate } from "../datetime/format_date";
import { formatDateTimeWithSeconds } from "../datetime/format_date_time";
import { formatNumber } from "../number/format_number";
import { capitalizeFirstLetter } from "../string/capitalize-first-letter";
import { isDate } from "../string/is_date";
import { isTimestamp } from "../string/is_timestamp";
import { blankBeforeUnit } from "../translations/blank_before_unit";
import { LocalizeFunc } from "../translations/localize";
import { computeDomain } from "./compute_domain";
import { computeStateDomain } from "./compute_state_domain";
export const computeAttributeValueDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
config: HassConfig,
entities: HomeAssistant["entities"],
attribute: string,
value?: any
): string => {
const attributeValue =
value !== undefined ? value : stateObj.attributes[attribute];
// Null value, the state is unknown
if (attributeValue === null) {
return localize("state.default.unknown");
}
// Number value, return formatted number
if (typeof attributeValue === "number") {
const domain = computeStateDomain(stateObj);
const formatter = DOMAIN_ATTRIBUTES_FORMATERS[domain]?.[attribute];
const formattedValue = formatter
? formatter(attributeValue, locale)
: formatNumber(attributeValue, locale);
let unit = DOMAIN_ATTRIBUTES_UNITS[domain]?.[attribute] as
| string
| undefined;
if (domain === "weather") {
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
}
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
unit = config.unit_system.temperature;
}
if (unit) {
return `${formattedValue}${blankBeforeUnit(unit, locale)}${unit}`;
}
return formattedValue;
}
// Special handling in case this is a string with an known format
if (typeof attributeValue === "string") {
// Date handling
if (isDate(attributeValue, true)) {
// Timestamp handling
if (isTimestamp(attributeValue)) {
const date = new Date(attributeValue);
if (checkValidDate(date)) {
return formatDateTimeWithSeconds(date, locale, config);
}
}
// Value was not a timestamp, so only do date formatting
const date = new Date(attributeValue);
if (checkValidDate(date)) {
return formatDate(date, locale, config);
}
}
}
// Values are objects, render object
if (
(Array.isArray(attributeValue) &&
attributeValue.some((val) => val instanceof Object)) ||
(!Array.isArray(attributeValue) && attributeValue instanceof Object)
) {
return JSON.stringify(attributeValue);
}
// If this is an array, try to determine the display value for each item
if (Array.isArray(attributeValue)) {
return attributeValue
.map((item) =>
computeAttributeValueDisplay(
localize,
stateObj,
locale,
config,
entities,
attribute,
item
)
)
.join(", ");
}
// We've explored all known value handling, so now we'll try to find a
// translation for the value.
const entityId = stateObj.entity_id;
const domain = computeDomain(entityId);
const deviceClass = stateObj.attributes.device_class;
const registryEntry = entities[entityId] as
| EntityRegistryDisplayEntry
| undefined;
const translationKey = registryEntry?.translation_key;
return (
(translationKey &&
localize(
`component.${registryEntry.platform}.entity.${domain}.${translationKey}.state_attributes.${attribute}.state.${attributeValue}`
)) ||
(deviceClass &&
localize(
`component.${domain}.entity_component.${deviceClass}.state_attributes.${attribute}.state.${attributeValue}`
)) ||
localize(
`component.${domain}.entity_component._.state_attributes.${attribute}.state.${attributeValue}`
) ||
attributeValue
);
};
export const computeAttributeNameDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
entities: HomeAssistant["entities"],
attribute: string
): string => {
const entityId = stateObj.entity_id;
const deviceClass = stateObj.attributes.device_class;
const domain = computeDomain(entityId);
const entity = entities[entityId] as EntityRegistryDisplayEntry | undefined;
const translationKey = entity?.translation_key;
return (
(translationKey &&
localize(
`component.${entity.platform}.entity.${domain}.${translationKey}.state_attributes.${attribute}.name`
)) ||
(deviceClass &&
localize(
`component.${domain}.entity_component.${deviceClass}.state_attributes.${attribute}.name`
)) ||
localize(
`component.${domain}.entity_component._.state_attributes.${attribute}.name`
) ||
capitalizeFirstLetter(
attribute
.replace(/_/g, " ")
.replace(/\bid\b/g, "ID")
.replace(/\bip\b/g, "IP")
.replace(/\bmac\b/g, "MAC")
.replace(/\bgps\b/g, "GPS")
)
);
};