diff --git a/src/components/state-history-chart-line.js b/src/components/state-history-chart-line.js index f88b48053bce..1c9a4e51b853 100644 --- a/src/components/state-history-chart-line.js +++ b/src/components/state-history-chart-line.js @@ -163,11 +163,23 @@ class StateHistoryChartLine extends LocalizeMixin(PolymerElement) { domain === "climate" ? (state) => state.attributes.hvac_action === "cooling" : (state) => state.state === "cool"; + const isDrying = + domain === "climate" + ? (state) => state.attributes.hvac_action === "drying" + : (state) => state.state === "dry"; // We differentiate between thermostats that have a target temperature // range versus ones that have just a target temperature // Using step chart by step-before so manually interpolation not needed. + const hasTemp = states.states.some( + (state) => + state.attributes && isFinite(state.attributes.current_temperature) + ); + const hasHumidity = states.states.some( + (state) => + state.attributes && isFinite(state.attributes.current_humidity) + ); const hasTargetRange = states.states.some( (state) => state.attributes && @@ -176,8 +188,14 @@ class StateHistoryChartLine extends LocalizeMixin(PolymerElement) { ); const hasHeat = states.states.some(isHeating); const hasCool = states.states.some(isCooling); + const hasDry = states.states.some(isDrying); - addColumn(name + " current temperature", true); + if (hasTemp) { + addColumn(name + " current temperature", true); + } + if (hasHumidity) { + addColumn(name + " current humidity", true); + } if (hasHeat) { addColumn(name + " heating", true, true); // The "heating" series uses steppedArea to shade the area below the current @@ -188,36 +206,58 @@ class StateHistoryChartLine extends LocalizeMixin(PolymerElement) { // The "cooling" series uses steppedArea to shade the area below the current // temperature when the thermostat is calling for heat. } + if (hasDry) { + addColumn(name + " drying", true, true); + // The "drying" series uses steppedArea to shade the area below the current + // humidity when the device is calling for dry. + } if (hasTargetRange) { addColumn(name + " target temperature high", true); addColumn(name + " target temperature low", true); - } else { + } else if (hasTemp) { addColumn(name + " target temperature", true); } + if (hasHumidity) { + addColumn(name + " target humidity", true); + } + states.states.forEach((state) => { if (!state.attributes) return; + const series = []; const curTemp = safeParseFloat(state.attributes.current_temperature); - const series = [curTemp]; + if (hasTemp) { + series.push(curTemp); + } + const curHumidity = safeParseFloat(state.attributes.current_humidity); + if (hasHumidity) { + series.push(curHumidity); + } if (hasHeat) { series.push(isHeating(state) ? curTemp : null); } if (hasCool) { series.push(isCooling(state) ? curTemp : null); } + if (hasDry) { + series.push(isDrying(state) ? curHumidity : null); + } if (hasTargetRange) { const targetHigh = safeParseFloat( state.attributes.target_temp_high ); const targetLow = safeParseFloat(state.attributes.target_temp_low); series.push(targetHigh, targetLow); - pushData(new Date(state.last_changed), series); - } else { + } else if (hasTemp) { const target = safeParseFloat(state.attributes.temperature); series.push(target); - pushData(new Date(state.last_changed), series); } + if (hasHumidity) { + const target = safeParseFloat(state.attributes.humidity); + series.push(target); + } + pushData(new Date(state.last_changed), series); }); } else { // Only disable interpolation for sensors diff --git a/src/data/history.ts b/src/data/history.ts index 04976580319c..b00a0b8b5867 100644 --- a/src/data/history.ts +++ b/src/data/history.ts @@ -12,6 +12,8 @@ const LINE_ATTRIBUTES_TO_KEEP = [ "target_temp_low", "target_temp_high", "hvac_action", + "humidity", + "current_humidity", ]; export interface LineChartState { diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 9ca11ab80bed..8073a08f7e17 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -136,13 +136,17 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
- ${stateObj.attributes.current_temperature} + ${stateObj.attributes.current_temperature + ? stateObj.attributes.current_temperature + : stateObj.attributes.current_humidity} ${stateObj.attributes.current_temperature ? html` ${this.hass.config.unit_system.temperature} ` + : stateObj.attributes.current_humidity + ? "%" : ""}
@@ -222,8 +226,12 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { sliderType, value: sliderValue, disabled: sliderValue === null, - min: stateObj.attributes.min_temp, - max: stateObj.attributes.max_temp, + min: stateObj.attributes.current_temperature + ? stateObj.attributes.min_temp + : stateObj.attributes.min_humidity, + max: stateObj.attributes.current_temperature + ? stateObj.attributes.max_temp + : stateObj.attributes.max_humidity, }); this._updateSetTemp(uiValue); } @@ -232,6 +240,9 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { private get _stepSize(): number { const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; + if (!stateObj.attributes.current_temperature) { + return 0.5; + } if (stateObj.attributes.target_temp_step) { return stateObj.attributes.target_temp_step; } @@ -271,8 +282,12 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { this._jQuery("#thermostat", this.shadowRoot).roundSlider({ ...thermostatConfig, radius, - min: stateObj.attributes.min_temp, - max: stateObj.attributes.max_temp, + min: stateObj.attributes.current_temperature + ? stateObj.attributes.min_temp + : stateObj.attributes.min_humidity, + max: stateObj.attributes.current_temperature + ? stateObj.attributes.max_temp + : stateObj.attributes.max_humidity, sliderType, change: (value) => this._setTemperature(value), drag: (value) => this._dragEvent(value), @@ -295,6 +310,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { sliderValue = null; uiValue = this.hass!.localize("state.default.unavailable"); } else if ( + stateObj.attributes.current_temperature && stateObj.attributes.target_temp_low && stateObj.attributes.target_temp_high ) { @@ -309,12 +325,18 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { ], false ); - } else { + } else if (stateObj.attributes.current_temperature) { sliderType = "min-range"; sliderValue = Number.isFinite(Number(stateObj.attributes.temperature)) ? stateObj.attributes.temperature : null; uiValue = sliderValue !== null ? String(sliderValue) : ""; + } else { + sliderType = "min-range"; + sliderValue = stateObj.attributes.humidity + ? stateObj.attributes.humidity + : null; + uiValue = sliderValue !== null ? String(sliderValue) : ""; } return [sliderValue, uiValue, sliderType]; @@ -330,7 +352,12 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { private _setTemperature(e): void { const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; - if ( + if (!stateObj.attributes.current_temperature) { + this.hass!.callService("climate", "set_humidity", { + entity_id: this._config!.entity, + humidity: e.value, + }); + } else if ( stateObj.attributes.target_temp_low && stateObj.attributes.target_temp_high ) {