Add unit when formatting attribute for display (#17607)

This commit is contained in:
Paul Bottein 2023-08-18 10:28:27 +02:00 committed by GitHub
parent bbb99a6eee
commit 6e27fbe10f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 262 additions and 207 deletions

View File

@ -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

View File

@ -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")) {

View File

@ -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 "";

View File

@ -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 "";

View File

@ -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)
)
: "";
}

View File

@ -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: "%",
},
};

View File

@ -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)
)
: "";
}

View File

@ -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)
: ""}
`;
};

View File

@ -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>
`;
}

View File

@ -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>
`

View File

@ -94,7 +94,7 @@ class MoreInfoCover extends LitElement {
const positionStateDisplay = computeCoverPositionStateDisplay(
this.stateObj!,
this.hass.locale,
this.hass,
liveValue
);

View File

@ -112,7 +112,7 @@ class MoreInfoFan extends LitElement {
const positionStateDisplay = computeFanSpeedStateDisplay(
this.stateObj!,
this.hass.locale,
this.hass,
liveValue
);

View File

@ -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>
`

View File

@ -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;
}

View File

@ -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>
`;

View File

@ -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>

View File

@ -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>
`

View File

@ -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>`

View File

@ -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!}

View File

@ -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}`;
}
}

View File

@ -284,7 +284,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
this.hass.locale
)}&nbsp;<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
)}

View File

@ -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!)}

View File

@ -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}

View File

@ -261,7 +261,7 @@ export interface HomeAssistant {
formatEntityAttributeValue(
stateObj: HassEntity,
attribute: string,
value?: string
value?: any
): string;
formatEntityAttributeName(stateObj: HassEntity, attribute: string): string;
}