Compare commits

...

4 Commits

Author SHA1 Message Date
Zack Arnett
9a49956e98 Updates 2020-09-18 16:00:55 -05:00
Zack Barett
640d6e9549 Merge branch 'dev' into Thermostat-card 2020-09-18 15:26:03 -05:00
Zack Arnett
cb043200cc do calc once 2020-08-12 10:58:53 -05:00
Zack Arnett
6b46949eb7 thermostat changes 2020-08-10 17:15:55 -05:00

View File

@@ -19,6 +19,7 @@ import { UNIT_F } from "../../../common/const";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event"; import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name"; import { computeStateName } from "../../../common/entity/compute_state_name";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-card"; import "../../../components/ha-card";
import type { HaCard } from "../../../components/ha-card"; import type { HaCard } from "../../../components/ha-card";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
@@ -30,8 +31,10 @@ import {
} from "../../../data/climate"; } from "../../../data/climate";
import { UNAVAILABLE } from "../../../data/entity"; import { UNAVAILABLE } from "../../../data/entity";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entites"; import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed"; import { hasConfigOrEntityChanged } from "../common/has-changed";
import { installResizeObserver } from "../common/install-resize-observer";
import { createEntityNotFoundWarning } from "../components/hui-warning"; import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCard, LovelaceCardEditor } from "../types";
import { ThermostatCardConfig } from "./types"; import { ThermostatCardConfig } from "./types";
@@ -79,8 +82,25 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
@internalProperty() private _setTemp?: number | number[]; @internalProperty() private _setTemp?: number | number[];
@internalProperty() private _lastSetMode?: number;
@internalProperty() private _narrow = false;
@query("ha-card") private _card?: HaCard; @query("ha-card") private _card?: HaCard;
private _resizeObserver?: ResizeObserver;
public connectedCallback(): void {
super.connectedCallback();
this.updateComplete.then(() => this._attachObserver());
}
public disconnectedCallback(): void {
if (this._resizeObserver) {
this._resizeObserver.disconnect();
}
}
public getCardSize(): number { public getCardSize(): number {
return 5; return 5;
} }
@@ -119,7 +139,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
const slider = const slider =
stateObj.state === UNAVAILABLE stateObj.state === UNAVAILABLE
? html` <round-slider disabled="true"></round-slider> ` ? html`<round-slider disabled="true"></round-slider>`
: html` : html`
<round-slider <round-slider
.value=${targetTemp} .value=${targetTemp}
@@ -214,6 +234,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
<ha-card <ha-card
class=${classMap({ class=${classMap({
[mode]: true, [mode]: true,
narrow: this._narrow,
})} })}
> >
<mwc-icon-button <mwc-icon-button
@@ -237,12 +258,40 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
</div> </div>
</div> </div>
<div id="info"> <div id="info">
<div id="modes"> ${!this._narrow
${(stateObj.attributes.hvac_modes || []) ? html`
.concat() <div class="step-icons">
.sort(compareClimateHvacModes) <ha-icon-button
.map((modeItem) => this._renderIcon(modeItem, mode))} class="minus step-icon ${classMap({
</div> disabled:
Array.isArray(this._setTemp) && !this._lastSetMode,
})}"
icon="hass:minus"
@action=${this._handleStepAction}
.actionHandler=${actionHandler()}
tempDiff="-1"
tabindex="0"
></ha-icon-button
><ha-icon-button
class="plus step-icon ${classMap({
disabled:
Array.isArray(this._setTemp) && !this._lastSetMode,
})}"
icon="hass:plus"
@action=${this._handleStepAction}
.actionHandler=${actionHandler()}
tabindex="0"
tempDiff="1"
></ha-icon-button>
</div>
<div id="modes">
${(stateObj.attributes.hvac_modes || [])
.concat()
.sort(compareClimateHvacModes)
.map((modeItem) => this._renderIcon(modeItem, mode))}
</div>
`
: ""}
${name} ${name}
</div> </div>
</div> </div>
@@ -254,6 +303,11 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
return hasConfigOrEntityChanged(this, changedProps); return hasConfigOrEntityChanged(this, changedProps);
} }
protected firstUpdated(): void {
this._measureCard();
this._attachObserver();
}
protected updated(changedProps: PropertyValues): void { protected updated(changedProps: PropertyValues): void {
super.updated(changedProps); super.updated(changedProps);
@@ -356,12 +410,14 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
if (e.detail.low) { if (e.detail.low) {
this._lastSetMode = 0;
this.hass!.callService("climate", "set_temperature", { this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity, entity_id: this._config!.entity,
target_temp_low: e.detail.low, target_temp_low: e.detail.low,
target_temp_high: stateObj.attributes.target_temp_high, target_temp_high: stateObj.attributes.target_temp_high,
}); });
} else if (e.detail.high) { } else if (e.detail.high) {
this._lastSetMode = 1;
this.hass!.callService("climate", "set_temperature", { this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity, entity_id: this._config!.entity,
target_temp_low: stateObj.attributes.target_temp_low, target_temp_low: stateObj.attributes.target_temp_low,
@@ -381,10 +437,11 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
} }
return html` return html`
<ha-icon-button <ha-icon-button
class="${classMap({ "selected-icon": currentMode === mode })}" class=${classMap({ "selected-icon": currentMode === mode })}
.mode="${mode}" .mode=${mode}
.icon="${modeIcons[mode]}" .icon=${modeIcons[mode]}
@click=${this._handleAction} @action=${this._handleAction}
.actionHandler=${actionHandler()}
tabindex="0" tabindex="0"
></ha-icon-button> ></ha-icon-button>
`; `;
@@ -403,6 +460,53 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
}); });
} }
private _handleStepAction(e: MouseEvent): void {
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
const tempChange = (e.currentTarget as any).tempDiff * this._stepSize;
if (!Array.isArray(this._setTemp!)) {
this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity,
temperature: (this._setTemp! as number) + tempChange,
});
} else if (this._lastSetMode === 0) {
this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity,
target_temp_low: this._setTemp![this._lastSetMode] + tempChange,
target_temp_high: stateObj.attributes.target_temp_high,
});
} else if (this._lastSetMode === 1) {
this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity,
target_temp_low: stateObj.attributes.target_temp_low,
target_temp_high: this._setTemp![this._lastSetMode] + tempChange,
});
}
}
private async _attachObserver(): Promise<void> {
if (!this._resizeObserver) {
await installResizeObserver();
this._resizeObserver = new ResizeObserver(
debounce(() => this._measureCard(), 250, false)
);
}
const card = this.shadowRoot!.querySelector("ha-card");
// If we show an error or warning there is no ha-card
if (!card) {
return;
}
this._resizeObserver.observe(card);
}
private _measureCard() {
if (!this.isConnected) {
return;
}
this._narrow = this.offsetWidth < 174;
}
static get styles(): CSSResult { static get styles(): CSSResult {
return css` return css`
:host { :host {
@@ -531,14 +635,29 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
} }
#info { #info {
display: flex-vertical; display: flex;
flex-direction: column;
justify-content: center; justify-content: center;
align-items: center;
text-align: center; text-align: center;
padding: 16px; padding: 16px;
margin-top: -60px; margin-top: -55px;
font-size: var(--name-font-size); font-size: var(--name-font-size);
} }
.narrow #info {
margin-top: -40px;
}
#modes {
--mdc-icon-button-size: 32px;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
width: 100%;
padding-top: 8px;
}
#modes > * { #modes > * {
color: var(--disabled-text-color); color: var(--disabled-text-color);
cursor: pointer; cursor: pointer;
@@ -552,6 +671,36 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
text { text {
fill: var(--primary-text-color); fill: var(--primary-text-color);
} }
.step-icons {
display: flex;
justify-content: space-around;
max-width: 250px;
min-width: 100px;
width: 100%;
}
.step-icon {
--mdc-icon-button-size: 28px;
--mdc-icon-size: 18px;
border-radius: 50%;
border: 1px solid;
}
.step-icon.disabled {
border-color: var(--disabled-text-color);
color: var(--disabled-text-color);
}
.minus {
border-color: var(--cool-color);
color: var(--cool-color);
}
.plus {
border-color: var(--heat-color);
color: var(--heat-color);
}
`; `;
} }
} }