diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 7ace186bc7..9ac4eedf14 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -4,6 +4,8 @@ import { mdiDotsVertical, mdiFan, mdiFire, + mdiMinus, + mdiPlus, mdiPower, mdiSnowflake, mdiWaterPercent, @@ -16,10 +18,9 @@ import { html, LitElement, PropertyValues, - svg, TemplateResult, } from "lit"; -import { customElement, property, state, query } from "lit/decorators"; +import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import { UNIT_F } from "../../../common/const"; import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; @@ -27,11 +28,9 @@ import { fireEvent } from "../../../common/dom/fire_event"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { formatNumber } from "../../../common/number/format_number"; import "../../../components/ha-card"; -import type { HaCard } from "../../../components/ha-card"; import "../../../components/ha-icon-button"; import { ClimateEntity, - CLIMATE_PRESET_NONE, compareClimateHvacModes, HvacMode, } from "../../../data/climate"; @@ -84,8 +83,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { @state() private _setTemp?: number | number[]; - @query("ha-card") private _card?: HaCard; - public getCardSize(): number { return 7; } @@ -116,125 +113,97 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { const name = this._config!.name || computeStateName(this.hass!.states[this._config!.entity]); - const targetTemp = - stateObj.attributes.temperature !== null && - Number.isFinite(Number(stateObj.attributes.temperature)) - ? stateObj.attributes.temperature - : stateObj.attributes.min_temp; + // const targetTemp = + // stateObj.attributes.temperature !== null && + // Number.isFinite(Number(stateObj.attributes.temperature)) + // ? stateObj.attributes.temperature + // : stateObj.attributes.min_temp; - const slider = - stateObj.state === UNAVAILABLE - ? html` ` - : html` - - `; + // const currentTemperature = html` + // + // + // ${stateObj.attributes.current_temperature !== null && + // !isNaN(stateObj.attributes.current_temperature) + // ? html`${formatNumber( + // stateObj.attributes.current_temperature, + // this.hass.locale + // )} + // + // ${this.hass.config.unit_system.temperature} + // ` + // : ""} + // + // + // `; - const currentTemperature = svg` - - - ${ - stateObj.attributes.current_temperature !== null && - !isNaN(stateObj.attributes.current_temperature) - ? svg`${formatNumber( - stateObj.attributes.current_temperature, - this.hass.locale - )} - - ${this.hass.config.unit_system.temperature} - ` - : "" - } - - - `; - - const setValues = svg` - - - - ${ - stateObj.state === UNAVAILABLE - ? this.hass.localize("state.default.unavailable") - : this._setTemp === undefined || this._setTemp === null - ? "" - : Array.isArray(this._setTemp) - ? this._stepSize === 1 - ? svg` - ${formatNumber(this._setTemp[0], this.hass.locale, { - maximumFractionDigits: 0, - })} - - ${formatNumber(this._setTemp[1], this.hass.locale, { - maximumFractionDigits: 0, - })} - ` - : svg` - ${formatNumber(this._setTemp[0], this.hass.locale, { - minimumFractionDigits: 1, - maximumFractionDigits: 1, - })} - - ${formatNumber(this._setTemp[1], this.hass.locale, { - minimumFractionDigits: 1, - maximumFractionDigits: 1, - })} - ` - : this._stepSize === 1 - ? svg` - ${formatNumber(this._setTemp, this.hass.locale, { - maximumFractionDigits: 0, - })} - ` - : svg` - ${formatNumber(this._setTemp, this.hass.locale, { - minimumFractionDigits: 1, - maximumFractionDigits: 1, - })} - ` - } - - - ${ - stateObj.attributes.hvac_action - ? this.hass!.localize( - `state_attributes.climate.hvac_action.${stateObj.attributes.hvac_action}` - ) - : this.hass!.localize( - `component.climate.state._.${stateObj.state}` - ) - } - ${ - stateObj.attributes.preset_mode && - stateObj.attributes.preset_mode !== CLIMATE_PRESET_NONE - ? html` - - - ${this.hass!.localize( - `state_attributes.climate.preset_mode.${stateObj.attributes.preset_mode}` - ) || stateObj.attributes.preset_mode} - ` - : "" - } - - - - `; + // const setValues = html` + // + // + // ${stateObj.state === UNAVAILABLE + // ? this.hass.localize("state.default.unavailable") + // : this._setTemp === undefined || this._setTemp === null + // ? "" + // : Array.isArray(this._setTemp) + // ? this._stepSize === 1 + // ? html` + // ${formatNumber(this._setTemp[0], this.hass.locale, { + // maximumFractionDigits: 0, + // })} + // - + // ${formatNumber(this._setTemp[1], this.hass.locale, { + // maximumFractionDigits: 0, + // })} + // ` + // : html` + // ${formatNumber(this._setTemp[0], this.hass.locale, { + // minimumFractionDigits: 1, + // maximumFractionDigits: 1, + // })} + // - + // ${formatNumber(this._setTemp[1], this.hass.locale, { + // minimumFractionDigits: 1, + // maximumFractionDigits: 1, + // })} + // ` + // : this._stepSize === 1 + // ? html` + // ${formatNumber(this._setTemp, this.hass.locale, { + // maximumFractionDigits: 0, + // })} + // ` + // : html` + // ${formatNumber(this._setTemp, this.hass.locale, { + // minimumFractionDigits: 1, + // maximumFractionDigits: 1, + // })} + // `} + // + // + // ${stateObj.attributes.hvac_action + // ? this.hass!.localize( + // `state_attributes.climate.hvac_action.${stateObj.attributes.hvac_action}` + // ) + // : this.hass!.localize( + // `component.climate.state._.${stateObj.state}` + // )} + // ${stateObj.attributes.preset_mode && + // stateObj.attributes.preset_mode !== CLIMATE_PRESET_NONE + // ? html` + // - + // ${this.hass!.localize( + // `state_attributes.climate.preset_mode.${stateObj.attributes.preset_mode}` + // ) || stateObj.attributes.preset_mode} + // ` + // : ""} + // + // + // `; return html` +
+
+ ${stateObj.attributes.current_temperature !== null && + !isNaN(stateObj.attributes.current_temperature) + ? html` + + ${formatNumber( + stateObj.attributes.current_temperature, + this.hass.locale + )} + + ${this.hass.config.unit_system.temperature} + + + ` + : ""} + + ${stateObj.attributes.hvac_action + ? this.hass!.localize( + `state_attributes.climate.hvac_action.${stateObj.attributes.hvac_action}` + ) + : this.hass!.localize( + `component.climate.state._.${stateObj.state}` + )} + to + ${stateObj.state === UNAVAILABLE + ? this.hass.localize("state.default.unavailable") + : this._setTemp === undefined || this._setTemp === null + ? "" + : Array.isArray(this._setTemp) + ? this._stepSize === 1 + ? html` + ${formatNumber(this._setTemp[0], this.hass.locale, { + maximumFractionDigits: 0, + })} + - + ${formatNumber(this._setTemp[1], this.hass.locale, { + maximumFractionDigits: 0, + })} + ` + : html` + ${formatNumber(this._setTemp[0], this.hass.locale, { + minimumFractionDigits: 1, + maximumFractionDigits: 1, + })} + - + ${formatNumber(this._setTemp[1], this.hass.locale, { + minimumFractionDigits: 1, + maximumFractionDigits: 1, + })} + ` + : this._stepSize === 1 + ? html` + ${formatNumber(this._setTemp, this.hass.locale, { + maximumFractionDigits: 0, + })} + ` + : html` + ${formatNumber(this._setTemp, this.hass.locale, { + minimumFractionDigits: 1, + maximumFractionDigits: 1, + })} + `} +
+
+ + + + +
+
-
-
-
- ${slider} -
-
${currentTemperature} ${setValues}
-
-
-
-
-
- ${(stateObj.attributes.hvac_modes || []) - .concat() - .sort(compareClimateHvacModes) - .map((modeItem) => this._renderIcon(modeItem, mode))} -
- ${name} +
+
+ ${(stateObj.attributes.hvac_modes || []) + .concat() + .sort(compareClimateHvacModes) + .map((modeItem) => this._renderIcon(modeItem, mode))}
+ ${name}
`; @@ -303,15 +342,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } - - const stateObj = this.hass.states[this._config.entity]; - if (!stateObj) { - return; - } - - if (!oldHass || oldHass.states[this._config.entity] !== stateObj) { - this._rescale_svg(); - } } public willUpdate(changedProps: PropertyValues) { @@ -331,27 +361,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { } } - private _rescale_svg() { - // Set the viewbox of the SVG containing the set temperature to perfectly - // fit the text - // That way it will auto-scale correctly - // This is not done to the SVG containing the current temperature, because - // it should not be centered on the text, but only on the value - const card = this._card; - if (card) { - card.updateComplete.then(() => { - const svgRoot = this.shadowRoot!.querySelector("#set-values")!; - const box = svgRoot.querySelector("g")!.getBBox()!; - svgRoot.setAttribute( - "viewBox", - `${box.x} ${box!.y} ${box.width} ${box.height}` - ); - svgRoot.setAttribute("width", `${box.width}`); - svgRoot.setAttribute("height", `${box.height}`); - }); - } - } - private get _stepSize(): number { const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; @@ -381,18 +390,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { return stateObj.attributes.temperature; } - private _dragEvent(e): void { - const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; - - if (e.detail.low) { - this._setTemp = [e.detail.low, stateObj.attributes.target_temp_high]; - } else if (e.detail.high) { - this._setTemp = [stateObj.attributes.target_temp_low, e.detail.high]; - } else { - this._setTemp = e.detail.value; - } - } - private _setTemperature(e): void { const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; @@ -508,47 +505,49 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { justify-content: center; } - #controls { + .current-controls { display: flex; justify-content: center; + align-items: center; + } + + .current { + display: flex; + flex-direction: column; + align-items: center; + padding: 16px; + } + + .current-temp { + font-size: 64px; + font-weight: 300; + display: flex; + align-items: flex-start; + line-height: 0.8; + padding-bottom: 8px; + } + + .current-temp-unit { + font-size: 22px; + } + + .current-action { + font-size: 16px; + } + + .controls { + display: flex; + justify-content: space-between; padding: 16px; position: relative; + flex-direction: column; + min-height: 100px; } - #slider { - height: 100%; - width: 100%; - position: relative; - max-width: 250px; - min-width: 100px; - } - - round-slider { - --round-slider-path-color: var(--slider-track-color); - --round-slider-bar-color: var(--mode-color); - padding-bottom: 10%; - } - - #slider-center { - position: absolute; - width: calc(100% - 40px); - height: calc(100% - 40px); - box-sizing: border-box; - border-radius: 100%; - left: 20px; - top: 20px; - text-align: center; - overflow-wrap: break-word; - pointer-events: none; - } - - #temperature { - position: absolute; - transform: translate(-50%, -50%); - width: 100%; - height: 50%; - top: 45%; - left: 50%; + .controls ha-icon-button { + border: 1px solid var(--divider-color); + border-radius: 50%; + --mdc-icon-button-size: 36px; } #set-values { @@ -566,8 +565,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { display: flex-vertical; justify-content: center; text-align: center; - padding: 16px; - margin-top: -60px; + padding: 0 16px 16px 16px; font-size: var(--name-font-size); }