mirror of
https://github.com/home-assistant/frontend.git
synced 2025-10-18 08:09:44 +00:00
174 lines
5.5 KiB
TypeScript
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")
|
|
)
|
|
);
|
|
};
|