Skip to content

Commit

Permalink
Add climate preset tile feature (#17946)
Browse files Browse the repository at this point in the history
* Add climate preset tile feature

* Minor fixes

* Formatting fixes

* Update src/panels/lovelace/create-element/create-tile-feature-element.ts

* Update src/panels/lovelace/editor/config-elements/hui-tile-card-features-editor.ts

---------

Co-authored-by: Paul Bottein <[email protected]>
  • Loading branch information
Weissnix4711 and piitaya authored Sep 21, 2023
1 parent 6179c75 commit bf12eaa
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import "../tile-features/hui-alarm-modes-tile-feature";
import "../tile-features/hui-climate-hvac-modes-tile-feature";
import "../tile-features/hui-climate-presets-tile-feature";
import "../tile-features/hui-cover-open-close-tile-feature";
import "../tile-features/hui-cover-position-tile-feature";
import "../tile-features/hui-cover-tilt-position-tile-feature";
Expand All @@ -21,6 +22,7 @@ import {
const TYPES: Set<LovelaceTileFeatureConfig["type"]> = new Set([
"alarm-modes",
"climate-hvac-modes",
"climate-presets",
"cover-open-close",
"cover-position",
"cover-tilt-position",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { HomeAssistant } from "../../../../types";
import { getTileFeatureElementClass } from "../../create-element/create-tile-feature-element";
import { supportsAlarmModesTileFeature } from "../../tile-features/hui-alarm-modes-tile-feature";
import { supportsClimateHvacModesTileFeature } from "../../tile-features/hui-climate-hvac-modes-tile-feature";
import { supportsClimatePresetsTileFeature } from "../../tile-features/hui-climate-presets-tile-feature";
import { supportsCoverOpenCloseTileFeature } from "../../tile-features/hui-cover-open-close-tile-feature";
import { supportsCoverPositionTileFeature } from "../../tile-features/hui-cover-position-tile-feature";
import { supportsCoverTiltPositionTileFeature } from "../../tile-features/hui-cover-tilt-position-tile-feature";
Expand All @@ -47,6 +48,7 @@ type SupportsFeature = (stateObj: HassEntity) => boolean;
const FEATURE_TYPES: FeatureType[] = [
"alarm-modes",
"climate-hvac-modes",
"climate-presets",
"cover-open-close",
"cover-position",
"cover-tilt-position",
Expand All @@ -73,6 +75,7 @@ const SUPPORTS_FEATURE_TYPES: Record<FeatureType, SupportsFeature | undefined> =
{
"alarm-modes": supportsAlarmModesTileFeature,
"climate-hvac-modes": supportsClimateHvacModesTileFeature,
"climate-presets": supportsClimatePresetsTileFeature,
"cover-open-close": supportsCoverOpenCloseTileFeature,
"cover-position": supportsCoverPositionTileFeature,
"cover-tilt-position": supportsCoverTiltPositionTileFeature,
Expand Down
140 changes: 140 additions & 0 deletions src/panels/lovelace/tile-features/hui-climate-presets-tile-feature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { HassEntity } from "home-assistant-js-websocket";
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { stateColorCss } from "../../../common/entity/state_color";
import { ClimateEntity, computePresetModeIcon } from "../../../data/climate";
import { UNAVAILABLE } from "../../../data/entity";
import { HomeAssistant } from "../../../types";
import { LovelaceTileFeature } from "../types";
import { ClimatePresetsTileFeatureConfig } from "./types";
import type { ControlSelectOption } from "../../../components/ha-control-select";
import { computeDomain } from "../../../common/entity/compute_domain";
import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
import "../../../components/ha-control-select";
import "../../../components/ha-control-slider";

export const supportsClimatePresetsTileFeature = (stateObj: HassEntity) => {
const domain = computeDomain(stateObj.entity_id);
return domain === "climate";
};

@customElement("hui-climate-presets-tile-feature")
class HuiClimatePresetsTileFeature
extends LitElement
implements LovelaceTileFeature
{
@property({ attribute: false }) public hass?: HomeAssistant;

@property({ attribute: false }) public stateObj?: ClimateEntity;

@state() private _config?: ClimatePresetsTileFeatureConfig;

@state() _currentPreset?: string;

static getStubConfig(): ClimatePresetsTileFeatureConfig {
return {
type: "climate-presets",
};
}

public setConfig(config: ClimatePresetsTileFeatureConfig): void {
if (!config) {
throw new Error("Invalid configuration");
}
this._config = config;
}

protected willUpdate(changedProp: PropertyValues): void {
super.willUpdate(changedProp);
if (changedProp.has("stateObj") && this.stateObj) {
this._currentPreset = this.stateObj.attributes.preset_mode as string;
}
}

private async _valueChanged(ev: CustomEvent) {
const preset = (ev.detail as any).value as string;
const oldPreset = this.stateObj!.attributes.preset_mode;

if (preset === oldPreset) return;
this._currentPreset = preset;

try {
await this._setPreset(preset);
} catch (err) {
this._currentPreset = oldPreset;
}
}

private async _setPreset(preset: string) {
await this.hass!.callService("climate", "set_preset_mode", {
entity_id: this.stateObj!.entity_id,
preset_mode: preset,
});
}

protected render(): TemplateResult | null {
if (
!this._config ||
!this.hass ||
!this.stateObj ||
!supportsClimatePresetsTileFeature(this.stateObj)
) {
return null;
}

const color = stateColorCss(this.stateObj);

const presets = (this.stateObj.attributes.preset_modes as string[]) || [];

const options = presets.map<ControlSelectOption>((preset) => ({
value: preset,
label: this.hass!.formatEntityAttributeName(this.stateObj!, preset),
path: computePresetModeIcon(preset),
}));

return html`
<div class="container">
<ha-control-select
.options=${options}
.value=${this._currentPreset}
@value-changed=${this._valueChanged}
hide-label
.ariaLabel=${this.hass.localize("ui.card.climate.preset")}
style=${styleMap({
"--control-select-color": color,
})}
.disabled=${this.stateObj!.state === UNAVAILABLE}
>
</ha-control-select>
</div>
`;
}

static get styles() {
return css`
ha-control-select {
--control-select-color: var(--tile-color);
--control-select-padding: 0;
--control-select-thickness: 40px;
--control-select-border-radius: 10px;
--control-select-button-border-radius: 10px;
}
ha-control-button-group {
margin: 0 12px 12px 12px;
--control-button-group-spacing: 12px;
}
.container {
padding: 0 12px 12px 12px;
width: auto;
}
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"hui-climate-preset-tile-feature": HuiClimatePresetsTileFeature;
}
}
5 changes: 5 additions & 0 deletions src/panels/lovelace/tile-features/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export interface ClimateHvacModesTileFeatureConfig {
hvac_modes?: HvacMode[];
}

export interface ClimatePresetsTileFeatureConfig {
type: "climate-presets";
}

export interface SelectOptionsTileFeatureConfig {
type: "select-options";
}
Expand Down Expand Up @@ -80,6 +84,7 @@ export interface LawnMowerCommandsTileFeatureConfig {
export type LovelaceTileFeatureConfig =
| AlarmModesTileFeatureConfig
| ClimateHvacModesTileFeatureConfig
| ClimatePresetsTileFeatureConfig
| CoverOpenCloseTileFeatureConfig
| CoverPositionTileFeatureConfig
| CoverTiltPositionTileFeatureConfig
Expand Down
6 changes: 5 additions & 1 deletion src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@
"cooling": "{name} cooling",
"high": "high",
"low": "low",
"mode": "Mode"
"mode": "Mode",
"preset": "Preset"
},
"counter": {
"actions": {
Expand Down Expand Up @@ -5037,6 +5038,9 @@
"label": "Climate HVAC modes",
"hvac_modes": "HVAC modes"
},
"climate-presets": {
"label": "Climate Presets"
},
"target-temperature": {
"label": "Target temperature"
},
Expand Down

0 comments on commit bf12eaa

Please sign in to comment.