From 1b74ca47bf045f0ce3aae075c58eb7a7bbcf70c5 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 5 Dec 2023 16:42:07 +0100 Subject: [PATCH] Add target humidity feature (#18913) --- .../hui-target-humidity-card-feature.ts | 127 ++++++++++++++++++ src/panels/lovelace/card-features/types.ts | 5 + .../create-card-feature-element.ts | 2 + .../hui-card-features-editor.ts | 3 + src/translations/en.json | 3 + 5 files changed, 140 insertions(+) create mode 100644 src/panels/lovelace/card-features/hui-target-humidity-card-feature.ts diff --git a/src/panels/lovelace/card-features/hui-target-humidity-card-feature.ts b/src/panels/lovelace/card-features/hui-target-humidity-card-feature.ts new file mode 100644 index 0000000000..2f637d050b --- /dev/null +++ b/src/panels/lovelace/card-features/hui-target-humidity-card-feature.ts @@ -0,0 +1,127 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import { css, html, LitElement, nothing, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { computeDomain } from "../../../common/entity/compute_domain"; +import "../../../components/ha-control-slider"; +import { UNAVAILABLE } from "../../../data/entity"; +import { HumidifierEntity } from "../../../data/humidifier"; +import { HomeAssistant } from "../../../types"; +import { LovelaceCardFeature } from "../types"; +import { TargetHumidityCardFeatureConfig } from "./types"; + +export const supportsTargetHumidityCardFeature = (stateObj: HassEntity) => { + const domain = computeDomain(stateObj.entity_id); + return domain === "humidifier"; +}; + +@customElement("hui-target-humidity-card-feature") +class HuiTargetHumidityCardFeature + extends LitElement + implements LovelaceCardFeature +{ + @property({ attribute: false }) public hass?: HomeAssistant; + + @property({ attribute: false }) public stateObj?: HumidifierEntity; + + @state() private _config?: TargetHumidityCardFeatureConfig; + + @state() private _targetHumidity?: number; + + static getStubConfig(): TargetHumidityCardFeatureConfig { + return { + type: "target-humidity", + }; + } + + public setConfig(config: TargetHumidityCardFeatureConfig): void { + if (!config) { + throw new Error("Invalid configuration"); + } + this._config = config; + } + + protected willUpdate(changedProp: PropertyValues): void { + super.willUpdate(changedProp); + if (changedProp.has("stateObj")) { + this._targetHumidity = this.stateObj!.attributes.humidity; + } + } + + private get _step() { + return 1; + } + + private get _min() { + return this.stateObj!.attributes.min_humidity ?? 0; + } + + private get _max() { + return this.stateObj!.attributes.max_humidity ?? 100; + } + + private _valueChanged(ev: CustomEvent) { + const value = (ev.detail as any).value; + if (isNaN(value)) return; + this._targetHumidity = value; + this._callService(); + } + + private _callService() { + this.hass!.callService("humidifier", "set_humidity", { + entity_id: this.stateObj!.entity_id, + humidity: this._targetHumidity, + }); + } + + protected render() { + if ( + !this._config || + !this.hass || + !this.stateObj || + !supportsTargetHumidityCardFeature(this.stateObj) + ) { + return nothing; + } + + return html` +
+ +
+ `; + } + + static get styles() { + return css` + ha-control-slider { + --control-slider-color: var(--feature-color); + --control-slider-background: var(--feature-color); + --control-slider-background-opacity: 0.2; + --control-slider-thickness: 40px; + --control-slider-border-radius: 10px; + } + .container { + padding: 0 12px 12px 12px; + width: auto; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-target-humidity-card-feature": HuiTargetHumidityCardFeature; + } +} diff --git a/src/panels/lovelace/card-features/types.ts b/src/panels/lovelace/card-features/types.ts index bb28c6a14a..2cb4ff6c3a 100644 --- a/src/panels/lovelace/card-features/types.ts +++ b/src/panels/lovelace/card-features/types.ts @@ -55,6 +55,10 @@ export interface NumericInputCardFeatureConfig { style?: "buttons" | "slider"; } +export interface TargetHumidityCardFeatureConfig { + type: "target-humidity"; +} + export interface TargetTemperatureCardFeatureConfig { type: "target-temperature"; } @@ -106,6 +110,7 @@ export type LovelaceCardFeatureConfig = | LightBrightnessCardFeatureConfig | LightColorTempCardFeatureConfig | VacuumCommandsCardFeatureConfig + | TargetHumidityCardFeatureConfig | TargetTemperatureCardFeatureConfig | WaterHeaterOperationModesCardFeatureConfig | SelectOptionsCardFeatureConfig diff --git a/src/panels/lovelace/create-element/create-card-feature-element.ts b/src/panels/lovelace/create-element/create-card-feature-element.ts index 5f326cc5fb..960029ca8b 100644 --- a/src/panels/lovelace/create-element/create-card-feature-element.ts +++ b/src/panels/lovelace/create-element/create-card-feature-element.ts @@ -13,6 +13,7 @@ import "../card-features/hui-light-color-temp-card-feature"; import "../card-features/hui-numeric-input-card-feature"; import "../card-features/hui-select-options-card-feature"; import "../card-features/hui-target-temperature-card-feature"; +import "../card-features/hui-target-humidity-card-feature"; import "../card-features/hui-vacuum-commands-card-feature"; import "../card-features/hui-water-heater-operation-modes-card-feature"; import { LovelaceCardFeatureConfig } from "../card-features/types"; @@ -36,6 +37,7 @@ const TYPES: Set = new Set([ "light-color-temp", "numeric-input", "select-options", + "target-humidity", "target-temperature", "vacuum-commands", "water-heater-operation-modes", diff --git a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts index 0f0df3c87a..6eedd9816b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts @@ -35,6 +35,7 @@ import { supportsLightBrightnessCardFeature } from "../../card-features/hui-ligh import { supportsLightColorTempCardFeature } from "../../card-features/hui-light-color-temp-card-feature"; import { supportsNumericInputCardFeature } from "../../card-features/hui-numeric-input-card-feature"; import { supportsSelectOptionsCardFeature } from "../../card-features/hui-select-options-card-feature"; +import { supportsTargetHumidityCardFeature } from "../../card-features/hui-target-humidity-card-feature"; import { supportsTargetTemperatureCardFeature } from "../../card-features/hui-target-temperature-card-feature"; import { supportsVacuumCommandsCardFeature } from "../../card-features/hui-vacuum-commands-card-feature"; import { supportsWaterHeaterOperationModesCardFeature } from "../../card-features/hui-water-heater-operation-modes-card-feature"; @@ -58,6 +59,7 @@ const UI_FEATURE_TYPES = [ "light-brightness", "light-color-temp", "select-options", + "target-humidity", "target-temperature", "vacuum-commands", "water-heater-operation-modes", @@ -93,6 +95,7 @@ const SUPPORTS_FEATURE_TYPES: Record< "light-brightness": supportsLightBrightnessCardFeature, "light-color-temp": supportsLightColorTempCardFeature, "numeric-input": supportsNumericInputCardFeature, + "target-humidity": supportsTargetHumidityCardFeature, "target-temperature": supportsTargetTemperatureCardFeature, "vacuum-commands": supportsVacuumCommandsCardFeature, "water-heater-operation-modes": supportsWaterHeaterOperationModesCardFeature, diff --git a/src/translations/en.json b/src/translations/en.json index 3749321b72..66925e8255 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5308,6 +5308,9 @@ "target-temperature": { "label": "Target temperature" }, + "target-humidity": { + "label": "Target humidity" + }, "water-heater-operation-modes": { "label": "Water heater operation modes", "operation_modes": "Operation modes"