Resync thermostat card setpoint values if service call fails (#15497)

This commit is contained in:
karwosts 2023-02-21 00:36:18 -08:00 committed by GitHub
parent c95a600fbb
commit 850609b1d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -90,6 +90,8 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
@query("ha-card") private _card?: HaCard;
@state() private resyncSetpoint = false;
public getCardSize(): number {
return 7;
}
@ -120,11 +122,23 @@ 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 = this.resyncSetpoint
? // If the user set position in the slider is out of sync with the entity
// value, then rerendering the slider with same $value a second time
// does not move the slider. Need to set it to a different dummy value
// for one update cycle to force it to rerender to the desired value.
stateObj.attributes.min_temp - 1
: stateObj.attributes.temperature !== null &&
Number.isFinite(Number(stateObj.attributes.temperature))
? stateObj.attributes.temperature
: stateObj.attributes.min_temp;
const targetLow = this.resyncSetpoint
? stateObj.attributes.min_temp - 1
: stateObj.attributes.target_temp_low;
const targetHigh = this.resyncSetpoint
? stateObj.attributes.min_temp - 1
: stateObj.attributes.target_temp_high;
const slider =
stateObj.state === UNAVAILABLE
@ -132,8 +146,8 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
: html`
<round-slider
.value=${targetTemp}
.low=${stateObj.attributes.target_temp_low}
.high=${stateObj.attributes.target_temp_high}
.low=${targetLow}
.high=${targetHigh}
.min=${stateObj.attributes.min_temp}
.max=${stateObj.attributes.max_temp}
.step=${this._stepSize}
@ -289,7 +303,10 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
}
protected shouldUpdate(changedProps: PropertyValues): boolean {
return hasConfigOrEntityChanged(this, changedProps);
return (
hasConfigOrEntityChanged(this, changedProps) ||
changedProps.has("resyncSetpoint")
);
}
protected updated(changedProps: PropertyValues): void {
@ -328,7 +345,11 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
}
public willUpdate(changedProps: PropertyValues) {
if (!this.hass || !this._config || !changedProps.has("hass")) {
if (
!this.hass ||
!this._config ||
!(changedProps.has("hass") || changedProps.has("resyncSetpoint"))
) {
return;
}
@ -339,7 +360,11 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if (!oldHass || oldHass.states[this._config.entity] !== stateObj) {
if (
!oldHass ||
oldHass.states[this._config.entity] !== stateObj ||
(changedProps.has("resyncSetpoint") && this.resyncSetpoint)
) {
this._setTemp = this._getSetTemp(stateObj);
}
}
@ -410,22 +435,35 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
if (e.detail.low) {
this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity,
target_temp_low: e.detail.low,
target_temp_high: stateObj.attributes.target_temp_high,
});
const newVal = e.detail.low;
this._callServiceHelper(
stateObj.attributes.target_temp_low,
newVal,
"set_temperature",
{
target_temp_low: newVal,
target_temp_high: stateObj.attributes.target_temp_high,
}
);
} else if (e.detail.high) {
this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity,
target_temp_low: stateObj.attributes.target_temp_low,
target_temp_high: e.detail.high,
});
const newVal = e.detail.high;
this._callServiceHelper(
stateObj.attributes.target_temp_high,
newVal,
"set_temperature",
{
target_temp_low: stateObj.attributes.target_temp_low,
target_temp_high: newVal,
}
);
} else {
this.hass!.callService("climate", "set_temperature", {
entity_id: this._config!.entity,
temperature: e.detail.value,
});
const newVal = e.detail.value;
this._callServiceHelper(
stateObj!.attributes.temperature,
newVal,
"set_temperature",
{ temperature: newVal }
);
}
}
@ -459,6 +497,44 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
});
}
private async _callServiceHelper(
oldVal: unknown,
newVal: unknown,
service: string,
data: {
entity_id?: string;
[key: string]: unknown;
}
) {
if (oldVal === newVal) {
return;
}
data.entity_id = this._config!.entity;
await this.hass!.callService("climate", service, data);
// After updating temperature, wait 2s and check if the values
// from call service are reflected in the entity. If not, resync
// the slider to the entity values.
await new Promise((resolve) => setTimeout(resolve, 2000));
const newState = this.hass!.states[this._config!.entity] as ClimateEntity;
delete data.entity_id;
if (
Object.entries(data).every(
([key, value]) => newState.attributes[key] === value
)
) {
return;
}
this.resyncSetpoint = true;
await this.updateComplete;
this.resyncSetpoint = false;
}
static get styles(): CSSResultGroup {
return css`
:host {