Add a feature to display any attribute of an entity in the Gauge Card (#25258)

* Add a feature to display any attribute of an entity in the Gauge Card

* Extract list of non numeric attributes into a constant and reuse it in number card as well as in numeric condition
This commit is contained in:
Volodymyr Honchar 2025-05-04 04:51:01 -07:00 committed by GitHub
parent 40fe62c2ec
commit 9983129e26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 101 additions and 72 deletions

View File

@ -107,3 +107,70 @@ export const DOMAIN_ATTRIBUTES_FORMATERS: Record<
}, },
}, },
}; };
export const NON_NUMERIC_ATTRIBUTES = [
"access_token",
"auto_update",
"available_modes",
"away_mode",
"changed_by",
"code_format",
"color_modes",
"current_activity",
"device_class",
"editable",
"effect_list",
"effect",
"entity_picture",
"event_type",
"event_types",
"fan_mode",
"fan_modes",
"fan_speed_list",
"forecast",
"friendly_name",
"frontend_stream_type",
"has_date",
"has_time",
"hs_color",
"hvac_mode",
"hvac_modes",
"icon",
"media_album_name",
"media_artist",
"media_content_type",
"media_position_updated_at",
"media_title",
"next_dawn",
"next_dusk",
"next_midnight",
"next_noon",
"next_rising",
"next_setting",
"operation_list",
"operation_mode",
"options",
"preset_mode",
"preset_modes",
"release_notes",
"release_summary",
"release_url",
"restored",
"rgb_color",
"rgbw_color",
"shuffle",
"sound_mode_list",
"sound_mode",
"source_list",
"source_type",
"source",
"state_class",
"supported_features",
"swing_mode",
"swing_mode",
"swing_modes",
"title",
"token",
"unit_of_measurement",
"xy_color",
];

View File

@ -18,6 +18,7 @@ import "../../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../../components/ha-form/types"; import type { SchemaUnion } from "../../../../../components/ha-form/types";
import type { NumericStateCondition } from "../../../../../data/automation"; import type { NumericStateCondition } from "../../../../../data/automation";
import type { HomeAssistant } from "../../../../../types"; import type { HomeAssistant } from "../../../../../types";
import { NON_NUMERIC_ATTRIBUTES } from "../../../../../data/entity_attributes";
const numericStateConditionStruct = object({ const numericStateConditionStruct = object({
alias: optional(string()), alias: optional(string()),
@ -85,72 +86,7 @@ export default class HaNumericStateCondition extends LitElement {
name: "attribute", name: "attribute",
selector: { selector: {
attribute: { attribute: {
hide_attributes: [ hide_attributes: NON_NUMERIC_ATTRIBUTES,
"access_token",
"auto_update",
"available_modes",
"away_mode",
"changed_by",
"code_format",
"color_modes",
"current_activity",
"device_class",
"editable",
"effect_list",
"effect",
"entity_picture",
"event_type",
"event_types",
"fan_mode",
"fan_modes",
"fan_speed_list",
"forecast",
"friendly_name",
"frontend_stream_type",
"has_date",
"has_time",
"hs_color",
"hvac_mode",
"hvac_modes",
"icon",
"media_album_name",
"media_artist",
"media_content_type",
"media_position_updated_at",
"media_title",
"next_dawn",
"next_dusk",
"next_midnight",
"next_noon",
"next_rising",
"next_setting",
"operation_list",
"operation_mode",
"options",
"preset_mode",
"preset_modes",
"release_notes",
"release_summary",
"release_url",
"restored",
"rgb_color",
"rgbw_color",
"shuffle",
"sound_mode_list",
"sound_mode",
"source_list",
"source_type",
"source",
"state_class",
"supported_features",
"swing_mode",
"swing_mode",
"swing_modes",
"title",
"token",
"unit_of_measurement",
"xy_color",
],
}, },
}, },
context: { context: {

View File

@ -109,12 +109,18 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
`; `;
} }
if (isNaN(entityState)) { const valueToDisplay = this._config.attribute
? stateObj.attributes[this._config.attribute]
: stateObj.state;
if (isNaN(valueToDisplay)) {
return html` return html`
<hui-warning <hui-warning
>${this.hass.localize( >${this.hass.localize(
"ui.panel.lovelace.warning.entity_non_numeric", this._config.attribute
{ entity: this._config.entity } ? "ui.panel.lovelace.warning.attribute_not_numeric"
: "ui.panel.lovelace.warning.entity_non_numeric",
{ entity: this._config.entity, attribute: this._config.attribute }
)}</hui-warning )}</hui-warning
> >
`; `;
@ -141,7 +147,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
<ha-gauge <ha-gauge
.min=${this._config.min!} .min=${this._config.min!}
.max=${this._config.max!} .max=${this._config.max!}
.value=${stateObj.state} .value=${valueToDisplay}
.formatOptions=${getNumberFormatOptions( .formatOptions=${getNumberFormatOptions(
stateObj, stateObj,
this.hass.entities[stateObj.entity_id] this.hass.entities[stateObj.entity_id]

View File

@ -233,6 +233,7 @@ export interface GaugeSegment {
export interface GaugeCardConfig extends LovelaceCardConfig { export interface GaugeCardConfig extends LovelaceCardConfig {
entity: string; entity: string;
attribute?: string;
name?: string; name?: string;
unit?: string; unit?: string;
min?: number; min?: number;

View File

@ -23,6 +23,7 @@ import type { UiAction } from "../../components/hui-action-editor";
import type { LovelaceCardEditor } from "../../types"; import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct"; import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { NON_NUMERIC_ATTRIBUTES } from "../../../../data/entity_attributes";
const TAP_ACTIONS: UiAction[] = [ const TAP_ACTIONS: UiAction[] = [
"more-info", "more-info",
@ -44,6 +45,7 @@ const cardConfigStruct = assign(
object({ object({
name: optional(string()), name: optional(string()),
entity: optional(string()), entity: optional(string()),
attribute: optional(string()),
unit: optional(string()), unit: optional(string()),
min: optional(number()), min: optional(number()),
max: optional(number()), max: optional(number()),
@ -76,7 +78,7 @@ export class HuiGaugeCardEditor
} }
private _schema = memoizeOne( private _schema = memoizeOne(
(showSeverity: boolean) => (showSeverity: boolean, entityId?: string) =>
[ [
{ {
name: "entity", name: "entity",
@ -86,6 +88,15 @@ export class HuiGaugeCardEditor
}, },
}, },
}, },
{
name: "attribute",
selector: {
attribute: {
entity_id: entityId,
hide_attributes: NON_NUMERIC_ATTRIBUTES,
},
},
},
{ {
name: "", name: "",
type: "grid", type: "grid",
@ -182,7 +193,10 @@ export class HuiGaugeCardEditor
return nothing; return nothing;
} }
const schema = this._schema(this._config!.severity !== undefined); const schema = this._schema(
this._config!.severity !== undefined,
this._config!.entity
);
const data = { const data = {
show_severity: this._config!.severity !== undefined, show_severity: this._config!.severity !== undefined,
...this._config, ...this._config,
@ -275,6 +289,10 @@ export class HuiGaugeCardEditor
)} (${this.hass!.localize( )} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional" "ui.panel.lovelace.editor.card.config.optional"
)})`; )})`;
case "attribute":
return this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.attribute"
);
default: default:
// "green" | "yellow" | "red" // "green" | "yellow" | "red"
return this.hass!.localize( return this.hass!.localize(

View File

@ -7828,6 +7828,7 @@
}, },
"warning": { "warning": {
"attribute_not_found": "Attribute {attribute} not available in: {entity}", "attribute_not_found": "Attribute {attribute} not available in: {entity}",
"attribute_not_numeric": "Attribute {attribute} is non-numeric",
"entity_not_found": "Entity not available: {entity}", "entity_not_found": "Entity not available: {entity}",
"entity_non_numeric": "Entity is non-numeric: {entity}", "entity_non_numeric": "Entity is non-numeric: {entity}",
"entity_unavailable": "Entity is currently unavailable: {entity}", "entity_unavailable": "Entity is currently unavailable: {entity}",