mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-08 09:56:36 +00:00
Migrate for climate 1.0 (#3333)
* Migrate for climate 1.0 * Update demo * Fix gallery * Add preset to thermostat card * Fix climate entity row
This commit is contained in:
parent
0a8703ad0a
commit
4fdbec93b3
@ -94,22 +94,19 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
target_temp_high: 24,
|
target_temp_high: 24,
|
||||||
target_temp_low: 20,
|
target_temp_low: 20,
|
||||||
fan_mode: "auto",
|
fan_mode: "auto",
|
||||||
fan_list: ["auto", "on"],
|
fan_modes: ["auto", "on"],
|
||||||
operation_mode: "auto",
|
hvac_modes: ["auto", "cool", "heat", "off"],
|
||||||
operation_list: ["auto", "auxHeatOnly", "cool", "heat", "off"],
|
|
||||||
hold_mode: null,
|
|
||||||
away_mode: "off",
|
|
||||||
aux_heat: "off",
|
aux_heat: "off",
|
||||||
actual_humidity: 30,
|
actual_humidity: 30,
|
||||||
fan: "on",
|
fan: "on",
|
||||||
climate_mode: "Day",
|
|
||||||
operation: "fan",
|
operation: "fan",
|
||||||
climate_list: ["Away", "Sleep", "Day", "Home"],
|
|
||||||
fan_min_on_time: 10,
|
fan_min_on_time: 10,
|
||||||
friendly_name: localize(
|
friendly_name: localize(
|
||||||
"ui.panel.page-demo.config.arsaboo.names.upstairs"
|
"ui.panel.page-demo.config.arsaboo.names.upstairs"
|
||||||
),
|
),
|
||||||
supported_features: 3575,
|
supported_features: 27,
|
||||||
|
preset_mode: "away",
|
||||||
|
preset_modes: ["home", "away", "eco", "sleep"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"input_boolean.abodeupdate": {
|
"input_boolean.abodeupdate": {
|
||||||
|
@ -14,14 +14,14 @@ const ENTITIES = [
|
|||||||
target_temp_high: 75,
|
target_temp_high: 75,
|
||||||
target_temp_low: 70,
|
target_temp_low: 70,
|
||||||
fan_mode: "Auto Low",
|
fan_mode: "Auto Low",
|
||||||
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||||
operation_mode: "auto",
|
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||||
operation_list: ["heat", "cool", "auto", "off"],
|
|
||||||
hold_mode: "home",
|
|
||||||
swing_mode: "Auto",
|
swing_mode: "Auto",
|
||||||
swing_list: ["Auto", "1", "2", "3", "Off"],
|
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||||
friendly_name: "Ecobee",
|
friendly_name: "Ecobee",
|
||||||
supported_features: 1014,
|
supported_features: 59,
|
||||||
|
preset_mode: "eco",
|
||||||
|
preset_modes: ["away", "eco"],
|
||||||
}),
|
}),
|
||||||
getEntity("climate", "nest", "heat", {
|
getEntity("climate", "nest", "heat", {
|
||||||
current_temperature: 17,
|
current_temperature: 17,
|
||||||
@ -29,14 +29,12 @@ const ENTITIES = [
|
|||||||
max_temp: 25,
|
max_temp: 25,
|
||||||
temperature: 19,
|
temperature: 19,
|
||||||
fan_mode: "Auto Low",
|
fan_mode: "Auto Low",
|
||||||
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||||
operation_mode: "heat",
|
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||||
operation_list: ["heat", "cool", "auto", "off"],
|
|
||||||
hold_mode: "home",
|
|
||||||
swing_mode: "Auto",
|
swing_mode: "Auto",
|
||||||
swing_list: ["Auto", "1", "2", "3", "Off"],
|
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||||
friendly_name: "Nest",
|
friendly_name: "Nest",
|
||||||
supported_features: 1014,
|
supported_features: 43,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class HaGallery extends PolymerElement {
|
|||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
a paper-item {
|
a {
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@ -138,12 +138,22 @@ class HaGallery extends PolymerElement {
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</app-header-layout>
|
</app-header-layout>
|
||||||
<notification-manager id='notifications'></notification-manager>
|
<notification-manager hass=[[_fakeHass]] id='notifications'></notification-manager>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
|
_fakeHass: {
|
||||||
|
type: Object,
|
||||||
|
// Just enough for computeRTL
|
||||||
|
value: {
|
||||||
|
language: "en",
|
||||||
|
translationMetadata: {
|
||||||
|
translations: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
_demo: {
|
_demo: {
|
||||||
type: String,
|
type: String,
|
||||||
value: document.location.hash.substr(1),
|
value: document.location.hash.substr(1),
|
||||||
|
@ -44,8 +44,8 @@ module.exports = {
|
|||||||
to: "static/images/leaflet/",
|
to: "static/images/leaflet/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: "../node_modules/@polymer/font-roboto-local/fonts",
|
from: "../node_modules/roboto-fontface/fonts/roboto/*.woff2",
|
||||||
to: "static/fonts",
|
to: "static/fonts/roboto/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: "../node_modules/leaflet/dist/images",
|
from: "../node_modules/leaflet/dist/images",
|
||||||
|
@ -38,7 +38,12 @@ class HaClimateState extends LocalizeMixin(PolymerElement) {
|
|||||||
|
|
||||||
<div class="target">
|
<div class="target">
|
||||||
<template is="dom-if" if="[[_hasKnownState(stateObj.state)]]">
|
<template is="dom-if" if="[[_hasKnownState(stateObj.state)]]">
|
||||||
<span class="state-label"> [[_localizeState(stateObj.state)]] </span>
|
<span class="state-label">
|
||||||
|
[[_localizeState(localize, stateObj.state)]]
|
||||||
|
<template is="dom-if" if="[[stateObj.attributes.preset_mode]]">
|
||||||
|
- [[_localizePreset(localize, stateObj.attributes.preset_mode)]]
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<div class="unit">[[computeTarget(hass, stateObj)]]</div>
|
<div class="unit">[[computeTarget(hass, stateObj)]]</div>
|
||||||
</div>
|
</div>
|
||||||
@ -111,8 +116,12 @@ class HaClimateState extends LocalizeMixin(PolymerElement) {
|
|||||||
return state !== "unknown";
|
return state !== "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
_localizeState(state) {
|
_localizeState(localize, state) {
|
||||||
return this.localize(`state.climate.${state}`) || state;
|
return localize(`state.climate.${state}`) || state;
|
||||||
|
}
|
||||||
|
|
||||||
|
_localizePreset(localize, preset) {
|
||||||
|
return localize(`state_attributes.climate.preset_mode.${preset}`) || preset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("ha-climate-state", HaClimateState);
|
customElements.define("ha-climate-state", HaClimateState);
|
||||||
|
51
src/data/climate.ts
Normal file
51
src/data/climate.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import {
|
||||||
|
HassEntityBase,
|
||||||
|
HassEntityAttributeBase,
|
||||||
|
} from "home-assistant-js-websocket";
|
||||||
|
|
||||||
|
export type HvacMode =
|
||||||
|
| "off"
|
||||||
|
| "heat"
|
||||||
|
| "cool"
|
||||||
|
| "heat_cool"
|
||||||
|
| "auto"
|
||||||
|
| "dry"
|
||||||
|
| "fan_only";
|
||||||
|
|
||||||
|
export type HvacAction = "off" | "Heating" | "cooling" | "drying" | "idle";
|
||||||
|
|
||||||
|
export type ClimateEntity = HassEntityBase & {
|
||||||
|
attributes: HassEntityAttributeBase & {
|
||||||
|
hvac_mode: HvacMode;
|
||||||
|
hvac_modes: HvacMode[];
|
||||||
|
hvac_action?: HvacAction;
|
||||||
|
current_temperature: number;
|
||||||
|
min_temp: number;
|
||||||
|
max_temp: number;
|
||||||
|
temperature: number;
|
||||||
|
target_temp_step?: number;
|
||||||
|
target_temp_high?: number;
|
||||||
|
target_temp_low?: number;
|
||||||
|
humidity?: number;
|
||||||
|
current_humidity?: number;
|
||||||
|
target_humidity_low?: number;
|
||||||
|
target_humidity_high?: number;
|
||||||
|
min_humidity?: number;
|
||||||
|
max_humidity?: number;
|
||||||
|
fan_mode?: string;
|
||||||
|
fan_modes?: string[];
|
||||||
|
preset_mode?: string;
|
||||||
|
preset_modes?: string[];
|
||||||
|
swing_mode?: string;
|
||||||
|
swing_modes?: string[];
|
||||||
|
aux_heat?: "on" | "off";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CLIMATE_SUPPORT_TARGET_TEMPERATURE = 1;
|
||||||
|
export const CLIMATE_SUPPORT_TARGET_TEMPERATURE_RANGE = 2;
|
||||||
|
export const CLIMATE_SUPPORT_TARGET_HUMIDITY = 4;
|
||||||
|
export const CLIMATE_SUPPORT_FAN_MODE = 8;
|
||||||
|
export const CLIMATE_SUPPORT_PRESET_MODE = 16;
|
||||||
|
export const CLIMATE_SUPPORT_SWING_MODE = 32;
|
||||||
|
export const CLIMATE_SUPPORT_AUX_HEAT = 64;
|
@ -1,533 +0,0 @@
|
|||||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
|
||||||
import "@polymer/paper-item/paper-item";
|
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
|
||||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
|
||||||
import { timeOut } from "@polymer/polymer/lib/utils/async";
|
|
||||||
import { Debouncer } from "@polymer/polymer/lib/utils/debounce";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
|
|
||||||
import "../../../components/ha-climate-control";
|
|
||||||
import "../../../components/ha-paper-slider";
|
|
||||||
import "../../../components/ha-paper-dropdown-menu";
|
|
||||||
|
|
||||||
import attributeClassNames from "../../../common/entity/attribute_class_names";
|
|
||||||
import featureClassNames from "../../../common/entity/feature_class_names";
|
|
||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
|
||||||
|
|
||||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
|
||||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @appliesMixin EventsMixin
|
|
||||||
* @appliesMixin LocalizeMixin
|
|
||||||
*/
|
|
||||||
class MoreInfoClimate extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style include="iron-flex"></style>
|
|
||||||
<style>
|
|
||||||
:host {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-on,
|
|
||||||
.container-away_mode,
|
|
||||||
.container-aux_heat,
|
|
||||||
.container-temperature,
|
|
||||||
.container-humidity,
|
|
||||||
.container-operation_list,
|
|
||||||
.container-fan_list,
|
|
||||||
.container-swing_list {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.has-on .container-on,
|
|
||||||
.has-away_mode .container-away_mode,
|
|
||||||
.has-aux_heat .container-aux_heat,
|
|
||||||
.has-target_temperature .container-temperature,
|
|
||||||
.has-target_temperature_low .container-temperature,
|
|
||||||
.has-target_temperature_high .container-temperature,
|
|
||||||
.has-target_humidity .container-humidity,
|
|
||||||
.has-operation_mode .container-operation_list,
|
|
||||||
.has-fan_mode .container-fan_list,
|
|
||||||
.has-swing_list .container-swing_list,
|
|
||||||
.has-swing_mode .container-swing_list {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-operation_list iron-icon,
|
|
||||||
.container-fan_list iron-icon,
|
|
||||||
.container-swing_list iron-icon {
|
|
||||||
margin: 22px 16px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-paper-dropdown-menu {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-item {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-paper-slider {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-humidity .single-row {
|
|
||||||
display: flex;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.target-humidity {
|
|
||||||
width: 90px;
|
|
||||||
font-size: 200%;
|
|
||||||
margin: auto;
|
|
||||||
direction: ltr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-climate-control.range-control-left,
|
|
||||||
ha-climate-control.range-control-right {
|
|
||||||
float: left;
|
|
||||||
width: 46%;
|
|
||||||
}
|
|
||||||
ha-climate-control.range-control-left {
|
|
||||||
margin-right: 4%;
|
|
||||||
}
|
|
||||||
ha-climate-control.range-control-right {
|
|
||||||
margin-left: 4%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.humidity {
|
|
||||||
--paper-slider-active-color: var(--paper-blue-400);
|
|
||||||
--paper-slider-secondary-color: var(--paper-blue-400);
|
|
||||||
}
|
|
||||||
|
|
||||||
.single-row {
|
|
||||||
padding: 8px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class$="[[computeClassNames(stateObj)]]">
|
|
||||||
<template is="dom-if" if="[[supportsOn(stateObj)]]">
|
|
||||||
<div class="container-on">
|
|
||||||
<div class="center horizontal layout single-row">
|
|
||||||
<div class="flex">[[localize('ui.card.climate.on_off')]]</div>
|
|
||||||
<paper-toggle-button
|
|
||||||
checked="[[onToggleChecked]]"
|
|
||||||
on-change="onToggleChanged"
|
|
||||||
>
|
|
||||||
</paper-toggle-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="container-temperature">
|
|
||||||
<div class$="[[stateObj.attributes.operation_mode]]">
|
|
||||||
<div hidden$="[[!supportsTemperatureControls(stateObj)]]">
|
|
||||||
[[localize('ui.card.climate.target_temperature')]]
|
|
||||||
</div>
|
|
||||||
<template is="dom-if" if="[[supportsTemperature(stateObj)]]">
|
|
||||||
<ha-climate-control
|
|
||||||
value="[[stateObj.attributes.temperature]]"
|
|
||||||
units="[[hass.config.unit_system.temperature]]"
|
|
||||||
step="[[computeTemperatureStepSize(hass, stateObj)]]"
|
|
||||||
min="[[stateObj.attributes.min_temp]]"
|
|
||||||
max="[[stateObj.attributes.max_temp]]"
|
|
||||||
on-change="targetTemperatureChanged"
|
|
||||||
>
|
|
||||||
</ha-climate-control>
|
|
||||||
</template>
|
|
||||||
<template is="dom-if" if="[[supportsTemperatureRange(stateObj)]]">
|
|
||||||
<ha-climate-control
|
|
||||||
value="[[stateObj.attributes.target_temp_low]]"
|
|
||||||
units="[[hass.config.unit_system.temperature]]"
|
|
||||||
step="[[computeTemperatureStepSize(hass, stateObj)]]"
|
|
||||||
min="[[stateObj.attributes.min_temp]]"
|
|
||||||
max="[[stateObj.attributes.target_temp_high]]"
|
|
||||||
class="range-control-left"
|
|
||||||
on-change="targetTemperatureLowChanged"
|
|
||||||
>
|
|
||||||
</ha-climate-control>
|
|
||||||
<ha-climate-control
|
|
||||||
value="[[stateObj.attributes.target_temp_high]]"
|
|
||||||
units="[[hass.config.unit_system.temperature]]"
|
|
||||||
step="[[computeTemperatureStepSize(hass, stateObj)]]"
|
|
||||||
min="[[stateObj.attributes.target_temp_low]]"
|
|
||||||
max="[[stateObj.attributes.max_temp]]"
|
|
||||||
class="range-control-right"
|
|
||||||
on-change="targetTemperatureHighChanged"
|
|
||||||
>
|
|
||||||
</ha-climate-control>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template is="dom-if" if="[[supportsHumidity(stateObj)]]">
|
|
||||||
<div class="container-humidity">
|
|
||||||
<div>[[localize('ui.card.climate.target_humidity')]]</div>
|
|
||||||
<div class="single-row">
|
|
||||||
<div class="target-humidity">
|
|
||||||
[[stateObj.attributes.humidity]] %
|
|
||||||
</div>
|
|
||||||
<ha-paper-slider
|
|
||||||
class="humidity"
|
|
||||||
min="[[stateObj.attributes.min_humidity]]"
|
|
||||||
max="[[stateObj.attributes.max_humidity]]"
|
|
||||||
secondary-progress="[[stateObj.attributes.max_humidity]]"
|
|
||||||
step="1"
|
|
||||||
pin=""
|
|
||||||
value="[[stateObj.attributes.humidity]]"
|
|
||||||
on-change="targetHumiditySliderChanged"
|
|
||||||
ignore-bar-touch=""
|
|
||||||
dir="[[rtl]]"
|
|
||||||
>
|
|
||||||
</ha-paper-slider>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template is="dom-if" if="[[supportsOperationMode(stateObj)]]">
|
|
||||||
<div class="container-operation_list">
|
|
||||||
<div class="controls">
|
|
||||||
<ha-paper-dropdown-menu
|
|
||||||
label-float=""
|
|
||||||
dynamic-align=""
|
|
||||||
label="[[localize('ui.card.climate.operation')]]"
|
|
||||||
>
|
|
||||||
<paper-listbox
|
|
||||||
slot="dropdown-content"
|
|
||||||
selected="[[stateObj.attributes.operation_mode]]"
|
|
||||||
attr-for-selected="item-name"
|
|
||||||
on-selected-changed="handleOperationmodeChanged"
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
is="dom-repeat"
|
|
||||||
items="[[stateObj.attributes.operation_list]]"
|
|
||||||
>
|
|
||||||
<paper-item item-name$="[[item]]"
|
|
||||||
>[[_localizeOperationMode(localize, item)]]</paper-item
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</paper-listbox>
|
|
||||||
</ha-paper-dropdown-menu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template is="dom-if" if="[[supportsFanMode(stateObj)]]">
|
|
||||||
<div class="container-fan_list">
|
|
||||||
<ha-paper-dropdown-menu
|
|
||||||
label-float=""
|
|
||||||
dynamic-align=""
|
|
||||||
label="[[localize('ui.card.climate.fan_mode')]]"
|
|
||||||
>
|
|
||||||
<paper-listbox
|
|
||||||
slot="dropdown-content"
|
|
||||||
selected="[[stateObj.attributes.fan_mode]]"
|
|
||||||
attr-for-selected="item-name"
|
|
||||||
on-selected-changed="handleFanmodeChanged"
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
is="dom-repeat"
|
|
||||||
items="[[stateObj.attributes.fan_list]]"
|
|
||||||
>
|
|
||||||
<paper-item item-name$="[[item]]"
|
|
||||||
>[[_localizeFanMode(localize, item)]]
|
|
||||||
</paper-item>
|
|
||||||
</template>
|
|
||||||
</paper-listbox>
|
|
||||||
</ha-paper-dropdown-menu>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template is="dom-if" if="[[supportsSwingMode(stateObj)]]">
|
|
||||||
<div class="container-swing_list">
|
|
||||||
<ha-paper-dropdown-menu
|
|
||||||
label-float=""
|
|
||||||
dynamic-align=""
|
|
||||||
label="[[localize('ui.card.climate.swing_mode')]]"
|
|
||||||
>
|
|
||||||
<paper-listbox
|
|
||||||
slot="dropdown-content"
|
|
||||||
selected="[[stateObj.attributes.swing_mode]]"
|
|
||||||
attr-for-selected="item-name"
|
|
||||||
on-selected-changed="handleSwingmodeChanged"
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
is="dom-repeat"
|
|
||||||
items="[[stateObj.attributes.swing_list]]"
|
|
||||||
>
|
|
||||||
<paper-item item-name$="[[item]]">[[item]]</paper-item>
|
|
||||||
</template>
|
|
||||||
</paper-listbox>
|
|
||||||
</ha-paper-dropdown-menu>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template is="dom-if" if="[[supportsAwayMode(stateObj)]]">
|
|
||||||
<div class="container-away_mode">
|
|
||||||
<div class="center horizontal layout single-row">
|
|
||||||
<div class="flex">[[localize('ui.card.climate.away_mode')]]</div>
|
|
||||||
<paper-toggle-button
|
|
||||||
checked="[[awayToggleChecked]]"
|
|
||||||
on-change="awayToggleChanged"
|
|
||||||
>
|
|
||||||
</paper-toggle-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template is="dom-if" if="[[supportsAuxHeat(stateObj)]]">
|
|
||||||
<div class="container-aux_heat">
|
|
||||||
<div class="center horizontal layout single-row">
|
|
||||||
<div class="flex">[[localize('ui.card.climate.aux_heat')]]</div>
|
|
||||||
<paper-toggle-button
|
|
||||||
checked="[[auxToggleChecked]]"
|
|
||||||
on-change="auxToggleChanged"
|
|
||||||
>
|
|
||||||
</paper-toggle-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: "stateObjChanged",
|
|
||||||
},
|
|
||||||
|
|
||||||
awayToggleChecked: Boolean,
|
|
||||||
auxToggleChecked: Boolean,
|
|
||||||
onToggleChecked: Boolean,
|
|
||||||
|
|
||||||
rtl: {
|
|
||||||
type: String,
|
|
||||||
value: "ltr",
|
|
||||||
computed: "_computeRTLDirection(hass)",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
stateObjChanged(newVal, oldVal) {
|
|
||||||
if (newVal) {
|
|
||||||
this.setProperties({
|
|
||||||
awayToggleChecked: newVal.attributes.away_mode === "on",
|
|
||||||
auxToggleChecked: newVal.attributes.aux_heat === "on",
|
|
||||||
onToggleChecked: newVal.state !== "off",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldVal) {
|
|
||||||
this._debouncer = Debouncer.debounce(
|
|
||||||
this._debouncer,
|
|
||||||
timeOut.after(500),
|
|
||||||
() => {
|
|
||||||
this.fire("iron-resize");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
computeTemperatureStepSize(hass, stateObj) {
|
|
||||||
if (stateObj.attributes.target_temp_step) {
|
|
||||||
return stateObj.attributes.target_temp_step;
|
|
||||||
}
|
|
||||||
if (hass.config.unit_system.temperature.indexOf("F") !== -1) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsTemperatureControls(stateObj) {
|
|
||||||
return (
|
|
||||||
this.supportsTemperature(stateObj) ||
|
|
||||||
this.supportsTemperatureRange(stateObj)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsTemperature(stateObj) {
|
|
||||||
return (
|
|
||||||
supportsFeature(stateObj, 1) &&
|
|
||||||
typeof stateObj.attributes.temperature === "number"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsTemperatureRange(stateObj) {
|
|
||||||
return (
|
|
||||||
supportsFeature(stateObj, 6) &&
|
|
||||||
(typeof stateObj.attributes.target_temp_low === "number" ||
|
|
||||||
typeof stateObj.attributes.target_temp_high === "number")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsHumidity(stateObj) {
|
|
||||||
return supportsFeature(stateObj, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsFanMode(stateObj) {
|
|
||||||
return supportsFeature(stateObj, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsOperationMode(stateObj) {
|
|
||||||
return supportsFeature(stateObj, 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsSwingMode(stateObj) {
|
|
||||||
return supportsFeature(stateObj, 512);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsAwayMode(stateObj) {
|
|
||||||
return supportsFeature(stateObj, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsAuxHeat(stateObj) {
|
|
||||||
return supportsFeature(stateObj, 2048);
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsOn(stateObj) {
|
|
||||||
return supportsFeature(stateObj, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
computeClassNames(stateObj) {
|
|
||||||
const _featureClassNames = {
|
|
||||||
1: "has-target_temperature",
|
|
||||||
2: "has-target_temperature_high",
|
|
||||||
4: "has-target_temperature_low",
|
|
||||||
8: "has-target_humidity",
|
|
||||||
16: "has-target_humidity_high",
|
|
||||||
32: "has-target_humidity_low",
|
|
||||||
64: "has-fan_mode",
|
|
||||||
128: "has-operation_mode",
|
|
||||||
256: "has-hold_mode",
|
|
||||||
512: "has-swing_mode",
|
|
||||||
1024: "has-away_mode",
|
|
||||||
2048: "has-aux_heat",
|
|
||||||
4096: "has-on",
|
|
||||||
};
|
|
||||||
|
|
||||||
var classes = [
|
|
||||||
attributeClassNames(stateObj, [
|
|
||||||
"current_temperature",
|
|
||||||
"current_humidity",
|
|
||||||
]),
|
|
||||||
featureClassNames(stateObj, _featureClassNames),
|
|
||||||
];
|
|
||||||
|
|
||||||
classes.push("more-info-climate");
|
|
||||||
|
|
||||||
return classes.join(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
targetTemperatureChanged(ev) {
|
|
||||||
const temperature = ev.target.value;
|
|
||||||
if (temperature === this.stateObj.attributes.temperature) return;
|
|
||||||
this.callServiceHelper("set_temperature", { temperature: temperature });
|
|
||||||
}
|
|
||||||
|
|
||||||
targetTemperatureLowChanged(ev) {
|
|
||||||
const targetTempLow = ev.currentTarget.value;
|
|
||||||
if (targetTempLow === this.stateObj.attributes.target_temp_low) return;
|
|
||||||
this.callServiceHelper("set_temperature", {
|
|
||||||
target_temp_low: targetTempLow,
|
|
||||||
target_temp_high: this.stateObj.attributes.target_temp_high,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
targetTemperatureHighChanged(ev) {
|
|
||||||
const targetTempHigh = ev.currentTarget.value;
|
|
||||||
if (targetTempHigh === this.stateObj.attributes.target_temp_high) return;
|
|
||||||
this.callServiceHelper("set_temperature", {
|
|
||||||
target_temp_low: this.stateObj.attributes.target_temp_low,
|
|
||||||
target_temp_high: targetTempHigh,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
targetHumiditySliderChanged(ev) {
|
|
||||||
const humidity = ev.target.value;
|
|
||||||
if (humidity === this.stateObj.attributes.humidity) return;
|
|
||||||
this.callServiceHelper("set_humidity", { humidity: humidity });
|
|
||||||
}
|
|
||||||
|
|
||||||
awayToggleChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.attributes.away_mode === "on";
|
|
||||||
const newVal = ev.target.checked;
|
|
||||||
if (oldVal === newVal) return;
|
|
||||||
this.callServiceHelper("set_away_mode", { away_mode: newVal });
|
|
||||||
}
|
|
||||||
|
|
||||||
auxToggleChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.attributes.aux_heat === "on";
|
|
||||||
const newVal = ev.target.checked;
|
|
||||||
if (oldVal === newVal) return;
|
|
||||||
this.callServiceHelper("set_aux_heat", { aux_heat: newVal });
|
|
||||||
}
|
|
||||||
|
|
||||||
onToggleChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.state !== "off";
|
|
||||||
const newVal = ev.target.checked;
|
|
||||||
if (oldVal === newVal) return;
|
|
||||||
this.callServiceHelper(newVal ? "turn_on" : "turn_off", {});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFanmodeChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.attributes.fan_mode;
|
|
||||||
const newVal = ev.detail.value;
|
|
||||||
if (!newVal || oldVal === newVal) return;
|
|
||||||
this.callServiceHelper("set_fan_mode", { fan_mode: newVal });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOperationmodeChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.attributes.operation_mode;
|
|
||||||
const newVal = ev.detail.value;
|
|
||||||
if (!newVal || oldVal === newVal) return;
|
|
||||||
this.callServiceHelper("set_operation_mode", {
|
|
||||||
operation_mode: newVal,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSwingmodeChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.attributes.swing_mode;
|
|
||||||
const newVal = ev.detail.value;
|
|
||||||
if (!newVal || oldVal === newVal) return;
|
|
||||||
this.callServiceHelper("set_swing_mode", { swing_mode: newVal });
|
|
||||||
}
|
|
||||||
|
|
||||||
callServiceHelper(service, data) {
|
|
||||||
// We call stateChanged after a successful call to re-sync the inputs
|
|
||||||
// with the state. It will be out of sync if our service call did not
|
|
||||||
// result in the entity to be turned on. Since the state is not changing,
|
|
||||||
// the resync is not called automatic.
|
|
||||||
/* eslint-disable no-param-reassign */
|
|
||||||
data.entity_id = this.stateObj.entity_id;
|
|
||||||
/* eslint-enable no-param-reassign */
|
|
||||||
this.hass.callService("climate", service, data).then(() => {
|
|
||||||
this.stateObjChanged(this.stateObj);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_localizeOperationMode(localize, mode) {
|
|
||||||
return localize(`state.climate.${mode}`) || mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
_localizeFanMode(localize, mode) {
|
|
||||||
return localize(`state_attributes.climate.fan_mode.${mode}`) || mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeRTLDirection(hass) {
|
|
||||||
return computeRTLDirection(hass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("more-info-climate", MoreInfoClimate);
|
|
501
src/dialogs/more-info/controls/more-info-climate.ts
Normal file
501
src/dialogs/more-info/controls/more-info-climate.ts
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
|
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||||
|
import {
|
||||||
|
LitElement,
|
||||||
|
html,
|
||||||
|
TemplateResult,
|
||||||
|
CSSResult,
|
||||||
|
css,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
import "../../../components/ha-climate-control";
|
||||||
|
import "../../../components/ha-paper-slider";
|
||||||
|
import "../../../components/ha-paper-dropdown-menu";
|
||||||
|
|
||||||
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
|
|
||||||
|
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import {
|
||||||
|
ClimateEntity,
|
||||||
|
CLIMATE_SUPPORT_TARGET_TEMPERATURE,
|
||||||
|
CLIMATE_SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||||
|
CLIMATE_SUPPORT_TARGET_HUMIDITY,
|
||||||
|
CLIMATE_SUPPORT_FAN_MODE,
|
||||||
|
CLIMATE_SUPPORT_SWING_MODE,
|
||||||
|
CLIMATE_SUPPORT_AUX_HEAT,
|
||||||
|
CLIMATE_SUPPORT_PRESET_MODE,
|
||||||
|
} from "../../../data/climate";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
|
|
||||||
|
class MoreInfoClimate extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
@property() public stateObj?: ClimateEntity;
|
||||||
|
private _resizeDebounce?: number;
|
||||||
|
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
if (!this.stateObj) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hass = this.hass;
|
||||||
|
const stateObj = this.stateObj;
|
||||||
|
|
||||||
|
const supportTargetTemperature = supportsFeature(
|
||||||
|
stateObj,
|
||||||
|
CLIMATE_SUPPORT_TARGET_TEMPERATURE
|
||||||
|
);
|
||||||
|
const supportTargetTemperatureRange = supportsFeature(
|
||||||
|
stateObj,
|
||||||
|
CLIMATE_SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||||
|
);
|
||||||
|
const supportTargetHumidity = supportsFeature(
|
||||||
|
stateObj,
|
||||||
|
CLIMATE_SUPPORT_TARGET_HUMIDITY
|
||||||
|
);
|
||||||
|
const supportFanMode = supportsFeature(stateObj, CLIMATE_SUPPORT_FAN_MODE);
|
||||||
|
const supportPresetMode = supportsFeature(
|
||||||
|
stateObj,
|
||||||
|
CLIMATE_SUPPORT_PRESET_MODE
|
||||||
|
);
|
||||||
|
const supportSwingMode = supportsFeature(
|
||||||
|
stateObj,
|
||||||
|
CLIMATE_SUPPORT_SWING_MODE
|
||||||
|
);
|
||||||
|
const supportAuxHeat = supportsFeature(stateObj, CLIMATE_SUPPORT_AUX_HEAT);
|
||||||
|
|
||||||
|
const temperatureStepSize =
|
||||||
|
stateObj.attributes.target_temp_step ||
|
||||||
|
hass.config.unit_system.temperature.indexOf("F") === -1
|
||||||
|
? 0.5
|
||||||
|
: 1;
|
||||||
|
|
||||||
|
const rtlDirection = computeRTLDirection(hass);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
class=${classMap({
|
||||||
|
"has-current_temperature":
|
||||||
|
"current_temperature" in stateObj.attributes,
|
||||||
|
"has-current_humidity": "current_humidity" in stateObj.attributes,
|
||||||
|
"has-target_temperature": supportTargetTemperature,
|
||||||
|
"has-target_temperature_range": supportTargetTemperatureRange,
|
||||||
|
"has-target_humidity": supportTargetHumidity,
|
||||||
|
"has-fan_mode": supportFanMode,
|
||||||
|
"has-swing_mode": supportSwingMode,
|
||||||
|
"has-aux_heat": supportAuxHeat,
|
||||||
|
"has-preset_mode": supportPresetMode,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div class="container-temperature">
|
||||||
|
<div class=${stateObj.state}>
|
||||||
|
${supportTargetTemperature || supportTargetTemperatureRange
|
||||||
|
? html`
|
||||||
|
<div>
|
||||||
|
${hass.localize("ui.card.climate.target_temperature")}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${stateObj.attributes.temperature
|
||||||
|
? html`
|
||||||
|
<ha-climate-control
|
||||||
|
.value=${stateObj.attributes.temperature}
|
||||||
|
.units=${hass.config.unit_system.temperature}
|
||||||
|
.step=${temperatureStepSize}
|
||||||
|
.min=${stateObj.attributes.min_temp}
|
||||||
|
.max=${stateObj.attributes.max_temp}
|
||||||
|
@change=${this._targetTemperatureChanged}
|
||||||
|
></ha-climate-control>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${stateObj.attributes.target_temp_low ||
|
||||||
|
stateObj.attributes.target_temp_high
|
||||||
|
? html`
|
||||||
|
<ha-climate-control
|
||||||
|
.value=${stateObj.attributes.target_temp_low}
|
||||||
|
.units=${hass.config.unit_system.temperature}
|
||||||
|
.step=${temperatureStepSize}
|
||||||
|
.min=${stateObj.attributes.min_temp}
|
||||||
|
.max=${stateObj.attributes.target_temp_high}
|
||||||
|
class="range-control-left"
|
||||||
|
@change=${this._targetTemperatureLowChanged}
|
||||||
|
></ha-climate-control>
|
||||||
|
<ha-climate-control
|
||||||
|
.value=${stateObj.attributes.target_temp_high}
|
||||||
|
.units=${hass.config.unit_system.temperature}
|
||||||
|
.step=${temperatureStepSize}
|
||||||
|
.min=${stateObj.attributes.target_temp_low}
|
||||||
|
.max=${stateObj.attributes.max_temp}
|
||||||
|
class="range-control-right"
|
||||||
|
@change=${this._targetTemperatureHighChanged}
|
||||||
|
></ha-climate-control>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${supportTargetHumidity
|
||||||
|
? html`
|
||||||
|
<div class="container-humidity">
|
||||||
|
<div>${hass.localize("ui.card.climate.target_humidity")}</div>
|
||||||
|
<div class="single-row">
|
||||||
|
<div class="target-humidity">
|
||||||
|
${stateObj.attributes.humidity} %
|
||||||
|
</div>
|
||||||
|
<ha-paper-slider
|
||||||
|
class="humidity"
|
||||||
|
step="1"
|
||||||
|
pin
|
||||||
|
ignore-bar-touch
|
||||||
|
dir=${rtlDirection}
|
||||||
|
.min=${stateObj.attributes.min_humidity}
|
||||||
|
.max=${stateObj.attributes.max_humidity}
|
||||||
|
.secondaryProgress=${stateObj.attributes.max_humidity}
|
||||||
|
.value=${stateObj.attributes.humidity}
|
||||||
|
@change=${this._targetHumiditySliderChanged}
|
||||||
|
>
|
||||||
|
</ha-paper-slider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
|
||||||
|
<div class="container-hvac_modes">
|
||||||
|
<div class="controls">
|
||||||
|
<ha-paper-dropdown-menu
|
||||||
|
label-float
|
||||||
|
dynamic-align
|
||||||
|
.label=${hass.localize("ui.card.climate.operation")}
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
slot="dropdown-content"
|
||||||
|
attr-for-selected="item-name"
|
||||||
|
.selected=${stateObj.state}
|
||||||
|
@selected-changed=${this._handleOperationmodeChanged}
|
||||||
|
>
|
||||||
|
${stateObj.attributes.hvac_modes.map(
|
||||||
|
(mode) => html`
|
||||||
|
<paper-item item-name=${mode}>
|
||||||
|
${hass.localize(`state.climate.${mode}`)}
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</ha-paper-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${supportPresetMode
|
||||||
|
? html`
|
||||||
|
<div class="container-preset_modes">
|
||||||
|
<ha-paper-dropdown-menu
|
||||||
|
label-float
|
||||||
|
dynamic-align
|
||||||
|
.label=${hass.localize("ui.card.climate.preset_mode")}
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
slot="dropdown-content"
|
||||||
|
attr-for-selected="item-name"
|
||||||
|
.selected=${stateObj.attributes.preset_mode}
|
||||||
|
@selected-changed=${this._handlePresetmodeChanged}
|
||||||
|
>
|
||||||
|
<paper-item item-name="">
|
||||||
|
${hass.localize(
|
||||||
|
`state_attributes.climate.preset_mode.none`
|
||||||
|
)}
|
||||||
|
</paper-item>
|
||||||
|
${stateObj.attributes.preset_modes!.map(
|
||||||
|
(mode) => html`
|
||||||
|
<paper-item item-name=${mode}>
|
||||||
|
${hass.localize(
|
||||||
|
`state_attributes.climate.preset_mode.${mode}`
|
||||||
|
) || mode}
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</ha-paper-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${supportFanMode
|
||||||
|
? html`
|
||||||
|
<div class="container-fan_list">
|
||||||
|
<ha-paper-dropdown-menu
|
||||||
|
label-float
|
||||||
|
dynamic-align
|
||||||
|
.label=${hass.localize("ui.card.climate.fan_mode")}
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
slot="dropdown-content"
|
||||||
|
attr-for-selected="item-name"
|
||||||
|
.selected=${stateObj.attributes.fan_mode}
|
||||||
|
@selected-changed=${this._handleFanmodeChanged}
|
||||||
|
>
|
||||||
|
${stateObj.attributes.fan_modes!.map(
|
||||||
|
(mode) => html`
|
||||||
|
<paper-item item-name=${mode}>
|
||||||
|
${hass.localize(
|
||||||
|
`state_attributes.climate.fan_mode.${mode}`
|
||||||
|
) || mode}
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</ha-paper-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${supportSwingMode
|
||||||
|
? html`
|
||||||
|
<div class="container-swing_list">
|
||||||
|
<ha-paper-dropdown-menu
|
||||||
|
label-float
|
||||||
|
dynamic-align
|
||||||
|
.label=${hass.localize("ui.card.climate.swing_mode")}
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
slot="dropdown-content"
|
||||||
|
attr-for-selected="item-name"
|
||||||
|
.selected=${stateObj.attributes.swing_mode}
|
||||||
|
@selected-changed=${this._handleSwingmodeChanged}
|
||||||
|
>
|
||||||
|
${stateObj.attributes.swing_modes!.map(
|
||||||
|
(mode) => html`
|
||||||
|
<paper-item item-name=${mode}>${mode}</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</ha-paper-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${supportAuxHeat
|
||||||
|
? html`
|
||||||
|
<div class="container-aux_heat">
|
||||||
|
<div class="center horizontal layout single-row">
|
||||||
|
<div class="flex">
|
||||||
|
${hass.localize("ui.card.climate.aux_heat")}
|
||||||
|
</div>
|
||||||
|
<paper-toggle-button
|
||||||
|
.checked=${stateObj.attributes.aux_heat === "on"}
|
||||||
|
@change=${this._auxToggleChanged}
|
||||||
|
></paper-toggle-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (!changedProps.has("stateObj") || !this.stateObj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._resizeDebounce) {
|
||||||
|
clearTimeout(this._resizeDebounce);
|
||||||
|
}
|
||||||
|
this._resizeDebounce = window.setTimeout(() => {
|
||||||
|
fireEvent(this, "iron-resize");
|
||||||
|
this._resizeDebounce = undefined;
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _targetTemperatureChanged(ev) {
|
||||||
|
const newVal = ev.target.value;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.temperature,
|
||||||
|
newVal,
|
||||||
|
"set_temperature",
|
||||||
|
{ temperature: newVal }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _targetTemperatureLowChanged(ev) {
|
||||||
|
const newVal = ev.currentTarget.value;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.target_temp_low,
|
||||||
|
newVal,
|
||||||
|
"set_temperature",
|
||||||
|
{
|
||||||
|
target_temp_low: newVal,
|
||||||
|
target_temp_high: this.stateObj!.attributes.target_temp_high,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _targetTemperatureHighChanged(ev) {
|
||||||
|
const newVal = ev.currentTarget.value;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.target_temp_high,
|
||||||
|
newVal,
|
||||||
|
"set_temperature",
|
||||||
|
{
|
||||||
|
target_temp_low: this.stateObj!.attributes.target_temp_low,
|
||||||
|
target_temp_high: newVal,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _targetHumiditySliderChanged(ev) {
|
||||||
|
const newVal = ev.target.value;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.humidity,
|
||||||
|
newVal,
|
||||||
|
"set_humidity",
|
||||||
|
{ humidity: newVal }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _auxToggleChanged(ev) {
|
||||||
|
const newVal = ev.target.checked;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.aux_heat === "on",
|
||||||
|
newVal,
|
||||||
|
"set_aux_heat",
|
||||||
|
{ aux_heat: newVal }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleFanmodeChanged(ev) {
|
||||||
|
const newVal = ev.detail.value;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.fan_mode,
|
||||||
|
newVal,
|
||||||
|
"set_fan_mode",
|
||||||
|
{ fan_mode: newVal }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleOperationmodeChanged(ev) {
|
||||||
|
const newVal = ev.detail.value;
|
||||||
|
this._callServiceHelper(this.stateObj!.state, newVal, "set_hvac_mode", {
|
||||||
|
hvac_mode: newVal,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleSwingmodeChanged(ev) {
|
||||||
|
const newVal = ev.detail.value;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.swing_mode,
|
||||||
|
newVal,
|
||||||
|
"set_swing_mode",
|
||||||
|
{ swing_mode: newVal }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handlePresetmodeChanged(ev) {
|
||||||
|
const newVal = ev.detail.value || null;
|
||||||
|
this._callServiceHelper(
|
||||||
|
this.stateObj!.attributes.preset_mode,
|
||||||
|
newVal,
|
||||||
|
"set_preset_mode",
|
||||||
|
{ preset_mode: newVal }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _callServiceHelper(
|
||||||
|
oldVal: unknown,
|
||||||
|
newVal: unknown,
|
||||||
|
service: string,
|
||||||
|
data: {
|
||||||
|
entity_id?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
if (oldVal === newVal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.entity_id = this.stateObj!.entity_id;
|
||||||
|
const curState = this.stateObj;
|
||||||
|
|
||||||
|
await this.hass.callService("climate", service, data);
|
||||||
|
|
||||||
|
// We reset stateObj to re-sync the inputs with the state. It will be out
|
||||||
|
// of sync if our service call did not result in the entity to be turned
|
||||||
|
// on. Since the state is not changing, the resync is not called automatic.
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
|
// No need to resync if we received a new state.
|
||||||
|
if (this.stateObj !== curState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stateObj = undefined;
|
||||||
|
await this.updateComplete;
|
||||||
|
// Only restore if not set yet by a state change
|
||||||
|
if (this.stateObj === undefined) {
|
||||||
|
this.stateObj = curState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-hvac_modes iron-icon,
|
||||||
|
.container-fan_list iron-icon,
|
||||||
|
.container-swing_list iron-icon {
|
||||||
|
margin: 22px 16px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-paper-dropdown-menu {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
paper-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-paper-slider {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-humidity .single-row {
|
||||||
|
display: flex;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.target-humidity {
|
||||||
|
width: 90px;
|
||||||
|
font-size: 200%;
|
||||||
|
margin: auto;
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-climate-control.range-control-left,
|
||||||
|
ha-climate-control.range-control-right {
|
||||||
|
float: left;
|
||||||
|
width: 46%;
|
||||||
|
}
|
||||||
|
ha-climate-control.range-control-left {
|
||||||
|
margin-right: 4%;
|
||||||
|
}
|
||||||
|
ha-climate-control.range-control-right {
|
||||||
|
margin-left: 4%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.humidity {
|
||||||
|
--paper-slider-active-color: var(--paper-blue-400);
|
||||||
|
--paper-slider-secondary-color: var(--paper-blue-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-row {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("more-info-climate", MoreInfoClimate);
|
@ -619,26 +619,6 @@ export const demoServices: HassServices = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
climate: {
|
climate: {
|
||||||
set_away_mode: {
|
|
||||||
description: "Turn away mode on/off for climate device.",
|
|
||||||
fields: {
|
|
||||||
entity_id: {
|
|
||||||
description: "Name(s) of entities to change.",
|
|
||||||
example: "climate.kitchen",
|
|
||||||
},
|
|
||||||
away_mode: { description: "New value of away mode.", example: "true" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
set_hold_mode: {
|
|
||||||
description: "Turn hold mode for climate device.",
|
|
||||||
fields: {
|
|
||||||
entity_id: {
|
|
||||||
description: "Name(s) of entities to change.",
|
|
||||||
example: "climate.kitchen",
|
|
||||||
},
|
|
||||||
hold_mode: { description: "New value of hold mode", example: "away" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
set_aux_heat: {
|
set_aux_heat: {
|
||||||
description: "Turn auxiliary heater on/off for climate device.",
|
description: "Turn auxiliary heater on/off for climate device.",
|
||||||
fields: {
|
fields: {
|
||||||
@ -701,16 +681,16 @@ export const demoServices: HassServices = {
|
|||||||
fan_mode: { description: "New value of fan mode.", example: "On Low" },
|
fan_mode: { description: "New value of fan mode.", example: "On Low" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
set_operation_mode: {
|
set_hvac_mode: {
|
||||||
description: "Set operation mode for climate device.",
|
description: "Set operation mode for climate device.",
|
||||||
fields: {
|
fields: {
|
||||||
entity_id: {
|
entity_id: {
|
||||||
description: "Name(s) of entities to change.",
|
description: "Name(s) of entities to change.",
|
||||||
example: "climate.nest",
|
example: "climate.nest",
|
||||||
},
|
},
|
||||||
operation_mode: {
|
hvac_mode: {
|
||||||
description: "New value of operation mode.",
|
description: "New value of operation mode.",
|
||||||
example: "Heat",
|
example: "heat",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -724,24 +704,6 @@ export const demoServices: HassServices = {
|
|||||||
swing_mode: { description: "New value of swing mode.", example: "" },
|
swing_mode: { description: "New value of swing mode.", example: "" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
turn_off: {
|
|
||||||
description: "Turn climate device off.",
|
|
||||||
fields: {
|
|
||||||
entity_id: {
|
|
||||||
description: "Name(s) of entities to change.",
|
|
||||||
example: "climate.kitchen",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
turn_on: {
|
|
||||||
description: "Turn climate device on.",
|
|
||||||
fields: {
|
|
||||||
entity_id: {
|
|
||||||
description: "Name(s) of entities to change.",
|
|
||||||
example: "climate.kitchen",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
image_processing: {
|
image_processing: {
|
||||||
scan: {
|
scan: {
|
||||||
|
@ -209,11 +209,24 @@ class ClimateEntity extends Entity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (service === "set_operation_mode") {
|
if (service === "set_hvac_mode") {
|
||||||
this.update(
|
this.update(data.hvac_mode, this.attributes);
|
||||||
data.operation_mode === "heat" ? "heat" : data.operation_mode,
|
} else if (
|
||||||
{ ...this.attributes, operation_mode: data.operation_mode }
|
[
|
||||||
);
|
"set_temperature",
|
||||||
|
"set_humidity",
|
||||||
|
"set_hvac_mode",
|
||||||
|
"set_fan_mode",
|
||||||
|
"set_preset_mode",
|
||||||
|
"set_swing_mode",
|
||||||
|
"set_aux_heat",
|
||||||
|
].includes(service)
|
||||||
|
) {
|
||||||
|
const { entity_id, ...toSet } = data;
|
||||||
|
this.update(this.state, {
|
||||||
|
...this.attributes,
|
||||||
|
...toSet,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
super.handleService(domain, service, data);
|
super.handleService(domain, service, data);
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,13 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
|||||||
import computeStateName from "../../../common/entity/compute_state_name";
|
import computeStateName from "../../../common/entity/compute_state_name";
|
||||||
|
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
import { HomeAssistant, ClimateEntity } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
||||||
import { UNIT_F } from "../../../common/const";
|
import { UNIT_F } from "../../../common/const";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { ThermostatCardConfig } from "./types";
|
import { ThermostatCardConfig } from "./types";
|
||||||
|
import { ClimateEntity, HvacMode } from "../../../data/climate";
|
||||||
|
|
||||||
const thermostatConfig = {
|
const thermostatConfig = {
|
||||||
radius: 150,
|
radius: 150,
|
||||||
@ -35,16 +36,14 @@ const thermostatConfig = {
|
|||||||
animation: false,
|
animation: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const modeIcons = {
|
const modeIcons: { [mode in HvacMode]: string } = {
|
||||||
auto: "hass:autorenew",
|
auto: "hass:autorenew",
|
||||||
manual: "hass:cursor-pointer",
|
heat_cool: "hass:autorenew",
|
||||||
heat: "hass:fire",
|
heat: "hass:fire",
|
||||||
cool: "hass:snowflake",
|
cool: "hass:snowflake",
|
||||||
off: "hass:power",
|
off: "hass:power",
|
||||||
fan_only: "hass:fan",
|
fan_only: "hass:fan",
|
||||||
eco: "hass:leaf",
|
|
||||||
dry: "hass:water-percent",
|
dry: "hass:water-percent",
|
||||||
idle: "hass:power-sleep",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("hui-thermostat-card")
|
@customElement("hui-thermostat-card")
|
||||||
@ -109,9 +108,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mode = modeIcons[stateObj.attributes.operation_mode || ""]
|
const mode = stateObj.state in modeIcons ? stateObj.state : "unknown-mode";
|
||||||
? stateObj.attributes.operation_mode!
|
|
||||||
: "unknown-mode";
|
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyle()}
|
${this.renderStyle()}
|
||||||
<ha-card
|
<ha-card
|
||||||
@ -146,11 +143,23 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
</div>
|
</div>
|
||||||
<div class="climate-info">
|
<div class="climate-info">
|
||||||
<div id="set-temperature"></div>
|
<div id="set-temperature"></div>
|
||||||
<div class="current-mode">${this.hass!.localize(
|
<div class="current-mode">
|
||||||
`state.climate.${stateObj.state}`
|
${this.hass!.localize(`state.climate.${stateObj.state}`)}
|
||||||
)}</div>
|
${
|
||||||
|
stateObj.attributes.preset_mode
|
||||||
|
? html`
|
||||||
|
-
|
||||||
|
${this.hass!.localize(
|
||||||
|
`state_attributes.climate.preset_mode.${
|
||||||
|
stateObj.attributes.preset_mode
|
||||||
|
}`
|
||||||
|
) || stateObj.attributes.preset_mode}
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
<div class="modes">
|
<div class="modes">
|
||||||
${(stateObj.attributes.operation_list || []).map((modeItem) =>
|
${stateObj.attributes.hvac_modes.map((modeItem) =>
|
||||||
this._renderIcon(modeItem, mode)
|
this._renderIcon(modeItem, mode)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -205,7 +214,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get _stepSize(): number {
|
private get _stepSize(): number {
|
||||||
const stateObj = this.hass!.states[this._config!.entity];
|
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
|
||||||
|
|
||||||
if (stateObj.attributes.target_temp_step) {
|
if (stateObj.attributes.target_temp_step) {
|
||||||
return stateObj.attributes.target_temp_step;
|
return stateObj.attributes.target_temp_step;
|
||||||
@ -348,9 +357,9 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleModeClick(e: MouseEvent): void {
|
private _handleModeClick(e: MouseEvent): void {
|
||||||
this.hass!.callService("climate", "set_operation_mode", {
|
this.hass!.callService("climate", "set_hvac_mode", {
|
||||||
entity_id: this._config!.entity,
|
entity_id: this._config!.entity,
|
||||||
operation_mode: (e.currentTarget as any).mode,
|
hvac_mode: (e.currentTarget as any).mode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +403,8 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.auto {
|
.auto,
|
||||||
|
.heat_cool {
|
||||||
--mode-color: var(--auto-color);
|
--mode-color: var(--auto-color);
|
||||||
}
|
}
|
||||||
.cool {
|
.cool {
|
||||||
|
@ -11,12 +11,13 @@ export function hasConfigOrEntityChanged(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
if (oldHass) {
|
if (!oldHass) {
|
||||||
return (
|
|
||||||
oldHass.states[element._config!.entity] !==
|
|
||||||
element.hass!.states[element._config!.entity]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
oldHass.states[element._config!.entity] !==
|
||||||
|
element.hass!.states[element._config!.entity] ||
|
||||||
|
oldHass.localize !== element.hass.localize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -176,20 +176,12 @@
|
|||||||
},
|
},
|
||||||
"climate": {
|
"climate": {
|
||||||
"off": "[%key:state::default::off%]",
|
"off": "[%key:state::default::off%]",
|
||||||
"on": "[%key:state::default::on%]",
|
|
||||||
"heat": "Heat",
|
"heat": "Heat",
|
||||||
"cool": "Cool",
|
"cool": "Cool",
|
||||||
"idle": "Idle",
|
"heat_cool": "Auto",
|
||||||
"auto": "Auto",
|
"auto": "Auto",
|
||||||
"dry": "Dry",
|
"dry": "Dry",
|
||||||
"fan_only": "Fan only",
|
"fan_only": "Fan only"
|
||||||
"eco": "Eco",
|
|
||||||
"electric": "Electric",
|
|
||||||
"performance": "Performance",
|
|
||||||
"high_demand": "High demand",
|
|
||||||
"heat_pump": "Heat pump",
|
|
||||||
"gas": "Gas",
|
|
||||||
"manual": "Manual"
|
|
||||||
},
|
},
|
||||||
"configurator": {
|
"configurator": {
|
||||||
"configure": "Configure",
|
"configure": "Configure",
|
||||||
@ -326,6 +318,16 @@
|
|||||||
"off": "[%key:state::default::off%]",
|
"off": "[%key:state::default::off%]",
|
||||||
"on": "[%key:state::default::on%]",
|
"on": "[%key:state::default::on%]",
|
||||||
"auto": "[%key:state::climate::auto%]"
|
"auto": "[%key:state::climate::auto%]"
|
||||||
|
},
|
||||||
|
"preset_mode": {
|
||||||
|
"none": "None",
|
||||||
|
"eco": "Eco",
|
||||||
|
"away": "Away",
|
||||||
|
"boost": "Boost",
|
||||||
|
"comfort": "Comfort",
|
||||||
|
"home": "Home",
|
||||||
|
"sleep": "Sleep",
|
||||||
|
"activity": "Activity"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -393,6 +395,7 @@
|
|||||||
"operation": "Operation",
|
"operation": "Operation",
|
||||||
"fan_mode": "Fan mode",
|
"fan_mode": "Fan mode",
|
||||||
"swing_mode": "Swing mode",
|
"swing_mode": "Swing mode",
|
||||||
|
"preset_mode": "Preset",
|
||||||
"away_mode": "Away mode",
|
"away_mode": "Away mode",
|
||||||
"aux_heat": "Aux heat"
|
"aux_heat": "Aux heat"
|
||||||
},
|
},
|
||||||
|
24
src/types.ts
24
src/types.ts
@ -160,30 +160,6 @@ export interface HomeAssistant {
|
|||||||
callWS: <T>(msg: MessageBase) => Promise<T>;
|
callWS: <T>(msg: MessageBase) => Promise<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ClimateEntity = HassEntityBase & {
|
|
||||||
attributes: HassEntityAttributeBase & {
|
|
||||||
current_temperature: number;
|
|
||||||
min_temp: number;
|
|
||||||
max_temp: number;
|
|
||||||
temperature: number;
|
|
||||||
target_temp_step?: number;
|
|
||||||
target_temp_high?: number;
|
|
||||||
target_temp_low?: number;
|
|
||||||
target_humidity?: number;
|
|
||||||
target_humidity_low?: number;
|
|
||||||
target_humidity_high?: number;
|
|
||||||
fan_mode?: string;
|
|
||||||
fan_list?: string[];
|
|
||||||
operation_mode?: string;
|
|
||||||
operation_list?: string[];
|
|
||||||
hold_mode?: string;
|
|
||||||
swing_mode?: string;
|
|
||||||
swing_list?: string[];
|
|
||||||
away_mode?: "on" | "off";
|
|
||||||
aux_heat?: "on" | "off";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type LightEntity = HassEntityBase & {
|
export type LightEntity = HassEntityBase & {
|
||||||
attributes: HassEntityAttributeBase & {
|
attributes: HassEntityAttributeBase & {
|
||||||
min_mireds: number;
|
min_mireds: number;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user