1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-02-15 07:25:54 +00:00

Support water_heater in thermostat card (#27096)

This commit is contained in:
karwosts
2025-09-22 13:16:11 -07:00
committed by GitHub
parent 3481f7e8be
commit 6760f4a2ae
3 changed files with 77 additions and 43 deletions

View File

@@ -10,8 +10,8 @@ import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import type { ClimateEntity } from "../../../data/climate";
import "../../../state-control/climate/ha-state-control-climate-temperature";
import "../../../state-control/water_heater/ha-state-control-water_heater-temperature";
import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
import type { LovelaceCardFeatureContext } from "../card-features/types";
@@ -23,6 +23,7 @@ import type {
LovelaceGridOptions,
} from "../types";
import type { ThermostatCardConfig } from "./types";
import { computeDomain } from "../../../common/entity/compute_domain";
@customElement("hui-thermostat-card")
export class HuiThermostatCard extends LitElement implements LovelaceCard {
@@ -69,8 +70,13 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
}
public setConfig(config: ThermostatCardConfig): void {
if (!config.entity || config.entity.split(".")[0] !== "climate") {
throw new Error("Specify an entity from within the climate domain");
if (
!config.entity ||
!["climate", "water_heater"].includes(config.entity.split(".")[0])
) {
throw new Error(
"Specify an entity from within the climate or water_heater domain"
);
}
this._config = config;
@@ -115,7 +121,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
if (!this.hass || !this._config) {
return nothing;
}
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
const stateObj = this.hass.states[this._config.entity];
if (!stateObj) {
return html`
@@ -124,6 +130,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
</hui-warning>
`;
}
const domain = computeDomain(stateObj.entity_id);
const name = this._config!.name || computeStateName(stateObj);
@@ -137,16 +144,26 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
<ha-card>
<p class="title">${name}</p>
<div class="container">
<ha-state-control-climate-temperature
style=${styleMap({
maxWidth: controlMaxWidth,
})}
prevent-interaction-on-scroll
.showCurrentAsPrimary=${this._config.show_current_as_primary}
show-secondary
.hass=${this.hass}
.stateObj=${stateObj}
></ha-state-control-climate-temperature>
${domain === "water_heater"
? html` <ha-state-control-water_heater-temperature
style=${styleMap({
maxWidth: controlMaxWidth,
})}
prevent-interaction-on-scroll
show-current
.hass=${this.hass}
.stateObj=${stateObj}
></ha-state-control-water_heater-temperature>`
: html` <ha-state-control-climate-temperature
style=${styleMap({
maxWidth: controlMaxWidth,
})}
prevent-interaction-on-scroll
.showCurrentAsPrimary=${this._config.show_current_as_primary}
show-secondary
.hass=${this.hass}
.stateObj=${stateObj}
></ha-state-control-climate-temperature>`}
</div>
<ha-icon-button
class="more-info"

View File

@@ -33,14 +33,18 @@ import type { EditDetailElementEvent, EditSubElementEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
import "./hui-card-features-editor";
import type { FeatureType } from "./hui-card-features-editor";
import { computeDomain } from "../../../../common/entity/compute_domain";
const COMPATIBLE_FEATURES_TYPES: FeatureType[] = [
"climate-hvac-modes",
"climate-preset-modes",
"climate-fan-modes",
"climate-swing-modes",
"climate-swing-horizontal-modes",
];
const COMPATIBLE_FEATURES_TYPES: Record<string, FeatureType[]> = {
climate: [
"climate-hvac-modes",
"climate-preset-modes",
"climate-fan-modes",
"climate-swing-modes",
"climate-swing-horizontal-modes",
],
water_heater: ["water-heater-operation-modes"],
};
const cardConfigStruct = assign(
baseLovelaceCardConfig,
@@ -53,24 +57,6 @@ const cardConfigStruct = assign(
})
);
const SCHEMA = [
{ name: "entity", selector: { entity: { domain: "climate" } } },
{
type: "grid",
name: "",
schema: [
{ name: "name", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
],
},
{
name: "show_current_as_primary",
selector: {
boolean: {},
},
},
] as const satisfies readonly HaFormSchema[];
@customElement("hui-thermostat-card-editor")
export class HuiThermostatCardEditor
extends LitElement
@@ -91,19 +77,48 @@ export class HuiThermostatCardEditor
})
);
private _schema = memoizeOne(
(domain: string) =>
[
{
name: "entity",
selector: { entity: { domain: ["climate", "water_heater"] } },
},
{
type: "grid",
name: "",
schema: [
{ name: "name", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
],
},
...(domain === "climate"
? [
{
name: "show_current_as_primary",
selector: {
boolean: {},
},
},
]
: []),
] as const satisfies readonly HaFormSchema[]
);
protected render() {
if (!this.hass || !this._config) {
return nothing;
}
const entityId = this._config.entity;
const domain = computeDomain(entityId);
const featureContext = this._featureContext(entityId);
return html`
<ha-form
.hass=${this.hass}
.data=${this._config}
.schema=${SCHEMA}
.schema=${this._schema(domain)}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged}
></ha-form>
@@ -118,7 +133,7 @@ export class HuiThermostatCardEditor
<hui-card-features-editor
.hass=${this.hass}
.context=${featureContext}
.featuresTypes=${COMPATIBLE_FEATURES_TYPES}
.featuresTypes=${COMPATIBLE_FEATURES_TYPES[domain]}
.features=${this._config!.features ?? []}
@features-changed=${this._featuresChanged}
@edit-detail-element=${this._editDetailElement}
@@ -177,7 +192,9 @@ export class HuiThermostatCardEditor
});
}
private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
if (schema.name === "show_current_as_primary") {
return this.hass!.localize(
"ui.panel.lovelace.editor.card.thermostat.show_current_as_primary"

View File

@@ -7924,7 +7924,7 @@
},
"thermostat": {
"name": "Thermostat",
"description": "The Thermostat card gives control of a climate entity for heating or cooling, allowing you to set its mode and desired temperature.",
"description": "The Thermostat card gives control of a climate or water heater entity for heating or cooling, allowing you to set its mode and desired temperature.",
"show_current_as_primary": "Show current temperature as primary information"
},
"tile": {