fix: numerical states would not follow HA's format

Fix #662
This commit is contained in:
Jérôme Wiedemann 2023-07-24 23:37:49 +00:00
parent f79aded282
commit 72d7c4133f
3 changed files with 37 additions and 38 deletions

View File

@ -334,7 +334,13 @@ Inside the javascript code, you'll have access to those variables:
- `user`: The user object (equivalent to `hass.user`) - `user`: The user object (equivalent to `hass.user`)
- `hass`: The complete `hass` object - `hass`: The complete `hass` object
- `variables`: an object containing all your variables defined in the configuration. See [Variables](#variables) - `variables`: an object containing all your variables defined in the configuration. See [Variables](#variables)
- `localize(entity, state?)`: a function which localizes a state (eg. `localize(entity)`) and returns a string. Takes an entity object as argument (not the state of the entity as we need context) and takes an optional `state` string as argument. If `state` is not provided, it localizes the state of the `entity` (Eg. `localize(entity)` or `localize(states['weather.your_city'])`). If `state` is provided, it localizes `state` in the context of the `entity` (eg. : `localize(states['weather.your_city'], states['weather.your_city'].attributes.forecast[0].condition)`) - `localize(entity, state?, numeric_precision?, show_units?, units?)`: a function which localizes a state (eg. `localize(entity)`) and returns a string. Takes an entity object as argument (not the state of the entity as we need context) and takes optional arguments.
- If `state` is not provided, it localizes the state of the `entity` (Eg. `localize(entity)` or `localize(states['weather.your_city'])`).
- If `state` is provided, it localizes `state` in the context of the `entity` (eg. : `localize(entity, entity.attributes.forecast[0].condition)` or `localize(states['weather.your_city'], states['weather.your_city'].attributes.forecast[0].condition)`)
- `numeric_precision` (number): For state which are numbers, force the precision instead of letting HA decide for you
- `show_units` (boolean): Will display units or not. Default is to display them.
- `units` (string): Will force the units to be the value of that parameter.
- To skip one or multiple parameter while calling the function, use `undefined`. Eg. `localize(states['sensor.temperature'], undefined, 1, undefined, 'Celcius')`
- `formatDateTime(date)`, `formatShortDateTimeWithYear(date)`, `formatShortDateTime(date)`, `formatDateTimeWithSeconds(date)`, `formatDateTimeNumeric(date)`: Some helper functions to format a date time string or Date object. Name are pretty explicit. Example: `return formatDateTime(entity.attribute.last_changed)` - `formatDateTime(date)`, `formatShortDateTimeWithYear(date)`, `formatShortDateTime(date)`, `formatDateTimeWithSeconds(date)`, `formatDateTimeNumeric(date)`: Some helper functions to format a date time string or Date object. Name are pretty explicit. Example: `return formatDateTime(entity.attribute.last_changed)`
See [here](#templates-support) for some examples or [here](#custom-fields) for some crazy advanced stuff using templates! See [here](#templates-support) for some examples or [here](#custom-fields) for some crazy advanced stuff using templates!

View File

@ -294,7 +294,13 @@ class ButtonCard extends LitElement {
return retval; return retval;
} }
private _localize(stateObj: HassEntity, state?: string): string { private _localize(
stateObj: HassEntity,
state?: string,
numeric_precision?: number,
show_units = true,
units?: string,
): string {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
return computeStateDisplay( return computeStateDisplay(
this._hass!.localize, this._hass!.localize,
@ -302,7 +308,7 @@ class ButtonCard extends LitElement {
this._hass!.locale, this._hass!.locale,
this._hass!.config, this._hass!.config,
this._hass!.entities, this._hass!.entities,
this._config?.numeric_precision, { numeric_precision: numeric_precision || this._config?.numeric_precision, show_units, units },
state, state,
); );
} }
@ -543,10 +549,7 @@ class ButtonCard extends LitElement {
private _buildStateString(stateObj: HassEntity | undefined): string | undefined | null { private _buildStateString(stateObj: HassEntity | undefined): string | undefined | null {
let stateString: string | undefined | null; let stateString: string | undefined | null;
if (this._config!.show_state && stateObj && stateObj.state) { if (this._config!.show_state && stateObj && stateObj.state) {
const units = this._buildUnits(stateObj); if (computeDomain(stateObj.entity_id) === 'timer') {
if (units) {
stateString = `${stateObj.state} ${units}`;
} else if (computeDomain(stateObj.entity_id) === 'timer') {
if (stateObj.state === 'idle' || this._timeRemaining === 0) { if (stateObj.state === 'idle' || this._timeRemaining === 0) {
stateString = computeStateDisplay( stateString = computeStateDisplay(
this._hass!.localize, this._hass!.localize,
@ -554,7 +557,7 @@ class ButtonCard extends LitElement {
this._hass!.locale, this._hass!.locale,
this._hass!.config, this._hass!.config,
this._hass!.entities, this._hass!.entities,
this._config?.numeric_precision, this._config,
); );
} else { } else {
stateString = this._computeTimeDisplay(stateObj); stateString = this._computeTimeDisplay(stateObj);
@ -565,12 +568,10 @@ class ButtonCard extends LitElement {
this._hass!.locale, this._hass!.locale,
this._hass!.config, this._hass!.config,
this._hass!.entities, this._hass!.entities,
this._config?.numeric_precision, this._config,
)})`; )})`;
} }
} }
} else if (!this._config?.show_units && computeDomain(stateObj.entity_id) === 'sensor') {
stateString = stateObj.state;
} else { } else {
stateString = computeStateDisplay( stateString = computeStateDisplay(
this._hass!.localize, this._hass!.localize,
@ -578,27 +579,13 @@ class ButtonCard extends LitElement {
this._hass!.locale, this._hass!.locale,
this._hass!.config, this._hass!.config,
this._hass!.entities, this._hass!.entities,
this._config?.numeric_precision, this._config,
); );
} }
} }
return stateString; return stateString;
} }
private _buildUnits(state: HassEntity | undefined): string | undefined {
let units: string | undefined;
if (state) {
if (this._config!.show_units) {
if (state.attributes?.unit_of_measurement && !this._config!.units) {
units = state.attributes.unit_of_measurement;
} else {
units = this._config!.units ? this._config!.units : undefined;
}
}
}
return units;
}
private _buildLastChanged(state: HassEntity | undefined, style: StyleInfo): TemplateResult | undefined { private _buildLastChanged(state: HassEntity | undefined, style: StyleInfo): TemplateResult | undefined {
return this._config!.show_last_changed && state return this._config!.show_last_changed && state
? html` ? html`

View File

@ -14,6 +14,7 @@ import { formatDate } from './format_date';
import { formatTime } from './format_time'; import { formatTime } from './format_time';
import { UPDATE_SUPPORT_PROGRESS, updateIsInstallingFromAttributes } from './update'; import { UPDATE_SUPPORT_PROGRESS, updateIsInstallingFromAttributes } from './update';
import { supportsFeatureFromAttributes } from './supports-features'; import { supportsFeatureFromAttributes } from './supports-features';
import { ButtonCardConfig } from '../types/types';
const UNAVAILABLE = 'unavailable'; const UNAVAILABLE = 'unavailable';
const UNKNOWN = 'unknown'; const UNKNOWN = 'unknown';
@ -24,7 +25,7 @@ export const computeStateDisplaySingleEntity = (
locale: FrontendLocaleData, locale: FrontendLocaleData,
config: HassConfig, config: HassConfig,
entity: EntityRegistryDisplayEntry | undefined, entity: EntityRegistryDisplayEntry | undefined,
numeric_precision: number | undefined, buttonConfig: { numeric_precision?: number; show_units?: boolean; units?: string } | undefined,
state?: string, state?: string,
): string => ): string =>
computeStateDisplayFromEntityAttributes( computeStateDisplayFromEntityAttributes(
@ -34,7 +35,7 @@ export const computeStateDisplaySingleEntity = (
entity, entity,
stateObj.entity_id, stateObj.entity_id,
stateObj.attributes, stateObj.attributes,
numeric_precision, buttonConfig,
state !== undefined ? state : stateObj.state, state !== undefined ? state : stateObj.state,
); );
@ -44,7 +45,7 @@ export const computeStateDisplay = (
locale: FrontendLocaleData, locale: FrontendLocaleData,
config: HassConfig, config: HassConfig,
entities: HomeAssistant['entities'], entities: HomeAssistant['entities'],
numeric_precision: number | undefined, buttonConfig: { numeric_precision?: number; show_units?: boolean; units?: string } | undefined,
state?: string, state?: string,
): string => { ): string => {
const entity = entities[stateObj.entity_id] as EntityRegistryDisplayEntry | undefined; const entity = entities[stateObj.entity_id] as EntityRegistryDisplayEntry | undefined;
@ -56,7 +57,7 @@ export const computeStateDisplay = (
entity, entity,
stateObj.entity_id, stateObj.entity_id,
stateObj.attributes, stateObj.attributes,
numeric_precision, buttonConfig,
state !== undefined ? state : stateObj.state, state !== undefined ? state : stateObj.state,
); );
}; };
@ -68,7 +69,7 @@ export const computeStateDisplayFromEntityAttributes = (
entity: EntityRegistryDisplayEntry | undefined, entity: EntityRegistryDisplayEntry | undefined,
entityId: string, entityId: string,
attributes: any, attributes: any,
numeric_precision: number | undefined, buttonConfig: { numeric_precision?: number; show_units?: boolean; units?: string } | undefined,
state: string, state: string,
): string => { ): string => {
if (state === UNKNOWN || state === UNAVAILABLE) { if (state === UNKNOWN || state === UNAVAILABLE) {
@ -93,24 +94,29 @@ export const computeStateDisplayFromEntityAttributes = (
try { try {
return formatNumber(state, locale, { return formatNumber(state, locale, {
style: 'currency', style: 'currency',
currency: attributes.unit_of_measurement, currency: buttonConfig?.units || attributes.unit_of_measurement,
minimumFractionDigits: 2, minimumFractionDigits: 2,
// Override monetary options with number format // Override monetary options with number format
...getNumberFormatOptions({ state, attributes } as HassEntity, numeric_precision, entity), ...getNumberFormatOptions({ state, attributes } as HassEntity, buttonConfig?.numeric_precision, entity),
}); });
} catch (_err) { } catch (_err) {
// fallback to default // fallback to default
} }
} }
const unit = !attributes.unit_of_measurement const localOrConfigUnit = buttonConfig?.show_units
? buttonConfig?.units
? buttonConfig?.units
: attributes.unit_of_measurement
: undefined;
const unit = !localOrConfigUnit
? '' ? ''
: attributes.unit_of_measurement === '%' : localOrConfigUnit === '%'
? blankBeforePercent(locale) + '%' ? blankBeforePercent(locale) + '%'
: ` ${attributes.unit_of_measurement}`; : ` ${localOrConfigUnit}`;
return `${formatNumber( return `${formatNumber(
state, state,
locale, locale,
getNumberFormatOptions({ state, attributes } as HassEntity, numeric_precision, entity), getNumberFormatOptions({ state, attributes } as HassEntity, buttonConfig?.numeric_precision, entity),
)}${unit}`; )}${unit}`;
} }
@ -161,7 +167,7 @@ export const computeStateDisplayFromEntityAttributes = (
return formatNumber( return formatNumber(
state, state,
locale, locale,
getNumberFormatOptions({ state, attributes } as HassEntity, numeric_precision, entity), getNumberFormatOptions({ state, attributes } as HassEntity, buttonConfig?.numeric_precision, entity),
); );
} }