diff --git a/src/cards/chips-card/chips/alarm-control-panel-chip.ts b/src/cards/chips-card/chips/alarm-control-panel-chip.ts
index 8638c56b6..828057921 100644
--- a/src/cards/chips-card/chips/alarm-control-panel-chip.ts
+++ b/src/cards/chips-card/chips/alarm-control-panel-chip.ts
@@ -7,7 +7,6 @@ import {
actionHandler,
ActionHandlerEvent,
computeRTL,
- computeStateDisplay,
handleAction,
hasAction,
HomeAssistant,
@@ -82,15 +81,7 @@ export class AlarmControlPanelChip extends LitElement implements LovelaceChip {
const iconColor = getStateColor(stateObj.state);
const iconPulse = shouldPulse(stateObj.state);
- const stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ const stateDisplay = this.hass.formatEntityState(stateObj);
const iconStyle = {};
if (iconColor) {
diff --git a/src/cards/chips-card/chips/entity-chip.ts b/src/cards/chips-card/chips/entity-chip.ts
index f894fe571..712f9a3a7 100644
--- a/src/cards/chips-card/chips/entity-chip.ts
+++ b/src/cards/chips-card/chips/entity-chip.ts
@@ -1,3 +1,4 @@
+import { HassEntity } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
@@ -13,7 +14,6 @@ import {
actionHandler,
ActionHandlerEvent,
computeRTL,
- computeStateDisplay,
getEntityPicture,
handleAction,
hasAction,
@@ -31,7 +31,6 @@ import {
LovelaceChip,
} from "../../../utils/lovelace/chip/types";
import { LovelaceChipEditor } from "../../../utils/lovelace/types";
-import { HassEntity } from "home-assistant-js-websocket";
@customElement(computeChipComponentName("entity"))
export class EntityChip extends LitElement implements LovelaceChip {
@@ -84,15 +83,7 @@ export class EntityChip extends LitElement implements LovelaceChip {
? getEntityPicture(stateObj)
: undefined;
- const stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ const stateDisplay = this.hass.formatEntityState(stateObj);
const active = isActive(stateObj);
diff --git a/src/cards/chips-card/chips/light-chip.ts b/src/cards/chips-card/chips/light-chip.ts
index 500a501e1..3d7239aef 100644
--- a/src/cards/chips-card/chips/light-chip.ts
+++ b/src/cards/chips-card/chips/light-chip.ts
@@ -6,7 +6,6 @@ import {
actionHandler,
ActionHandlerEvent,
computeRTL,
- computeStateDisplay,
handleAction,
hasAction,
HomeAssistant,
@@ -80,15 +79,7 @@ export class LightChip extends LitElement implements LovelaceChip {
const name = this._config.name || stateObj.attributes.friendly_name || "";
const icon = this._config.icon;
- const stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ const stateDisplay = this.hass.formatEntityState(stateObj);
const active = isActive(stateObj);
diff --git a/src/cards/chips-card/chips/weather-chip.ts b/src/cards/chips-card/chips/weather-chip.ts
index de540c01c..f4174d0d5 100644
--- a/src/cards/chips-card/chips/weather-chip.ts
+++ b/src/cards/chips-card/chips/weather-chip.ts
@@ -1,10 +1,10 @@
+import { HassEntity } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import {
actionHandler,
ActionHandlerEvent,
computeRTL,
- computeStateDisplay,
formatNumber,
handleAction,
hasAction,
@@ -20,7 +20,6 @@ import {
} from "../../../utils/lovelace/chip/types";
import { LovelaceChipEditor } from "../../../utils/lovelace/types";
import { getWeatherStateSVG, weatherSVGStyles } from "../../../utils/weather";
-import { HassEntity } from "home-assistant-js-websocket";
@customElement(computeChipComponentName("weather"))
export class WeatherChip extends LitElement implements LovelaceChip {
@@ -71,23 +70,15 @@ export class WeatherChip extends LitElement implements LovelaceChip {
const displayLabels: string[] = [];
if (this._config.show_conditions) {
- const stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ const stateDisplay = this.hass.formatEntityState(stateObj);
displayLabels.push(stateDisplay);
}
if (this._config.show_temperature) {
- const temperatureDisplay = `${formatNumber(
- stateObj.attributes.temperature,
- this.hass.locale
- )} ${this.hass.config.unit_system.temperature}`;
+ const temperatureDisplay = this.hass.formatEntityAttributeValue(
+ stateObj,
+ "temperature"
+ );
displayLabels.push(temperatureDisplay);
}
@@ -104,7 +95,7 @@ export class WeatherChip extends LitElement implements LovelaceChip {
>
${weatherIcon}
${displayLabels.length > 0
- ? html`${displayLabels.join(" / ")}`
+ ? html`${displayLabels.join(" ⸱ ")}`
: nothing}
`;
diff --git a/src/cards/climate-card/climate-card.ts b/src/cards/climate-card/climate-card.ts
index 7bdf551e0..52fc59ab0 100644
--- a/src/cards/climate-card/climate-card.ts
+++ b/src/cards/climate-card/climate-card.ts
@@ -14,7 +14,6 @@ import {
ActionHandlerEvent,
ClimateEntity,
computeRTL,
- computeStateDisplay,
formatNumber,
handleAction,
hasAction,
@@ -167,22 +166,13 @@ export class ClimateCard
const appearance = computeAppearance(this._config);
const picture = computeEntityPicture(stateObj, appearance.icon_type);
- let stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ let stateDisplay = this.hass.formatEntityState(stateObj);
if (stateObj.attributes.current_temperature !== null) {
- const temperature = formatNumber(
- stateObj.attributes.current_temperature,
- this.hass.locale
+ const temperature = this.hass.formatEntityAttributeValue(
+ stateObj,
+ "current_temperature"
);
- const unit = this.hass.config.unit_system.temperature;
- stateDisplay += ` - ${temperature} ${unit}`;
+ stateDisplay += ` ⸱ ${temperature}`;
}
const rtl = computeRTL(this.hass);
diff --git a/src/cards/cover-card/cover-card.ts b/src/cards/cover-card/cover-card.ts
index 0efcccc92..8769f283f 100644
--- a/src/cards/cover-card/cover-card.ts
+++ b/src/cards/cover-card/cover-card.ts
@@ -12,9 +12,7 @@ import { styleMap } from "lit/directives/style-map.js";
import {
actionHandler,
ActionHandlerEvent,
- blankBeforePercent,
computeRTL,
- computeStateDisplay,
CoverEntity,
handleAction,
hasAction,
@@ -195,17 +193,14 @@ export class CoverCard
const appearance = computeAppearance(this._config);
const picture = computeEntityPicture(stateObj, appearance.icon_type);
- let stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ let stateDisplay = this.hass.formatEntityState(stateObj);
if (this.position) {
- stateDisplay += ` - ${this.position}${blankBeforePercent(this.hass.locale)}%`;
+ const position = this.hass.formatEntityAttributeValue(
+ stateObj,
+ "current_position",
+ this.position
+ );
+ stateDisplay += ` ⸱ ${position}`;
}
const rtl = computeRTL(this.hass);
diff --git a/src/cards/fan-card/fan-card.ts b/src/cards/fan-card/fan-card.ts
index 3ea139248..8f6fd3805 100644
--- a/src/cards/fan-card/fan-card.ts
+++ b/src/cards/fan-card/fan-card.ts
@@ -13,9 +13,7 @@ import { styleMap } from "lit/directives/style-map.js";
import {
actionHandler,
ActionHandlerEvent,
- blankBeforePercent,
computeRTL,
- computeStateDisplay,
handleAction,
hasAction,
HomeAssistant,
@@ -137,17 +135,14 @@ export class FanCard
const appearance = computeAppearance(this._config);
const picture = computeEntityPicture(stateObj, appearance.icon_type);
- let stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ let stateDisplay = this.hass.formatEntityState(stateObj);
if (this.percentage != null && stateObj.state === "on") {
- stateDisplay = `${this.percentage}${blankBeforePercent(this.hass.locale)}%`;
+ const percentage = this.hass.formatEntityAttributeValue(
+ stateObj,
+ "percentage",
+ this.percentage
+ );
+ stateDisplay = percentage;
}
const rtl = computeRTL(this.hass);
diff --git a/src/cards/humidifier-card/humidifier-card.ts b/src/cards/humidifier-card/humidifier-card.ts
index 9939c3526..3dac3656f 100644
--- a/src/cards/humidifier-card/humidifier-card.ts
+++ b/src/cards/humidifier-card/humidifier-card.ts
@@ -4,9 +4,7 @@ import { classMap } from "lit/directives/class-map.js";
import {
actionHandler,
ActionHandlerEvent,
- blankBeforePercent,
computeRTL,
- computeStateDisplay,
handleAction,
hasAction,
HomeAssistant,
@@ -110,17 +108,14 @@ export class HumidifierCard
const appearance = computeAppearance(this._config);
const picture = computeEntityPicture(stateObj, appearance.icon_type);
- let stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ let stateDisplay = this.hass.formatEntityState(stateObj);
if (this.humidity) {
- stateDisplay = `${this.humidity}${blankBeforePercent(this.hass.locale)}%`;
+ const humidity = this.hass.formatEntityAttributeValue(
+ stateObj,
+ "current_humidity",
+ this.humidity
+ );
+ stateDisplay = humidity;
}
const rtl = computeRTL(this.hass);
diff --git a/src/cards/light-card/light-card.ts b/src/cards/light-card/light-card.ts
index 7d3a6bffd..0a0ed1d4e 100644
--- a/src/cards/light-card/light-card.ts
+++ b/src/cards/light-card/light-card.ts
@@ -12,9 +12,7 @@ import { styleMap } from "lit/directives/style-map.js";
import {
actionHandler,
ActionHandlerEvent,
- blankBeforePercent,
computeRTL,
- computeStateDisplay,
handleAction,
hasAction,
HomeAssistant,
@@ -46,7 +44,6 @@ import "./controls/light-color-control";
import "./controls/light-color-temp-control";
import { LightCardConfig } from "./light-card-config";
import {
- getBrightness,
getRGBColor,
isColorLight,
isColorSuperLight,
@@ -158,12 +155,12 @@ export class LightCard
const stateObj = this._stateObj;
if (!stateObj) return;
- this.brightness = getBrightness(stateObj);
+ this.brightness = stateObj.attributes.brightness;
}
private onCurrentBrightnessChange(e: CustomEvent<{ value?: number }>): void {
if (e.detail.value != null) {
- this.brightness = e.detail.value;
+ this.brightness = (e.detail.value * 255) / 100;
}
}
@@ -196,17 +193,14 @@ export class LightCard
const appearance = computeAppearance(this._config);
const picture = computeEntityPicture(stateObj, appearance.icon_type);
- let stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ let stateDisplay = this.hass.formatEntityState(stateObj);
if (this.brightness != null) {
- stateDisplay = `${this.brightness}${blankBeforePercent(this.hass.locale)}%`;
+ const brightness = this.hass.formatEntityAttributeValue(
+ stateObj,
+ "brightness",
+ this.brightness
+ );
+ stateDisplay = brightness;
}
const rtl = computeRTL(this.hass);
diff --git a/src/cards/media-player-card/media-player-card.ts b/src/cards/media-player-card/media-player-card.ts
index 4c14ba10c..93b8009a5 100644
--- a/src/cards/media-player-card/media-player-card.ts
+++ b/src/cards/media-player-card/media-player-card.ts
@@ -11,7 +11,6 @@ import { classMap } from "lit/directives/class-map.js";
import {
actionHandler,
ActionHandlerEvent,
- blankBeforePercent,
computeRTL,
handleAction,
hasAction,
@@ -45,7 +44,6 @@ import {
computeMediaIcon,
computeMediaNameDisplay,
computeMediaStateDisplay,
- getVolumeLevel,
} from "./utils";
type MediaPlayerCardControl = "media_control" | "volume_control";
@@ -137,13 +135,12 @@ export class MediaPlayerCard
const stateObj = this._stateObj;
if (!stateObj) return;
- const volume = getVolumeLevel(stateObj);
- this.volume = volume != null ? Math.round(volume) : volume;
+ this.volume = stateObj.attributes.volume_level;
}
private onCurrentVolumeChange(e: CustomEvent<{ value?: number }>): void {
if (e.detail.value != null) {
- this.volume = e.detail.value;
+ this.volume = e.detail.value / 100;
}
}
@@ -173,18 +170,22 @@ export class MediaPlayerCard
const icon = computeMediaIcon(this._config, stateObj);
const nameDisplay = computeMediaNameDisplay(this._config, stateObj);
- const stateDisplay = computeMediaStateDisplay(
+ const appearance = computeAppearance(this._config);
+ const picture = computeEntityPicture(stateObj, appearance.icon_type);
+ let stateDisplay = computeMediaStateDisplay(
this._config,
stateObj,
this.hass
);
- const appearance = computeAppearance(this._config);
- const picture = computeEntityPicture(stateObj, appearance.icon_type);
- const stateValue =
- this.volume != null && this._config.show_volume_level
- ? `${stateDisplay} - ${this.volume}${blankBeforePercent(this.hass.locale)}%`
- : stateDisplay;
+ if (this.volume != null && this._config.show_volume_level) {
+ const volume = this.hass.formatEntityAttributeValue(
+ stateObj,
+ "volume_level",
+ this.volume
+ );
+ stateDisplay += ` ⸱ ${volume}`;
+ }
const rtl = computeRTL(this.hass);
@@ -216,7 +217,7 @@ export class MediaPlayerCard
stateObj,
appearance,
nameDisplay,
- stateValue
+ stateDisplay
)};
${isControlVisible
diff --git a/src/cards/media-player-card/utils.ts b/src/cards/media-player-card/utils.ts
index 58359d268..3a8cfc8ed 100644
--- a/src/cards/media-player-card/utils.ts
+++ b/src/cards/media-player-card/utils.ts
@@ -15,7 +15,6 @@ import {
UNAVAILABLE,
UNKNOWN,
computeMediaDescription,
- computeStateDisplay,
supportsFeature,
} from "../../ha";
import {
@@ -56,15 +55,7 @@ export function computeMediaStateDisplay(
entity: MediaPlayerEntity,
hass: HomeAssistant
): string {
- let state = hass.formatEntityState
- ? hass.formatEntityState(entity)
- : computeStateDisplay(
- hass.localize,
- entity,
- hass.locale,
- hass.config,
- hass.entities
- );
+ let state = hass.formatEntityState(entity);
if (
![UNAVAILABLE, UNKNOWN, OFF].includes(entity.state) &&
config.use_media_info
diff --git a/src/cards/number-card/number-card.ts b/src/cards/number-card/number-card.ts
index 5ef2e9d46..f223f7a69 100644
--- a/src/cards/number-card/number-card.ts
+++ b/src/cards/number-card/number-card.ts
@@ -14,10 +14,6 @@ import {
actionHandler,
ActionHandlerEvent,
computeRTL,
- computeStateDisplay,
- formatNumber,
- getDefaultFormatOptions,
- getNumberFormatOptions,
handleAction,
hasAction,
HomeAssistant,
@@ -124,25 +120,12 @@ export class NumberCard
const appearance = computeAppearance(this._config);
const picture = computeEntityPicture(stateObj, appearance.icon_type);
- let stateDisplay = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ let stateDisplay = this.hass.formatEntityState(stateObj);
if (this.value !== undefined) {
- const numberValue = formatNumber(
- this.value,
- this.hass.locale,
- getNumberFormatOptions(
- stateObj,
- this.hass.entities[stateObj.entity_id]
- ) ?? getDefaultFormatOptions(stateObj.state)
+ stateDisplay = this.hass.formatEntityState(
+ stateObj,
+ this.value.toString()
);
- stateDisplay = `${numberValue} ${stateObj.attributes.unit_of_measurement ?? ""}`;
}
const rtl = computeRTL(this.hass);
diff --git a/src/cards/select-card/controls/select-option-control.ts b/src/cards/select-card/controls/select-option-control.ts
index 56110b034..23dbc3d5a 100644
--- a/src/cards/select-card/controls/select-option-control.ts
+++ b/src/cards/select-card/controls/select-option-control.ts
@@ -1,7 +1,7 @@
import { HassEntity } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
-import { computeStateDisplay, HomeAssistant } from "../../../ha";
+import { HomeAssistant } from "../../../ha";
import "../../../shared/form/mushroom-select";
import { getCurrentOption, getOptions } from "../utils";
@@ -47,16 +47,7 @@ export class SelectOptionControl extends LitElement {
${options.map((option) => {
return html`
- ${this.hass.formatEntityState
- ? this.hass.formatEntityState(this.entity, option)
- : computeStateDisplay(
- this.hass.localize,
- this.entity,
- this.hass.locale,
- this.hass.config,
- this.hass.entities,
- option
- )}
+ ${this.hass.formatEntityState(this.entity, option)}
`;
})}
diff --git a/src/ha/common/datetime/duration.ts b/src/ha/common/datetime/duration.ts
deleted file mode 100644
index 36fef1902..000000000
--- a/src/ha/common/datetime/duration.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import millisecondsToDuration from "./milliseconds_to_duration";
-
-const DAY_IN_MILLISECONDS = 86400000;
-const HOUR_IN_MILLISECONDS = 3600000;
-const MINUTE_IN_MILLISECONDS = 60000;
-const SECOND_IN_MILLISECONDS = 1000;
-
-export const UNIT_TO_MILLISECOND_CONVERT = {
- ms: 1,
- s: SECOND_IN_MILLISECONDS,
- min: MINUTE_IN_MILLISECONDS,
- h: HOUR_IN_MILLISECONDS,
- d: DAY_IN_MILLISECONDS,
-};
-
-export const formatDuration = (duration: string, units: string): string =>
- millisecondsToDuration(
- parseFloat(duration) * UNIT_TO_MILLISECOND_CONVERT[units]
- ) || "0";
diff --git a/src/ha/common/datetime/format_date.ts b/src/ha/common/datetime/format_date.ts
deleted file mode 100644
index 95ca1a94c..000000000
--- a/src/ha/common/datetime/format_date.ts
+++ /dev/null
@@ -1,193 +0,0 @@
-import { HassConfig } from "home-assistant-js-websocket";
-import memoizeOne from "memoize-one";
-import { FrontendLocaleData, DateFormat } from "../../data/translation";
-
-// Tuesday, August 10
-export const formatDateWeekdayDay = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateWeekdayDayMem(locale, config.time_zone).format(dateObj);
-
-const formatDateWeekdayDayMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- weekday: "long",
- month: "long",
- day: "numeric",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
-
-// August 10, 2021
-export const formatDate = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateMem(locale, config.time_zone).format(dateObj);
-
-const formatDateMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- year: "numeric",
- month: "long",
- day: "numeric",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
-
-// 10/08/2021
-export const formatDateNumeric = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => {
- const formatter = formatDateNumericMem(locale, config.time_zone);
-
- if (
- locale.date_format === DateFormat.language ||
- locale.date_format === DateFormat.system
- ) {
- return formatter.format(dateObj);
- }
-
- const parts = formatter.formatToParts(dateObj);
-
- const literal = parts.find((value) => value.type === "literal")?.value;
- const day = parts.find((value) => value.type === "day")?.value;
- const month = parts.find((value) => value.type === "month")?.value;
- const year = parts.find((value) => value.type === "year")?.value;
-
- const lastPart = parts[parts.length - 1];
- let lastLiteral = lastPart?.type === "literal" ? lastPart?.value : "";
-
- if (locale.language === "bg" && locale.date_format === DateFormat.YMD) {
- lastLiteral = "";
- }
-
- const formats = {
- [DateFormat.DMY]: `${day}${literal}${month}${literal}${year}${lastLiteral}`,
- [DateFormat.MDY]: `${month}${literal}${day}${literal}${year}${lastLiteral}`,
- [DateFormat.YMD]: `${year}${literal}${month}${literal}${day}${lastLiteral}`,
- };
-
- return formats[locale.date_format];
-};
-
-const formatDateNumericMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) => {
- const localeString =
- locale.date_format === DateFormat.system ? undefined : locale.language;
-
- if (
- locale.date_format === DateFormat.language ||
- locale.date_format === DateFormat.system
- ) {
- return new Intl.DateTimeFormat(localeString, {
- year: "numeric",
- month: "numeric",
- day: "numeric",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- });
- }
-
- return new Intl.DateTimeFormat(localeString, {
- year: "numeric",
- month: "numeric",
- day: "numeric",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- });
- }
-);
-
-// Aug 10
-export const formatDateShort = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateShortMem(locale, config.time_zone).format(dateObj);
-
-const formatDateShortMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- day: "numeric",
- month: "short",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
-
-// August 2021
-export const formatDateMonthYear = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateMonthYearMem(locale, config.time_zone).format(dateObj);
-
-const formatDateMonthYearMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- month: "long",
- year: "numeric",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
-
-// August
-export const formatDateMonth = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateMonthMem(locale, config.time_zone).format(dateObj);
-
-const formatDateMonthMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- month: "long",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
-
-// 2021
-export const formatDateYear = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateYearMem(locale, config.time_zone).format(dateObj);
-
-const formatDateYearMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- year: "numeric",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
-
-// Monday
-export const formatDateWeekday = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateWeekdayMem(locale, config.time_zone).format(dateObj);
-
-const formatDateWeekdayMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- weekday: "long",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
-
-// Mon
-export const formatDateWeekdayShort = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateWeekdayShortMem(locale, config.time_zone).format(dateObj);
-
-const formatDateWeekdayShortMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(locale.language, {
- weekday: "short",
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
diff --git a/src/ha/common/datetime/format_date_time.ts b/src/ha/common/datetime/format_date_time.ts
deleted file mode 100644
index f70c685a1..000000000
--- a/src/ha/common/datetime/format_date_time.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import { HassConfig } from "home-assistant-js-websocket";
-import memoizeOne from "memoize-one";
-import { FrontendLocaleData } from "../../data/translation";
-import { formatDateNumeric } from "./format_date";
-import { formatTime } from "./format_time";
-import { useAmPm } from "./use_am_pm";
-
-// August 9, 2021, 8:23 AM
-export const formatDateTime = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateTimeMem(locale, config.time_zone).format(dateObj);
-
-const formatDateTimeMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(
- locale.language === "en" && !useAmPm(locale)
- ? "en-u-hc-h23"
- : locale.language,
- {
- year: "numeric",
- month: "long",
- day: "numeric",
- hour: useAmPm(locale) ? "numeric" : "2-digit",
- minute: "2-digit",
- hour12: useAmPm(locale),
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- }
- )
-);
-
-// Aug 9, 2021, 8:23 AM
-export const formatShortDateTimeWithYear = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatShortDateTimeWithYearMem(locale, config.time_zone).format(dateObj);
-
-const formatShortDateTimeWithYearMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(
- locale.language === "en" && !useAmPm(locale)
- ? "en-u-hc-h23"
- : locale.language,
- {
- year: "numeric",
- month: "short",
- day: "numeric",
- hour: useAmPm(locale) ? "numeric" : "2-digit",
- minute: "2-digit",
- hour12: useAmPm(locale),
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- }
- )
-);
-
-// Aug 9, 8:23 AM
-export const formatShortDateTime = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatShortDateTimeMem(locale, config.time_zone).format(dateObj);
-
-const formatShortDateTimeMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(
- locale.language === "en" && !useAmPm(locale)
- ? "en-u-hc-h23"
- : locale.language,
- {
- month: "short",
- day: "numeric",
- hour: useAmPm(locale) ? "numeric" : "2-digit",
- minute: "2-digit",
- hour12: useAmPm(locale),
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- }
- )
-);
-
-// August 9, 2021, 8:23:15 AM
-export const formatDateTimeWithSeconds = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatDateTimeWithSecondsMem(locale, config.time_zone).format(dateObj);
-
-const formatDateTimeWithSecondsMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(
- locale.language === "en" && !useAmPm(locale)
- ? "en-u-hc-h23"
- : locale.language,
- {
- year: "numeric",
- month: "long",
- day: "numeric",
- hour: useAmPm(locale) ? "numeric" : "2-digit",
- minute: "2-digit",
- second: "2-digit",
- hour12: useAmPm(locale),
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- }
- )
-);
-
-// 9/8/2021, 8:23 AM
-export const formatDateTimeNumeric = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) =>
- `${formatDateNumeric(dateObj, locale, config)}, ${formatTime(dateObj, locale, config)}`;
diff --git a/src/ha/common/datetime/format_time.ts b/src/ha/common/datetime/format_time.ts
deleted file mode 100644
index 3bda190f5..000000000
--- a/src/ha/common/datetime/format_time.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { HassConfig } from "home-assistant-js-websocket";
-import memoizeOne from "memoize-one";
-import { FrontendLocaleData } from "../../data/translation";
-import { useAmPm } from "./use_am_pm";
-
-// 9:15 PM || 21:15
-export const formatTime = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatTimeMem(locale, config.time_zone).format(dateObj);
-
-const formatTimeMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(
- locale.language === "en" && !useAmPm(locale)
- ? "en-u-hc-h23"
- : locale.language,
- {
- hour: "numeric",
- minute: "2-digit",
- hour12: useAmPm(locale),
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- }
- )
-);
-
-// 9:15:24 PM || 21:15:24
-export const formatTimeWithSeconds = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatTimeWithSecondsMem(locale, config.time_zone).format(dateObj);
-
-const formatTimeWithSecondsMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(
- locale.language === "en" && !useAmPm(locale)
- ? "en-u-hc-h23"
- : locale.language,
- {
- hour: useAmPm(locale) ? "numeric" : "2-digit",
- minute: "2-digit",
- second: "2-digit",
- hour12: useAmPm(locale),
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- }
- )
-);
-
-// Tuesday 7:00 PM || Tuesday 19:00
-export const formatTimeWeekday = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatTimeWeekdayMem(locale, config.time_zone).format(dateObj);
-
-const formatTimeWeekdayMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- new Intl.DateTimeFormat(
- locale.language === "en" && !useAmPm(locale)
- ? "en-u-hc-h23"
- : locale.language,
- {
- weekday: "long",
- hour: useAmPm(locale) ? "numeric" : "2-digit",
- minute: "2-digit",
- hour12: useAmPm(locale),
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- }
- )
-);
-
-// 21:15
-export const formatTime24h = (
- dateObj: Date,
- locale: FrontendLocaleData,
- config: HassConfig
-) => formatTime24hMem(locale, config.time_zone).format(dateObj);
-
-const formatTime24hMem = memoizeOne(
- (locale: FrontendLocaleData, serverTimeZone: string) =>
- // en-GB to fix Chrome 24:59 to 0:59 https://stackoverflow.com/a/60898146
- new Intl.DateTimeFormat("en-GB", {
- hour: "numeric",
- minute: "2-digit",
- hour12: false,
- timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
- })
-);
diff --git a/src/ha/common/datetime/milliseconds_to_duration.ts b/src/ha/common/datetime/milliseconds_to_duration.ts
deleted file mode 100644
index 384a8a770..000000000
--- a/src/ha/common/datetime/milliseconds_to_duration.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-const leftPad = (num: number, digits = 2) => {
- let paddedNum = "" + num;
- for (let i = 1; i < digits; i++) {
- paddedNum = parseInt(paddedNum) < 10 ** i ? `0${paddedNum}` : paddedNum;
- }
- return paddedNum;
-};
-
-export default function millisecondsToDuration(d: number) {
- const h = Math.floor(d / 1000 / 3600);
- const m = Math.floor(((d / 1000) % 3600) / 60);
- const s = Math.floor(((d / 1000) % 3600) % 60);
- const ms = Math.floor(d % 1000);
-
- if (h > 0) {
- return `${h}:${leftPad(m)}:${leftPad(s)}`;
- }
- if (m > 0) {
- return `${m}:${leftPad(s)}`;
- }
- if (s > 0 || ms > 0) {
- return `${s}${ms > 0 ? `.${leftPad(ms, 3)}` : ``}`;
- }
- return null;
-}
diff --git a/src/ha/common/datetime/use_am_pm.ts b/src/ha/common/datetime/use_am_pm.ts
deleted file mode 100644
index 97bf2911b..000000000
--- a/src/ha/common/datetime/use_am_pm.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import memoizeOne from "memoize-one";
-import { FrontendLocaleData, TimeFormat } from "../../data/translation";
-
-export const useAmPm = memoizeOne((locale: FrontendLocaleData): boolean => {
- if (
- locale.time_format === TimeFormat.language ||
- locale.time_format === TimeFormat.system
- ) {
- const testLanguage =
- locale.time_format === TimeFormat.language ? locale.language : undefined;
- const test = new Date().toLocaleString(testLanguage);
- return test.includes("AM") || test.includes("PM");
- }
-
- return locale.time_format === TimeFormat.am_pm;
-});
diff --git a/src/ha/common/entity/compute_state_display.ts b/src/ha/common/entity/compute_state_display.ts
index 26bc0e830..e69de29bb 100644
--- a/src/ha/common/entity/compute_state_display.ts
+++ b/src/ha/common/entity/compute_state_display.ts
@@ -1,235 +0,0 @@
-import { HassConfig, HassEntity } from "home-assistant-js-websocket";
-import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
-import {
- updateIsInstallingFromAttributes,
- UPDATE_SUPPORT_PROGRESS,
-} from "../../data/update";
-import { EntityRegistryDisplayEntry, HomeAssistant } from "../../types";
-import { FrontendLocaleData, TimeZone } from "../../data/translation";
-import {
- UNIT_TO_MILLISECOND_CONVERT,
- formatDuration,
-} from "../datetime/duration";
-import { formatDate } from "../datetime/format_date";
-import { formatDateTime } from "../datetime/format_date_time";
-import { formatTime } from "../datetime/format_time";
-import {
- formatNumber,
- getNumberFormatOptions,
- isNumericFromAttributes,
-} from "../number/format_number";
-import { blankBeforePercent } from "../translations/blank_before_percent";
-import { LocalizeFunc } from "../translations/localize";
-import { computeDomain } from "./compute_domain";
-import { supportsFeatureFromAttributes } from "./supports-feature";
-
-export const computeStateDisplaySingleEntity = (
- localize: LocalizeFunc,
- stateObj: HassEntity,
- locale: FrontendLocaleData,
- config: HassConfig,
- entity: EntityRegistryDisplayEntry | undefined,
- state?: string
-): string =>
- computeStateDisplayFromEntityAttributes(
- localize,
- locale,
- config,
- entity,
- stateObj.entity_id,
- stateObj.attributes,
- state !== undefined ? state : stateObj.state
- );
-
-export const computeStateDisplay = (
- localize: LocalizeFunc,
- stateObj: HassEntity,
- locale: FrontendLocaleData,
- config: HassConfig,
- entities: HomeAssistant["entities"],
- state?: string
-): string => {
- const entity = entities[stateObj.entity_id] as
- | EntityRegistryDisplayEntry
- | undefined;
-
- return computeStateDisplayFromEntityAttributes(
- localize,
- locale,
- config,
- entity,
- stateObj.entity_id,
- stateObj.attributes,
- state !== undefined ? state : stateObj.state
- );
-};
-
-export const computeStateDisplayFromEntityAttributes = (
- localize: LocalizeFunc,
- locale: FrontendLocaleData,
- config: HassConfig,
- entity: EntityRegistryDisplayEntry | undefined,
- entityId: string,
- attributes: any,
- state: string
-): string => {
- if (state === UNKNOWN || state === UNAVAILABLE) {
- return localize(`state.default.${state}`);
- }
-
- // Entities with a `unit_of_measurement` or `state_class` are numeric values and should use `formatNumber`
- if (isNumericFromAttributes(attributes)) {
- // state is duration
- if (
- attributes.device_class === "duration" &&
- attributes.unit_of_measurement &&
- UNIT_TO_MILLISECOND_CONVERT[attributes.unit_of_measurement]
- ) {
- try {
- return formatDuration(state, attributes.unit_of_measurement);
- } catch (_err) {
- // fallback to default
- }
- }
- if (attributes.device_class === "monetary") {
- try {
- return formatNumber(state, locale, {
- style: "currency",
- currency: attributes.unit_of_measurement,
- minimumFractionDigits: 2,
- // Override monetary options with number format
- ...getNumberFormatOptions(
- { state, attributes } as HassEntity,
- entity
- ),
- });
- } catch (_err) {
- // fallback to default
- }
- }
- const unit = !attributes.unit_of_measurement
- ? ""
- : attributes.unit_of_measurement === "%"
- ? blankBeforePercent(locale) + "%"
- : ` ${attributes.unit_of_measurement}`;
- return `${formatNumber(
- state,
- locale,
- getNumberFormatOptions({ state, attributes } as HassEntity, entity)
- )}${unit}`;
- }
-
- const domain = computeDomain(entityId);
-
- if (domain === "datetime") {
- const time = new Date(state);
- return formatDateTime(time, locale, config);
- }
-
- if (["date", "input_datetime", "time"].includes(domain)) {
- // If trying to display an explicit state, need to parse the explicit state to `Date` then format.
- // Attributes aren't available, we have to use `state`.
-
- // These are timezone agnostic, so we should NOT use the system timezone here.
- try {
- const components = state.split(" ");
- if (components.length === 2) {
- // Date and time.
- return formatDateTime(
- new Date(components.join("T")),
- { ...locale, time_zone: TimeZone.local },
- config
- );
- }
- if (components.length === 1) {
- if (state.includes("-")) {
- // Date only.
- return formatDate(
- new Date(`${state}T00:00`),
- { ...locale, time_zone: TimeZone.local },
- config
- );
- }
- if (state.includes(":")) {
- // Time only.
- const now = new Date();
- return formatTime(
- new Date(`${now.toISOString().split("T")[0]}T${state}`),
- { ...locale, time_zone: TimeZone.local },
- config
- );
- }
- }
- return state;
- } catch (_e) {
- // Formatting methods may throw error if date parsing doesn't go well,
- // just return the state string in that case.
- return state;
- }
- }
-
- // `counter` `number` and `input_number` domains do not have a unit of measurement but should still use `formatNumber`
- if (
- domain === "counter" ||
- domain === "number" ||
- domain === "input_number"
- ) {
- // Format as an integer if the value and step are integers
- return formatNumber(
- state,
- locale,
- getNumberFormatOptions({ state, attributes } as HassEntity, entity)
- );
- }
-
- // state is a timestamp
- if (
- ["button", "event", "input_button", "scene", "stt", "tts"].includes(
- domain
- ) ||
- (domain === "sensor" && attributes.device_class === "timestamp")
- ) {
- try {
- return formatDateTime(new Date(state), locale, config);
- } catch (_err) {
- return state;
- }
- }
-
- if (domain === "update") {
- // When updating, and entity does not support % show "Installing"
- // When updating, and entity does support % show "Installing (xx%)"
- // When update available, show the version
- // When the latest version is skipped, show the latest version
- // When update is not available, show "Up-to-date"
- // When update is not available and there is no latest_version show "Unavailable"
- return state === "on"
- ? updateIsInstallingFromAttributes(attributes)
- ? supportsFeatureFromAttributes(attributes, UPDATE_SUPPORT_PROGRESS) &&
- typeof attributes.in_progress === "number"
- ? localize("ui.card.update.installing_with_progress", {
- progress: attributes.in_progress,
- })
- : localize("ui.card.update.installing")
- : attributes.latest_version
- : attributes.skipped_version === attributes.latest_version
- ? attributes.latest_version ?? localize("state.default.unavailable")
- : localize("ui.card.update.up_to_date");
- }
-
- return (
- (entity?.translation_key &&
- localize(
- `component.${entity.platform}.entity.${domain}.${entity.translation_key}.state.${state}`
- )) ||
- // Return device class translation
- (attributes.device_class &&
- localize(
- `component.${domain}.entity_component.${attributes.device_class}.state.${state}`
- )) ||
- // Return default translation
- localize(`component.${domain}.entity_component._.state.${state}`) ||
- // We don't know! Return the raw state.
- state
- );
-};
diff --git a/src/ha/common/translations/blank_before_percent.ts b/src/ha/common/translations/blank_before_percent.ts
deleted file mode 100644
index 4c489c96c..000000000
--- a/src/ha/common/translations/blank_before_percent.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { FrontendLocaleData } from "../../data/translation";
-
-// Logic based on https://en.wikipedia.org/wiki/Percent_sign#Form_and_spacing
-export const blankBeforePercent = (
- localeOptions: FrontendLocaleData
-): string => {
- switch (localeOptions.language) {
- case "cz":
- case "de":
- case "fi":
- case "fr":
- case "sk":
- case "sv":
- return " ";
- default:
- return "";
- }
-};
diff --git a/src/ha/index.ts b/src/ha/index.ts
index 93065225d..b0ba350f6 100644
--- a/src/ha/index.ts
+++ b/src/ha/index.ts
@@ -1,19 +1,13 @@
export * from "./common/const";
-export * from "./common/datetime/format_date";
-export * from "./common/datetime/format_date_time";
-export * from "./common/datetime/format_time";
-export * from "./common/datetime/use_am_pm";
export * from "./common/dom/fire_event";
export * from "./common/dom/get_main_window";
export * from "./common/entity/compute_domain";
-export * from "./common/entity/compute_state_display";
export * from "./common/entity/compute_state_domain";
export * from "./common/entity/supports-feature";
export * from "./common/number/clamp";
export * from "./common/number/format_number";
export * from "./common/number/round";
export * from "./common/structs/handle-errors";
-export * from "./common/translations/blank_before_percent";
export * from "./common/translations/localize";
export * from "./common/util/compute_rtl";
export * from "./common/util/debounce";
diff --git a/src/ha/types.ts b/src/ha/types.ts
index 1b8282f24..5511dcc0f 100644
--- a/src/ha/types.ts
+++ b/src/ha/types.ts
@@ -224,7 +224,7 @@ export interface HomeAssistant {
formatEntityAttributeValue(
stateObj: HassEntity,
attribute: string,
- value?: string
+ value?: any
): string;
formatEntityAttributeName(stateObj: HassEntity, attribute: string): string;
}
diff --git a/src/shared/input-number.ts b/src/shared/input-number.ts
index baa7eca12..8bfd9bd6c 100644
--- a/src/shared/input-number.ts
+++ b/src/shared/input-number.ts
@@ -45,7 +45,7 @@ export class InputNumber extends LitElement {
@property({ type: Number })
public max?: number;
- @property({ attribute: "false" })
+ @property({ attribute: false })
public formatOptions: Intl.NumberFormatOptions = {};
@state() pending = false;
diff --git a/src/utils/base-card.ts b/src/utils/base-card.ts
index ed5e93b8d..f86e2b3ce 100644
--- a/src/utils/base-card.ts
+++ b/src/utils/base-card.ts
@@ -4,7 +4,6 @@ import { property, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import {
computeRTL,
- computeStateDisplay,
HomeAssistant,
isActive,
isAvailable,
@@ -293,15 +292,8 @@ export class MushroomBaseCard<
name: string,
state?: string
): TemplateResult | null {
- const defaultState = this.hass.formatEntityState
- ? this.hass.formatEntityState(stateObj)
- : computeStateDisplay(
- this.hass.localize,
- stateObj,
- this.hass.locale,
- this.hass.config,
- this.hass.entities
- );
+ const defaultState = this.hass.formatEntityState(stateObj);
+
const displayState = state ?? defaultState;
const primary = computeInfoDisplay(