Merge 517943a40d
into cff54b73a4
This commit is contained in:
commit
142bb07162
|
@ -368,6 +368,7 @@ export class DemoEntityState extends LitElement {
|
|||
hass.localize,
|
||||
entry.stateObj,
|
||||
hass.locale,
|
||||
[], // numericDeviceClasses
|
||||
hass.config,
|
||||
hass.entities
|
||||
)}`,
|
||||
|
|
|
@ -19,28 +19,11 @@ import { blankBeforeUnit } from "../translations/blank_before_unit";
|
|||
import { LocalizeFunc } from "../translations/localize";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
|
||||
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,
|
||||
sensorNumericDeviceClasses: string[],
|
||||
config: HassConfig,
|
||||
entities: HomeAssistant["entities"],
|
||||
state?: string
|
||||
|
@ -52,6 +35,7 @@ export const computeStateDisplay = (
|
|||
return computeStateDisplayFromEntityAttributes(
|
||||
localize,
|
||||
locale,
|
||||
sensorNumericDeviceClasses,
|
||||
config,
|
||||
entity,
|
||||
stateObj.entity_id,
|
||||
|
@ -63,6 +47,7 @@ export const computeStateDisplay = (
|
|||
export const computeStateDisplayFromEntityAttributes = (
|
||||
localize: LocalizeFunc,
|
||||
locale: FrontendLocaleData,
|
||||
sensorNumericDeviceClasses: string[],
|
||||
config: HassConfig,
|
||||
entity: EntityRegistryDisplayEntry | undefined,
|
||||
entityId: string,
|
||||
|
@ -73,8 +58,15 @@ export const computeStateDisplayFromEntityAttributes = (
|
|||
return localize(`state.default.${state}`);
|
||||
}
|
||||
|
||||
const domain = computeDomain(entityId);
|
||||
|
||||
// Entities with a `unit_of_measurement` or `state_class` are numeric values and should use `formatNumber`
|
||||
if (isNumericFromAttributes(attributes)) {
|
||||
if (
|
||||
isNumericFromAttributes(
|
||||
attributes,
|
||||
domain === "sensor" ? sensorNumericDeviceClasses : []
|
||||
)
|
||||
) {
|
||||
// state is duration
|
||||
if (
|
||||
attributes.device_class === "duration" &&
|
||||
|
@ -120,8 +112,6 @@ export const computeStateDisplayFromEntityAttributes = (
|
|||
return value;
|
||||
}
|
||||
|
||||
const domain = computeDomain(entityId);
|
||||
|
||||
if (domain === "datetime") {
|
||||
const time = new Date(state);
|
||||
return formatDateTime(time, locale, config);
|
||||
|
|
|
@ -14,8 +14,12 @@ export const isNumericState = (stateObj: HassEntity): boolean =>
|
|||
isNumericFromAttributes(stateObj.attributes);
|
||||
|
||||
export const isNumericFromAttributes = (
|
||||
attributes: HassEntityAttributeBase
|
||||
): boolean => !!attributes.unit_of_measurement || !!attributes.state_class;
|
||||
attributes: HassEntityAttributeBase,
|
||||
numericDeviceClasses?: string[]
|
||||
): boolean =>
|
||||
!!attributes.unit_of_measurement ||
|
||||
!!attributes.state_class ||
|
||||
(numericDeviceClasses || []).includes(attributes.device_class || "");
|
||||
|
||||
export const numberFormatToLocale = (
|
||||
localeOptions: FrontendLocaleData
|
||||
|
|
|
@ -21,7 +21,8 @@ export const computeFormatFunctions = async (
|
|||
localize: LocalizeFunc,
|
||||
locale: FrontendLocaleData,
|
||||
config: HassConfig,
|
||||
entities: HomeAssistant["entities"]
|
||||
entities: HomeAssistant["entities"],
|
||||
sensorNumericDeviceClasses: string[]
|
||||
): Promise<{
|
||||
formatEntityState: FormatEntityStateFunc;
|
||||
formatEntityAttributeValue: FormatEntityAttributeValueFunc;
|
||||
|
@ -35,7 +36,15 @@ export const computeFormatFunctions = async (
|
|||
|
||||
return {
|
||||
formatEntityState: (stateObj, state) =>
|
||||
computeStateDisplay(localize, stateObj, locale, config, entities, state),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
locale,
|
||||
sensorNumericDeviceClasses,
|
||||
config,
|
||||
entities,
|
||||
state
|
||||
),
|
||||
formatEntityAttributeValue: (stateObj, attribute, value) =>
|
||||
computeAttributeValueDisplay(
|
||||
localize,
|
||||
|
|
|
@ -297,6 +297,7 @@ const processTimelineEntity = (
|
|||
state_localize: computeStateDisplayFromEntityAttributes(
|
||||
localize,
|
||||
locale,
|
||||
[], // numeric device classes not used for Timeline
|
||||
config,
|
||||
entities[entityId],
|
||||
entityId,
|
||||
|
|
|
@ -18,7 +18,9 @@ export type SensorNumericDeviceClasses = {
|
|||
numeric_device_classes: string[];
|
||||
};
|
||||
|
||||
let sensorNumericDeviceClassesCache: SensorNumericDeviceClasses | undefined;
|
||||
let sensorNumericDeviceClassesCache:
|
||||
| Promise<SensorNumericDeviceClasses>
|
||||
| undefined;
|
||||
|
||||
export const getSensorNumericDeviceClasses = async (
|
||||
hass: HomeAssistant
|
||||
|
@ -26,7 +28,7 @@ export const getSensorNumericDeviceClasses = async (
|
|||
if (sensorNumericDeviceClassesCache) {
|
||||
return sensorNumericDeviceClassesCache;
|
||||
}
|
||||
sensorNumericDeviceClassesCache = await hass.callWS({
|
||||
sensorNumericDeviceClassesCache = hass.callWS({
|
||||
type: "sensor/numeric_device_classes",
|
||||
});
|
||||
return sensorNumericDeviceClassesCache!;
|
||||
|
|
|
@ -119,7 +119,8 @@ export const provideHass = (
|
|||
hass().localize,
|
||||
hass().locale,
|
||||
hass().config,
|
||||
hass().entities
|
||||
hass().entities,
|
||||
[] // numericDeviceClasses
|
||||
);
|
||||
hass().updateHass({
|
||||
formatEntityState,
|
||||
|
|
|
@ -23,7 +23,6 @@ import { transform } from "../../../common/decorators/transform";
|
|||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateDisplaySingleEntity } from "../../../common/entity/compute_state_display";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import {
|
||||
|
@ -243,13 +242,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||
: ""}
|
||||
${this._config.show_state && stateObj
|
||||
? html`<span class="state">
|
||||
${computeStateDisplaySingleEntity(
|
||||
this._localize,
|
||||
stateObj,
|
||||
this._locale,
|
||||
this._hassConfig,
|
||||
this._entity
|
||||
)}
|
||||
${this.hass.formatEntityState(stateObj)}
|
||||
</span>`
|
||||
: ""}
|
||||
${this._shouldRenderRipple ? html`<mwc-ripple></mwc-ripple>` : ""}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||
import "../components/entity/state-info";
|
||||
import HassMediaPlayerEntity from "../util/hass-media-player-model";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
@ -26,7 +25,7 @@ class StateCardMediaPlayer extends LitElement {
|
|||
></state-info>
|
||||
<div class="state">
|
||||
<div class="main-text" take-height=${!playerObj.secondaryTitle}>
|
||||
${this._computePrimaryText(this.hass.localize, playerObj)}
|
||||
${this._computePrimaryText(playerObj)}
|
||||
</div>
|
||||
<div class="secondary-text">${playerObj.secondaryTitle}</div>
|
||||
</div>
|
||||
|
@ -34,16 +33,9 @@ class StateCardMediaPlayer extends LitElement {
|
|||
`;
|
||||
}
|
||||
|
||||
private _computePrimaryText(localize, playerObj) {
|
||||
private _computePrimaryText(playerObj) {
|
||||
return (
|
||||
playerObj.primaryTitle ||
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
playerObj.stateObj,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this.hass.entities
|
||||
)
|
||||
playerObj.primaryTitle || this.hass.formatEntityState(playerObj.stateObj)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { computeFormatFunctions } from "../common/translations/entity-state";
|
||||
import { getSensorNumericDeviceClasses } from "../data/sensor";
|
||||
import { Constructor, HomeAssistant } from "../types";
|
||||
import { HassBaseEl } from "./hass-base-mixin";
|
||||
|
||||
|
@ -31,6 +32,10 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) => {
|
|||
|
||||
private _updateStateDisplay = async () => {
|
||||
if (!this.hass) return;
|
||||
|
||||
const { numeric_device_classes: sensorNumericDeviceClasses } =
|
||||
await getSensorNumericDeviceClasses(this.hass);
|
||||
|
||||
const {
|
||||
formatEntityState,
|
||||
formatEntityAttributeName,
|
||||
|
@ -39,7 +44,8 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) => {
|
|||
this.hass.localize,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this.hass.entities
|
||||
this.hass.entities,
|
||||
sensorNumericDeviceClasses
|
||||
);
|
||||
this._updateHass({
|
||||
formatEntityState,
|
||||
|
|
|
@ -18,6 +18,8 @@ describe("computeStateDisplay", () => {
|
|||
const localize = (message, ...args) =>
|
||||
message + (args.length ? ": " + args.join(",") : "");
|
||||
|
||||
const numericDeviceClasses = [];
|
||||
|
||||
beforeEach(() => {
|
||||
localeData = {
|
||||
language: "en",
|
||||
|
@ -36,7 +38,14 @@ describe("computeStateDisplay", () => {
|
|||
attributes: {},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"component.binary_sensor.entity_component._.state.off"
|
||||
);
|
||||
});
|
||||
|
@ -50,7 +59,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"component.binary_sensor.state.moisture.off"
|
||||
);
|
||||
});
|
||||
|
@ -70,7 +86,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
altLocalize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"component.binary_sensor.state.invalid_device_class.off"
|
||||
);
|
||||
});
|
||||
|
@ -84,7 +107,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"123 m"
|
||||
);
|
||||
});
|
||||
|
@ -98,7 +128,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"1,234.5 m"
|
||||
);
|
||||
});
|
||||
|
@ -112,7 +149,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"1,234.5"
|
||||
);
|
||||
});
|
||||
|
@ -132,7 +176,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
altLocalize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"state.default.unknown"
|
||||
);
|
||||
});
|
||||
|
@ -152,7 +203,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
altLocalize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"state.default.unavailable"
|
||||
);
|
||||
});
|
||||
|
@ -172,7 +230,14 @@ describe("computeStateDisplay", () => {
|
|||
attributes: {},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
altLocalize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"component.sensor.entity_component._.state.custom_state"
|
||||
);
|
||||
});
|
||||
|
@ -194,14 +259,28 @@ describe("computeStateDisplay", () => {
|
|||
};
|
||||
it("Uses am/pm time format", () => {
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"November 18, 2017 at 11:12 PM"
|
||||
);
|
||||
});
|
||||
it("Uses 24h time format", () => {
|
||||
localeData.time_format = TimeFormat.twenty_four;
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"November 18, 2017 at 23:12"
|
||||
);
|
||||
});
|
||||
|
@ -223,7 +302,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"November 18, 2017"
|
||||
);
|
||||
});
|
||||
|
@ -246,14 +332,28 @@ describe("computeStateDisplay", () => {
|
|||
it("Uses am/pm time format", () => {
|
||||
localeData.time_format = TimeFormat.am_pm;
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"11:12 PM"
|
||||
);
|
||||
});
|
||||
it("Uses 24h time format", () => {
|
||||
localeData.time_format = TimeFormat.twenty_four;
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"23:12"
|
||||
);
|
||||
});
|
||||
|
@ -280,6 +380,7 @@ describe("computeStateDisplay", () => {
|
|||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{},
|
||||
"2021-07-04 15:40:03"
|
||||
|
@ -294,6 +395,7 @@ describe("computeStateDisplay", () => {
|
|||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{},
|
||||
"2021-07-04 15:40:03"
|
||||
|
@ -323,6 +425,7 @@ describe("computeStateDisplay", () => {
|
|||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{},
|
||||
"2021-07-04"
|
||||
|
@ -353,6 +456,7 @@ describe("computeStateDisplay", () => {
|
|||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{},
|
||||
"17:05:07"
|
||||
|
@ -367,6 +471,7 @@ describe("computeStateDisplay", () => {
|
|||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{},
|
||||
"17:05:07"
|
||||
|
@ -389,7 +494,14 @@ describe("computeStateDisplay", () => {
|
|||
attributes: {},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
altLocalize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"state.default.unavailable"
|
||||
);
|
||||
});
|
||||
|
@ -404,7 +516,14 @@ describe("computeStateDisplay", () => {
|
|||
attributes: {},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
|
||||
computeStateDisplay(
|
||||
altLocalize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
{}
|
||||
),
|
||||
"My Custom State"
|
||||
);
|
||||
});
|
||||
|
@ -422,7 +541,14 @@ describe("computeStateDisplay", () => {
|
|||
},
|
||||
};
|
||||
assert.strictEqual(
|
||||
computeStateDisplay(localize, stateObj, localeData, demoConfig, entities),
|
||||
computeStateDisplay(
|
||||
localize,
|
||||
stateObj,
|
||||
localeData,
|
||||
numericDeviceClasses,
|
||||
demoConfig,
|
||||
entities
|
||||
),
|
||||
"component.custom_integration.entity.sensor.custom_translation.state.custom_state"
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue