mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add unit when formatting attribute for display (#17607)
This commit is contained in:
parent
bbb99a6eee
commit
6e27fbe10f
@ -1,6 +1,11 @@
|
||||
import { HassConfig, HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
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";
|
||||
@ -9,8 +14,10 @@ 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 { blankBeforePercent } from "../translations/blank_before_percent";
|
||||
import { LocalizeFunc } from "../translations/localize";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
import { computeStateDomain } from "./compute_state_domain";
|
||||
|
||||
export const computeAttributeValueDisplay = (
|
||||
localize: LocalizeFunc,
|
||||
@ -31,7 +38,40 @@ export const computeAttributeValueDisplay = (
|
||||
|
||||
// Number value, return formatted number
|
||||
if (typeof attributeValue === "number") {
|
||||
return formatNumber(attributeValue, locale);
|
||||
const formattedValue = formatNumber(attributeValue, locale);
|
||||
|
||||
const domain = computeStateDomain(stateObj);
|
||||
|
||||
let unit = DOMAIN_ATTRIBUTES_UNITS[domain]?.[attribute] as
|
||||
| string
|
||||
| undefined;
|
||||
|
||||
if (domain === "light" && attribute === "brightness") {
|
||||
const percentage = Math.round((attributeValue / 255) * 100);
|
||||
return `${percentage}${blankBeforePercent(locale)}%`;
|
||||
}
|
||||
|
||||
if (domain === "weather") {
|
||||
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
|
||||
}
|
||||
|
||||
if (unit === "%") {
|
||||
return `${formattedValue}${blankBeforePercent(locale)}${unit}`;
|
||||
}
|
||||
|
||||
if (unit === "°") {
|
||||
return `${formattedValue}${unit}`;
|
||||
}
|
||||
|
||||
if (unit) {
|
||||
return `${formattedValue} ${unit}`;
|
||||
}
|
||||
|
||||
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
|
||||
return `${formattedValue} ${config.unit_system.temperature}`;
|
||||
}
|
||||
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
// Special handling in case this is a string with an known format
|
||||
|
@ -3,6 +3,7 @@ import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { until } from "lit/directives/until";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { formatNumber } from "../common/number/format_number";
|
||||
|
||||
let jsYamlPromise: Promise<typeof import("../resources/js-yaml-dump")>;
|
||||
|
||||
@ -14,11 +15,19 @@ class HaAttributeValue extends LitElement {
|
||||
|
||||
@property() public attribute!: string;
|
||||
|
||||
@property({ type: Boolean, attribute: "hide-unit" })
|
||||
public hideUnit?: boolean;
|
||||
|
||||
protected render() {
|
||||
if (!this.stateObj) {
|
||||
return nothing;
|
||||
}
|
||||
const attributeValue = this.stateObj.attributes[this.attribute];
|
||||
|
||||
if (typeof attributeValue === "number" && this.hideUnit) {
|
||||
return formatNumber(attributeValue, this.hass.locale);
|
||||
}
|
||||
|
||||
if (typeof attributeValue === "string") {
|
||||
// URL handling
|
||||
if (attributeValue.startsWith("http")) {
|
||||
|
@ -2,9 +2,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { computeAttributeValueDisplay } from "../common/entity/compute_attribute_display";
|
||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||
import { formatNumber } from "../common/number/format_number";
|
||||
import { blankBeforePercent } from "../common/translations/blank_before_percent";
|
||||
import { ClimateEntity, CLIMATE_PRESET_NONE } from "../data/climate";
|
||||
import { CLIMATE_PRESET_NONE, ClimateEntity } from "../data/climate";
|
||||
import { isUnavailableState } from "../data/entity";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
@ -54,28 +52,28 @@ class HaClimateState extends LitElement {
|
||||
this.stateObj.attributes.current_temperature != null &&
|
||||
this.stateObj.attributes.current_humidity != null
|
||||
) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.current_temperature,
|
||||
this.hass.locale
|
||||
)} ${this.hass.config.unit_system.temperature}/
|
||||
${formatNumber(
|
||||
this.stateObj.attributes.current_humidity,
|
||||
this.hass.locale
|
||||
)}${blankBeforePercent(this.hass.locale)}%`;
|
||||
return `${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_temperature"
|
||||
)}/
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_humidity"
|
||||
)}`;
|
||||
}
|
||||
|
||||
if (this.stateObj.attributes.current_temperature != null) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.current_temperature,
|
||||
this.hass.locale
|
||||
)} ${this.hass.config.unit_system.temperature}`;
|
||||
return this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_temperature"
|
||||
);
|
||||
}
|
||||
|
||||
if (this.stateObj.attributes.current_humidity != null) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.current_humidity,
|
||||
this.hass.locale
|
||||
)}${blankBeforePercent(this.hass.locale)}%`;
|
||||
return this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_humidity"
|
||||
);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -90,39 +88,33 @@ class HaClimateState extends LitElement {
|
||||
this.stateObj.attributes.target_temp_low != null &&
|
||||
this.stateObj.attributes.target_temp_high != null
|
||||
) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.target_temp_low,
|
||||
this.hass.locale
|
||||
)}-${formatNumber(
|
||||
this.stateObj.attributes.target_temp_high,
|
||||
this.hass.locale
|
||||
)} ${this.hass.config.unit_system.temperature}`;
|
||||
return `${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"target_temp_low"
|
||||
)}-${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"target_temp_high"
|
||||
)}`;
|
||||
}
|
||||
|
||||
if (this.stateObj.attributes.temperature != null) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.temperature,
|
||||
this.hass.locale
|
||||
)} ${this.hass.config.unit_system.temperature}`;
|
||||
return this.hass.formatEntityAttributeValue(this.stateObj, "temperature");
|
||||
}
|
||||
if (
|
||||
this.stateObj.attributes.target_humidity_low != null &&
|
||||
this.stateObj.attributes.target_humidity_high != null
|
||||
) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.target_humidity_low,
|
||||
this.hass.locale
|
||||
)}-${formatNumber(
|
||||
this.stateObj.attributes.target_humidity_high,
|
||||
this.hass.locale
|
||||
)} %`;
|
||||
return `${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"target_humidity_low"
|
||||
)}-${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"target_humidity_high"
|
||||
)}`;
|
||||
}
|
||||
|
||||
if (this.stateObj.attributes.humidity != null) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.humidity,
|
||||
this.hass.locale
|
||||
)} %`;
|
||||
return this.hass.formatEntityAttributeValue(this.stateObj, "humidity");
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -2,8 +2,6 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { computeAttributeValueDisplay } from "../common/entity/compute_attribute_display";
|
||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||
import { formatNumber } from "../common/number/format_number";
|
||||
import { blankBeforePercent } from "../common/translations/blank_before_percent";
|
||||
import { isUnavailableState, OFF } from "../data/entity";
|
||||
import { HumidifierEntity } from "../data/humidifier";
|
||||
import type { HomeAssistant } from "../types";
|
||||
@ -51,10 +49,10 @@ class HaHumidifierState extends LitElement {
|
||||
}
|
||||
|
||||
if (this.stateObj.attributes.current_humidity != null) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.current_humidity,
|
||||
this.hass.locale
|
||||
)}${blankBeforePercent(this.hass.locale)}%`;
|
||||
return `${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_humidity"
|
||||
)}`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -66,10 +64,10 @@ class HaHumidifierState extends LitElement {
|
||||
}
|
||||
|
||||
if (this.stateObj.attributes.humidity != null) {
|
||||
return `${formatNumber(
|
||||
this.stateObj.attributes.humidity,
|
||||
this.hass.locale
|
||||
)}${blankBeforePercent(this.hass.locale)}%`;
|
||||
return `${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"humidity"
|
||||
)}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -4,9 +4,8 @@ import {
|
||||
} from "home-assistant-js-websocket";
|
||||
import { stateActive } from "../common/entity/state_active";
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
import { blankBeforePercent } from "../common/translations/blank_before_percent";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { UNAVAILABLE } from "./entity";
|
||||
import { FrontendLocaleData } from "./translation";
|
||||
|
||||
export const enum CoverEntityFeature {
|
||||
OPEN = 1,
|
||||
@ -112,7 +111,7 @@ export interface CoverEntity extends HassEntityBase {
|
||||
|
||||
export function computeCoverPositionStateDisplay(
|
||||
stateObj: CoverEntity,
|
||||
locale: FrontendLocaleData,
|
||||
hass: HomeAssistant,
|
||||
position?: number
|
||||
) {
|
||||
const statePosition = stateActive(stateObj)
|
||||
@ -123,6 +122,11 @@ export function computeCoverPositionStateDisplay(
|
||||
const currentPosition = position ?? statePosition;
|
||||
|
||||
return currentPosition && currentPosition !== 100
|
||||
? `${Math.round(currentPosition)}${blankBeforePercent(locale)}%`
|
||||
? hass.formatEntityAttributeValue(
|
||||
stateObj,
|
||||
// Always use position as it's the same formatting as tilt position
|
||||
"current_position",
|
||||
Math.round(currentPosition)
|
||||
)
|
||||
: "";
|
||||
}
|
||||
|
@ -21,3 +21,53 @@ export const STATE_ATTRIBUTES = [
|
||||
"supported_features",
|
||||
"unit_of_measurement",
|
||||
];
|
||||
|
||||
export const TEMPERATURE_ATTRIBUTES = new Set([
|
||||
"temperature",
|
||||
"current_temperature",
|
||||
"target_temperature",
|
||||
"target_temp_temp",
|
||||
"target_temp_high",
|
||||
"target_temp_step",
|
||||
"min_temp",
|
||||
"max_temp",
|
||||
]);
|
||||
|
||||
export const DOMAIN_ATTRIBUTES_UNITS: Record<string, Record<string, string>> = {
|
||||
climate: {
|
||||
humidity: "%",
|
||||
current_humidity: "%",
|
||||
target_humidity_low: "%",
|
||||
target_humidity_high: "%",
|
||||
target_humidity_step: "%",
|
||||
min_humidity: "%",
|
||||
max_humidity: "%",
|
||||
},
|
||||
cover: {
|
||||
current_position: "%",
|
||||
current_tilt_position: "%",
|
||||
},
|
||||
fan: {
|
||||
percentage: "%",
|
||||
},
|
||||
humidifier: {
|
||||
humidity: "%",
|
||||
current_humidity: "%",
|
||||
min_humidity: "%",
|
||||
max_humidity: "%",
|
||||
},
|
||||
light: {
|
||||
color_temp: "mired",
|
||||
max_mireds: "mired",
|
||||
min_mireds: "mired",
|
||||
color_temp_kelvin: "K",
|
||||
min_color_temp_kelvin: "K",
|
||||
max_color_temp_kelvin: "K",
|
||||
},
|
||||
sun: {
|
||||
elevation: "°",
|
||||
},
|
||||
vaccum: {
|
||||
battery_level: "%",
|
||||
},
|
||||
};
|
||||
|
@ -10,8 +10,7 @@ import {
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { stateActive } from "../common/entity/state_active";
|
||||
import { blankBeforePercent } from "../common/translations/blank_before_percent";
|
||||
import { FrontendLocaleData } from "./translation";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
export const enum FanEntityFeature {
|
||||
SET_SPEED = 1,
|
||||
@ -97,7 +96,7 @@ export const FAN_SPEED_COUNT_MAX_FOR_BUTTONS = 4;
|
||||
|
||||
export function computeFanSpeedStateDisplay(
|
||||
stateObj: FanEntity,
|
||||
locale: FrontendLocaleData,
|
||||
hass: HomeAssistant,
|
||||
speed?: number
|
||||
) {
|
||||
const percentage = stateActive(stateObj)
|
||||
@ -106,6 +105,10 @@ export function computeFanSpeedStateDisplay(
|
||||
const currentSpeed = speed ?? percentage;
|
||||
|
||||
return currentSpeed
|
||||
? `${Math.floor(currentSpeed)}${blankBeforePercent(locale)}%`
|
||||
? hass.formatEntityAttributeValue(
|
||||
stateObj,
|
||||
"percentage",
|
||||
Math.round(currentSpeed)
|
||||
)
|
||||
: "";
|
||||
}
|
||||
|
@ -19,13 +19,14 @@ import {
|
||||
mdiWeatherWindyVariant,
|
||||
} from "@mdi/js";
|
||||
import {
|
||||
HassConfig,
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { css, html, svg, SVGTemplateResult, TemplateResult } from "lit";
|
||||
import { SVGTemplateResult, TemplateResult, css, html, svg } from "lit";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
import { formatNumber } from "../common/number/format_number";
|
||||
import { round } from "../common/number/round";
|
||||
import "../components/ha-svg-icon";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
@ -187,11 +188,7 @@ export const getWind = (
|
||||
): string => {
|
||||
const speedText =
|
||||
speed !== undefined && speed !== null
|
||||
? `${formatNumber(speed, hass.locale)} ${getWeatherUnit(
|
||||
hass!,
|
||||
stateObj,
|
||||
"wind_speed"
|
||||
)}`
|
||||
? hass.formatEntityAttributeValue(stateObj, "wind_speed", speed)
|
||||
: "-";
|
||||
if (bearing !== undefined && bearing !== null) {
|
||||
const cardinalDirection = getWindBearing(bearing);
|
||||
@ -205,11 +202,11 @@ export const getWind = (
|
||||
};
|
||||
|
||||
export const getWeatherUnit = (
|
||||
hass: HomeAssistant,
|
||||
config: HassConfig,
|
||||
stateObj: WeatherEntity,
|
||||
measure: string
|
||||
): string => {
|
||||
const lengthUnit = hass.config.unit_system.length || "";
|
||||
const lengthUnit = config.unit_system.length || "";
|
||||
switch (measure) {
|
||||
case "visibility":
|
||||
return stateObj.attributes.visibility_unit || lengthUnit;
|
||||
@ -224,9 +221,9 @@ export const getWeatherUnit = (
|
||||
(lengthUnit === "km" ? "hPa" : "inHg")
|
||||
);
|
||||
case "temperature":
|
||||
case "templow":
|
||||
return (
|
||||
stateObj.attributes.temperature_unit ||
|
||||
hass.config.unit_system.temperature
|
||||
stateObj.attributes.temperature_unit || config.unit_system.temperature
|
||||
);
|
||||
case "wind_speed":
|
||||
return stateObj.attributes.wind_speed_unit || `${lengthUnit}/h`;
|
||||
@ -234,7 +231,7 @@ export const getWeatherUnit = (
|
||||
case "precipitation_probability":
|
||||
return "%";
|
||||
default:
|
||||
return hass.config.unit_system[measure] || "";
|
||||
return config.unit_system[measure] || "";
|
||||
}
|
||||
};
|
||||
|
||||
@ -268,14 +265,15 @@ export const getSecondaryWeatherAttribute = (
|
||||
|
||||
const weatherAttrIcon = weatherAttrIcons[attribute];
|
||||
|
||||
const roundedValue = round(value, 1);
|
||||
|
||||
return html`
|
||||
${weatherAttrIcon
|
||||
? html`
|
||||
<ha-svg-icon class="attr-icon" .path=${weatherAttrIcon}></ha-svg-icon>
|
||||
`
|
||||
: hass!.localize(`ui.card.weather.attributes.${attribute}`)}
|
||||
${formatNumber(value, hass.locale, { maximumFractionDigits: 1 })}
|
||||
${getWeatherUnit(hass!, stateObj, attribute)}
|
||||
${hass.formatEntityAttributeValue(stateObj, attribute, roundedValue)}
|
||||
`;
|
||||
};
|
||||
|
||||
@ -311,12 +309,14 @@ const getWeatherExtrema = (
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const unit = getWeatherUnit(hass!, stateObj, "temperature");
|
||||
|
||||
return html`
|
||||
${tempHigh ? `${formatNumber(tempHigh, hass.locale)} ${unit}` : ""}
|
||||
${tempHigh
|
||||
? hass.formatEntityAttributeValue(stateObj, "temperature", tempHigh)
|
||||
: ""}
|
||||
${tempLow && tempHigh ? " / " : ""}
|
||||
${tempLow ? `${formatNumber(tempLow, hass.locale)} ${unit}` : ""}
|
||||
${tempLow
|
||||
? hass.formatEntityAttributeValue(stateObj, "temperature", tempLow)
|
||||
: ""}
|
||||
`;
|
||||
};
|
||||
|
||||
|
@ -6,8 +6,6 @@ import { stateActive } from "../../../../common/entity/state_active";
|
||||
import { domainStateColorProperties } from "../../../../common/entity/state_color";
|
||||
import { supportsFeature } from "../../../../common/entity/supports-feature";
|
||||
import { clamp } from "../../../../common/number/clamp";
|
||||
import { formatNumber } from "../../../../common/number/format_number";
|
||||
import { blankBeforePercent } from "../../../../common/translations/blank_before_percent";
|
||||
import { debounce } from "../../../../common/util/debounce";
|
||||
import "../../../../components/ha-control-circular-slider";
|
||||
import "../../../../components/ha-outlined-icon-button";
|
||||
@ -116,18 +114,19 @@ export class HaMoreInfoClimateHumidity extends LitElement {
|
||||
}
|
||||
|
||||
private _renderTarget(humidity: number) {
|
||||
const formatted = formatNumber(humidity, this.hass.locale, {
|
||||
maximumFractionDigits: 0,
|
||||
});
|
||||
const rounded = Math.round(humidity);
|
||||
const formatted = this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"humidity",
|
||||
rounded
|
||||
);
|
||||
|
||||
return html`
|
||||
<div class="target">
|
||||
<p class="value" aria-hidden="true">
|
||||
${formatted}<span class="unit">%</span>
|
||||
</p>
|
||||
<p class="visually-hidden">
|
||||
${formatted}${blankBeforePercent(this.hass.locale)}%
|
||||
${rounded}<span class="unit">%</span>
|
||||
</p>
|
||||
<p class="visually-hidden">${formatted}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ import { property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-icon-button-group";
|
||||
import "../../../components/ha-icon-button-toggle";
|
||||
@ -92,8 +90,10 @@ class MoreInfoClimate extends LitElement {
|
||||
)}
|
||||
</p>
|
||||
<p class="value">
|
||||
${formatNumber(currentTemperature, this.hass.locale)}
|
||||
${this.hass.config.unit_system.temperature}
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_temperature"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
@ -108,10 +108,10 @@ class MoreInfoClimate extends LitElement {
|
||||
)}
|
||||
</p>
|
||||
<p class="value">
|
||||
${formatNumber(
|
||||
currentHumidity,
|
||||
this.hass.locale
|
||||
)}${blankBeforePercent(this.hass.locale)}%
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_humidity"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
|
@ -94,7 +94,7 @@ class MoreInfoCover extends LitElement {
|
||||
|
||||
const positionStateDisplay = computeCoverPositionStateDisplay(
|
||||
this.stateObj!,
|
||||
this.hass.locale,
|
||||
this.hass,
|
||||
liveValue
|
||||
);
|
||||
|
||||
|
@ -112,7 +112,7 @@ class MoreInfoFan extends LitElement {
|
||||
|
||||
const positionStateDisplay = computeFanSpeedStateDisplay(
|
||||
this.stateObj!,
|
||||
this.hass.locale,
|
||||
this.hass,
|
||||
liveValue
|
||||
);
|
||||
|
||||
|
@ -16,8 +16,6 @@ import {
|
||||
} from "../../../common/entity/compute_attribute_display";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-list-item";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
@ -59,7 +57,7 @@ class MoreInfoHumidifier extends LitElement {
|
||||
HumidifierEntityFeature.MODES
|
||||
);
|
||||
|
||||
const currentHumidity = this.stateObj.attributes.current_humidity;
|
||||
const currentHumidity = this.stateObj.attributes.current_humidity as number;
|
||||
|
||||
return html`
|
||||
<div class="current">
|
||||
@ -75,10 +73,11 @@ class MoreInfoHumidifier extends LitElement {
|
||||
)}
|
||||
</p>
|
||||
<p class="value">
|
||||
${formatNumber(
|
||||
currentHumidity,
|
||||
this.hass.locale
|
||||
)}${blankBeforePercent(this.hass.locale)}%
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_humidity",
|
||||
currentHumidity
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
|
@ -18,7 +18,6 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||
import "../../../components/ha-attributes";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-icon-button-group";
|
||||
@ -31,7 +30,6 @@ import {
|
||||
LightColorMode,
|
||||
LightEntity,
|
||||
LightEntityFeature,
|
||||
formatTempColor,
|
||||
lightSupportsBrightness,
|
||||
lightSupportsColor,
|
||||
lightSupportsColorMode,
|
||||
@ -70,7 +68,7 @@ class MoreInfoLight extends LitElement {
|
||||
private _brightnessChanged(ev) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
this._selectedBrightness = value;
|
||||
this._selectedBrightness = (value * 255) / 100;
|
||||
}
|
||||
|
||||
private _tempColorHovered(ev: CustomEvent<HASSDomEvents["color-hovered"]>) {
|
||||
@ -83,9 +81,7 @@ class MoreInfoLight extends LitElement {
|
||||
|
||||
protected updated(changedProps: PropertyValues<typeof this>): void {
|
||||
if (changedProps.has("stateObj")) {
|
||||
this._selectedBrightness = this.stateObj?.attributes.brightness
|
||||
? Math.round((this.stateObj.attributes.brightness * 100) / 255)
|
||||
: undefined;
|
||||
this._selectedBrightness = this.stateObj?.attributes.brightness;
|
||||
this._effect = this.stateObj?.attributes.effect;
|
||||
}
|
||||
}
|
||||
@ -102,12 +98,18 @@ class MoreInfoLight extends LitElement {
|
||||
|
||||
private get _stateOverride() {
|
||||
if (this._colorTempPreview) {
|
||||
return formatTempColor(this._colorTempPreview);
|
||||
return this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"color_temp_kelvin",
|
||||
this._colorTempPreview
|
||||
);
|
||||
}
|
||||
if (this._selectedBrightness) {
|
||||
return `${Math.round(this._selectedBrightness)}${blankBeforePercent(
|
||||
this.hass!.locale
|
||||
)}%`;
|
||||
return this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"brightness",
|
||||
this._selectedBrightness
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { formatTime } from "../../../common/datetime/format_time";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import "../../../components/ha-relative-time";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
@ -56,7 +55,7 @@ class MoreInfoSun extends LitElement {
|
||||
${this.hass.localize("ui.dialogs.more_info_control.sun.elevation")}
|
||||
</div>
|
||||
<div class="value">
|
||||
${formatNumber(this.stateObj.attributes.elevation, this.hass.locale)}
|
||||
${this.hass.formatEntityAttributeValue(this.stateObj, "elevation")}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -17,7 +17,6 @@ import { computeAttributeValueDisplay } from "../../../common/entity/compute_att
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||
import "../../../components/entity/ha-battery-icon";
|
||||
import "../../../components/ha-attributes";
|
||||
import "../../../components/ha-icon";
|
||||
@ -280,11 +279,7 @@ class MoreInfoVacuum extends LitElement {
|
||||
return html`
|
||||
<div>
|
||||
<span>
|
||||
${batteryIsBinary
|
||||
? ""
|
||||
: `${Number(battery.state).toFixed()}${blankBeforePercent(
|
||||
this.hass.locale
|
||||
)}%`}
|
||||
${batteryIsBinary ? "" : this.hass.formatEntityState(battery)}
|
||||
<ha-battery-icon
|
||||
.hass=${this.hass}
|
||||
.batteryStateObj=${battery}
|
||||
@ -303,9 +298,12 @@ class MoreInfoVacuum extends LitElement {
|
||||
return html`
|
||||
<div>
|
||||
<span>
|
||||
${stateObj.attributes.battery_level.toFixed()}${blankBeforePercent(
|
||||
this.hass.locale
|
||||
)}%
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
stateObj,
|
||||
"battery_level",
|
||||
Math.round(stateObj.attributes.battery_level)
|
||||
)}
|
||||
|
||||
<ha-icon .icon=${stateObj.attributes.battery_icon}></ha-icon>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -3,9 +3,9 @@ import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-list-item";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import {
|
||||
WaterHeaterEntity,
|
||||
WaterHeaterEntityFeature,
|
||||
@ -15,7 +15,6 @@ import {
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { moreInfoControlStyle } from "../components/ha-more-info-control-style";
|
||||
import "../components/water_heater/ha-more-info-water_heater-temperature";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
|
||||
@customElement("more-info-water_heater")
|
||||
class MoreInfoWaterHeater extends LitElement {
|
||||
@ -54,8 +53,10 @@ class MoreInfoWaterHeater extends LitElement {
|
||||
)}
|
||||
</p>
|
||||
<p class="value">
|
||||
${formatNumber(currentTemperature, this.hass.locale)}
|
||||
${this.hass.config.unit_system.temperature}
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"current_temperature"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
|
@ -16,14 +16,12 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { formatDateWeekdayDay } from "../../../common/datetime/format_date";
|
||||
import { formatTimeWeekday } from "../../../common/datetime/format_time";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import {
|
||||
ForecastEvent,
|
||||
WeatherEntity,
|
||||
getDefaultForecastType,
|
||||
getForecast,
|
||||
getWeatherUnit,
|
||||
getWind,
|
||||
subscribeForecast,
|
||||
weatherIcons,
|
||||
@ -133,11 +131,10 @@ class MoreInfoWeather extends LitElement {
|
||||
${this.hass.localize("ui.card.weather.attributes.temperature")}
|
||||
</div>
|
||||
<div>
|
||||
${formatNumber(
|
||||
this.stateObj.attributes.temperature!,
|
||||
this.hass.locale
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"temperature"
|
||||
)}
|
||||
${getWeatherUnit(this.hass, this.stateObj, "temperature")}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
@ -150,11 +147,10 @@ class MoreInfoWeather extends LitElement {
|
||||
${this.hass.localize("ui.card.weather.attributes.air_pressure")}
|
||||
</div>
|
||||
<div>
|
||||
${formatNumber(
|
||||
this.stateObj.attributes.pressure!,
|
||||
this.hass.locale
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"pressure"
|
||||
)}
|
||||
${getWeatherUnit(this.hass, this.stateObj, "pressure")}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
@ -167,11 +163,10 @@ class MoreInfoWeather extends LitElement {
|
||||
${this.hass.localize("ui.card.weather.attributes.humidity")}
|
||||
</div>
|
||||
<div>
|
||||
${formatNumber(
|
||||
this.stateObj.attributes.humidity!,
|
||||
this.hass.locale
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"humidity"
|
||||
)}
|
||||
%
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
@ -202,11 +197,10 @@ class MoreInfoWeather extends LitElement {
|
||||
${this.hass.localize("ui.card.weather.attributes.visibility")}
|
||||
</div>
|
||||
<div>
|
||||
${formatNumber(
|
||||
this.stateObj.attributes.visibility!,
|
||||
this.hass.locale
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"visibility"
|
||||
)}
|
||||
${getWeatherUnit(this.hass, this.stateObj, "visibility")}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
@ -256,24 +250,20 @@ class MoreInfoWeather extends LitElement {
|
||||
</div>
|
||||
<div class="templow">
|
||||
${this._showValue(item.templow)
|
||||
? `${formatNumber(item.templow!, this.hass.locale)}
|
||||
${getWeatherUnit(
|
||||
this.hass,
|
||||
? this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"temperature"
|
||||
)}`
|
||||
"templow"
|
||||
)
|
||||
: hourly
|
||||
? ""
|
||||
: "—"}
|
||||
</div>
|
||||
<div class="temp">
|
||||
${this._showValue(item.temperature)
|
||||
? `${formatNumber(item.temperature!, this.hass.locale)}
|
||||
${getWeatherUnit(
|
||||
this.hass,
|
||||
this.stateObj!,
|
||||
"temperature"
|
||||
)}`
|
||||
? this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"temperature"
|
||||
)
|
||||
: "—"}
|
||||
</div>
|
||||
</div>`
|
||||
|
@ -159,6 +159,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
? stateObj.attributes[this._config.attribute!] !== undefined
|
||||
? html`
|
||||
<ha-attribute-value
|
||||
hide-unit
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
.attribute=${this._config.attribute!}
|
||||
|
@ -28,7 +28,6 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import { stateIconPath } from "../../../common/entity/state_icon_path";
|
||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/tile/ha-tile-badge";
|
||||
import "../../../components/tile/ha-tile-icon";
|
||||
@ -208,37 +207,26 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
if (domain === "light" && stateActive(stateObj)) {
|
||||
const brightness = (stateObj as LightEntity).attributes.brightness;
|
||||
if (brightness) {
|
||||
return `${Math.round((brightness * 100) / 255)}${blankBeforePercent(
|
||||
this.hass!.locale
|
||||
)}%`;
|
||||
return this.hass!.formatEntityAttributeValue(stateObj, "brightness");
|
||||
}
|
||||
}
|
||||
|
||||
if (domain === "fan") {
|
||||
const speedStateDisplay = computeFanSpeedStateDisplay(
|
||||
stateObj as FanEntity,
|
||||
this.hass!.locale
|
||||
this.hass!
|
||||
);
|
||||
if (speedStateDisplay) {
|
||||
return speedStateDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
if (domain === "humidifier" && stateActive(stateObj)) {
|
||||
const humidity = (stateObj as HumidifierEntity).attributes.humidity;
|
||||
if (humidity) {
|
||||
return `${Math.round(humidity)}${blankBeforePercent(
|
||||
this.hass!.locale
|
||||
)}%`;
|
||||
}
|
||||
}
|
||||
|
||||
const stateDisplay = this.hass!.formatEntityState(stateObj);
|
||||
|
||||
if (domain === "cover") {
|
||||
const positionStateDisplay = computeCoverPositionStateDisplay(
|
||||
stateObj as CoverEntity,
|
||||
this.hass!.locale
|
||||
this.hass!
|
||||
);
|
||||
if (positionStateDisplay) {
|
||||
return `${stateDisplay} ⸱ ${positionStateDisplay}`;
|
||||
@ -248,9 +236,12 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
if (domain === "humidifier" && stateActive(stateObj)) {
|
||||
const humidity = (stateObj as HumidifierEntity).attributes.humidity;
|
||||
if (humidity) {
|
||||
return `${stateDisplay} ⸱ ${Math.round(humidity)}${blankBeforePercent(
|
||||
this.hass!.locale
|
||||
)}%`;
|
||||
const formattedHumidity = this.hass!.formatEntityAttributeValue(
|
||||
stateObj,
|
||||
"humidity",
|
||||
Math.round(humidity)
|
||||
);
|
||||
return `${stateDisplay} ⸱ ${formattedHumidity}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
this.hass.locale
|
||||
)} <span
|
||||
>${getWeatherUnit(
|
||||
this.hass,
|
||||
this.hass.config,
|
||||
stateObj,
|
||||
"temperature"
|
||||
)}</span
|
||||
@ -317,14 +317,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
stateObj.attributes.wind_bearing
|
||||
)
|
||||
: html`
|
||||
${formatNumber(
|
||||
stateObj.attributes[
|
||||
this._config.secondary_info_attribute
|
||||
],
|
||||
this.hass.locale
|
||||
)}
|
||||
${getWeatherUnit(
|
||||
this.hass,
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
stateObj,
|
||||
this._config.secondary_info_attribute
|
||||
)}
|
||||
|
@ -1,29 +1,26 @@
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
css,
|
||||
html,
|
||||
nothing,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import "../../../components/entity/state-badge";
|
||||
import { isUnavailableState } from "../../../data/entity";
|
||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||
import {
|
||||
ForecastEvent,
|
||||
WeatherEntity,
|
||||
getDefaultForecastType,
|
||||
getForecast,
|
||||
getSecondaryWeatherAttribute,
|
||||
getWeatherStateIcon,
|
||||
getWeatherUnit,
|
||||
subscribeForecast,
|
||||
ForecastEvent,
|
||||
WeatherEntity,
|
||||
weatherSVGStyles,
|
||||
} from "../../../data/weather";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
@ -200,20 +197,8 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
||||
${isUnavailableState(stateObj.state) ||
|
||||
stateObj.attributes.temperature === undefined ||
|
||||
stateObj.attributes.temperature === null
|
||||
? computeStateDisplay(
|
||||
this.hass.localize,
|
||||
stateObj,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this.hass.entities
|
||||
)
|
||||
: html`
|
||||
${formatNumber(
|
||||
stateObj.attributes.temperature,
|
||||
this.hass.locale
|
||||
)}
|
||||
${getWeatherUnit(this.hass, stateObj, "temperature")}
|
||||
`}
|
||||
? this.hass.formatEntityState(stateObj)
|
||||
: this.hass.formatEntityAttributeValue(stateObj, "temperature")}
|
||||
</div>
|
||||
<div class="secondary">
|
||||
${getSecondaryWeatherAttribute(this.hass!, stateObj, forecast!)}
|
||||
|
@ -73,6 +73,7 @@ class HuiAttributeRow extends LitElement implements LovelaceRow {
|
||||
: attribute !== undefined
|
||||
? html`
|
||||
<ha-attribute-value
|
||||
.hideUnit=${this._config.suffix}
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
.attribute=${this._config.attribute}
|
||||
|
@ -261,7 +261,7 @@ export interface HomeAssistant {
|
||||
formatEntityAttributeValue(
|
||||
stateObj: HassEntity,
|
||||
attribute: string,
|
||||
value?: string
|
||||
value?: any
|
||||
): string;
|
||||
formatEntityAttributeName(stateObj: HassEntity, attribute: string): string;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user