Skip to content

Commit

Permalink
fix: sets proper power levels when device state changes
Browse files Browse the repository at this point in the history
  • Loading branch information
= authored and swingerman committed Aug 30, 2024
1 parent dfc38a7 commit de08b65
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 28 deletions.
14 changes: 4 additions & 10 deletions custom_components/dual_smart_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,16 +780,8 @@ def extra_state_attributes(self) -> dict:
_LOGGER.debug(
"Setting HVAC Power Level: %s", self.power_manager.hvac_power_level
)
attributes[ATTR_HVAC_POWER_LEVEL] = (
self.power_manager.hvac_power_level
if self.hvac_device.hvac_mode != HVACMode.OFF
else 0
)
attributes[ATTR_HVAC_POWER_PERCENT] = (
self.power_manager.hvac_power_percent
if self.hvac_device.hvac_mode != HVACMode.OFF
else 0
)
attributes[ATTR_HVAC_POWER_LEVEL] = self.power_manager.hvac_power_level
attributes[ATTR_HVAC_POWER_PERCENT] = self.power_manager.hvac_power_percent

_LOGGER.debug("Extra state attributes: %s", attributes)

Expand Down Expand Up @@ -1172,6 +1164,8 @@ async def _async_control_climate_forced(self, time=None) -> None:
_LOGGER.debug("_async_control_climate_forced, time %s", time)
await self._async_control_climate(force=True, time=time)

self.async_write_ha_state()

@callback
def _async_hvac_mode_changed(self, hvac_mode) -> None:
"""Handle HVAC mode changes."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ def is_active(self) -> bool:
on_state = STATE_OPEN if self._is_valve else STATE_ON

_LOGGER.debug(
"Checking if device is active: %s, on_state: %s", self.entity_id, on_state
"Checking if device is active: %s, on_state: %s",
self.entity_id,
on_state,
)
if self.entity_id is not None and self.hass.states.is_state(
self.entity_id, on_state
Expand Down Expand Up @@ -132,14 +134,21 @@ async def async_control_device_when_on(
) -> None:
"""Check if we need to turn heating on or off when theheater is on."""

_LOGGER.debug("%s _async_control_device_when_on", self.__class__.__name__)
_LOGGER.debug("below_env_attr: %s", strategy.hvac_goal_reached)
_LOGGER.debug("any_opening_open: %s", any_opening_open)
_LOGGER.debug("hvac_goal_reached: %s", strategy.hvac_goal_reached)

if strategy.hvac_goal_reached or any_opening_open:
_LOGGER.debug("Turning off entity %s", self.entity_id)

await self.async_turn_off_callback()

if strategy.hvac_goal_reached:
_LOGGER.debug("setting hvac_action_reason goal reached")
self._hvac_action_reason = strategy.goal_reached_reason()
if any_opening_open:
_LOGGER.debug("setting hvac_action_reason opening")
self._hvac_action_reason = HVACActionReason.OPENING

elif time is not None and not any_opening_open:
Expand All @@ -150,6 +159,8 @@ async def async_control_device_when_on(
)
await self.async_turn_on_callback()
self._hvac_action_reason = strategy.goal_not_reached_reason()
else:
_LOGGER.debug("No case matched when - keep device on")

async def async_control_device_when_off(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
from typing import Callable

from homeassistant.components.climate import HVACMode
from homeassistant.components.climate import HVACAction, HVACMode
from homeassistant.components.valve import DOMAIN as VALVE_DOMAIN, ValveEntityFeature
from homeassistant.const import (
ATTR_ENTITY_ID,
Expand Down Expand Up @@ -211,32 +211,39 @@ async def async_control_hvac(self, time=None, force=False):
):
return

any_opeing_open = self.openings.any_opening_open(self.hvac_mode)
any_opening_open = self.openings.any_opening_open(self.hvac_mode)

_LOGGER.debug(
"%s - async_control_hvac - is device active: %s, %s, strategy: %s, is opening open: %s",
self._device_type,
self.entity_id,
self.hvac_controller.is_active,
self.strategy,
any_opeing_open,
any_opening_open,
)

if self.hvac_controller.is_active:
await self.hvac_controller.async_control_device_when_on(
self.strategy,
any_opeing_open,
any_opening_open,
time,
)
else:
await self.hvac_controller.async_control_device_when_off(
self.strategy,
any_opeing_open,
any_opening_open,
time,
)

_LOGGER.debug(
"hvac action reason after control: %s",
self.hvac_controller.hvac_action_reason,
)

self._hvac_action_reason = self.hvac_controller.hvac_action_reason
self.hvac_power.update_hvac_power(self.strategy, self.target_env_attr)
self.hvac_power.update_hvac_power(
self.strategy, self.target_env_attr, self.hvac_action
)

async def async_on_startup(self, async_write_ha_state_cb: Callable = None):

Expand Down Expand Up @@ -287,6 +294,10 @@ async def async_turn_off(self):
else:
await self._async_turn_off_entity()

self.hvac_power.update_hvac_power(
self.strategy, self.target_env_attr, HVACAction.OFF
)

async def _async_turn_on_entity(self) -> None:
"""Turn on the entity."""
_LOGGER.info(
Expand All @@ -302,6 +313,7 @@ async def _async_turn_on_entity(self) -> None:
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: self.entity_id},
context=self._context,
blocking=True,
)

async def _async_turn_off_entity(self) -> None:
Expand All @@ -318,6 +330,7 @@ async def _async_turn_off_entity(self) -> None:
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: self.entity_id},
context=self._context,
blocking=True,
)

async def _async_open_valve_entity(self) -> None:
Expand All @@ -332,6 +345,7 @@ async def _async_open_valve_entity(self) -> None:
SERVICE_OPEN_VALVE,
{ATTR_ENTITY_ID: self.entity_id},
context=self._context,
blocking=True,
)

async def _async_close_valve_entity(self) -> None:
Expand All @@ -346,4 +360,5 @@ async def _async_close_valve_entity(self) -> None:
SERVICE_CLOSE_VALVE,
{ATTR_ENTITY_ID: self.entity_id},
context=self._context,
blocking=True,
)
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,12 @@ def is_warmer_outside(self) -> bool:

def is_too_cold(self, target_attr="_target_temp") -> bool:
"""Checks if the current temperature is below target."""
if self._cur_temp is None:
return False
target_temp = getattr(self, target_attr)
if self._cur_temp is None or target_temp is None:
return False

_LOGGER.debug(
"Target temp attr: %s, Target temp: %s, current temp: %s, tolerance: %s",
"is_too_cold - target temp attr: %s, Target temp: %s, current temp: %s, tolerance: %s",
target_attr,
target_temp,
self._cur_temp,
Expand All @@ -358,23 +359,37 @@ def is_too_cold(self, target_attr="_target_temp") -> bool:

def is_too_hot(self, target_attr="_target_temp") -> bool:
"""Checks if the current temperature is above target."""
if self._cur_temp is None:
return False
target_temp = getattr(self, target_attr)
if self._cur_temp is None or target_temp is None:
return False

_LOGGER.debug(
"is_too_hot - target temp attr: %s, Target temp: %s, current temp: %s, tolerance: %s",
target_attr,
target_temp,
self._cur_temp,
self._hot_tolerance,
)
return self._cur_temp >= target_temp + self._hot_tolerance

@property
def is_too_moist(self) -> bool:
"""Checks if the current humidity is above target."""
if self._cur_humidity is None:
if self._cur_humidity is None or self._target_humidity is None:
return False
return self._cur_humidity >= self._target_humidity + self._moist_tolerance

@property
def is_too_dry(self) -> bool:
"""Checks if the current humidity is below target."""
if self._cur_humidity is None:
if self._cur_humidity is None or self._target_humidity is None:
return False
_LOGGER.debug(
"is_too_dry - Target humidity: %s, current humidity: %s, tolerance: %s",
self._target_humidity,
self._cur_humidity,
self._dry_tolerance,
)
return self._cur_humidity <= self._target_humidity - self._dry_tolerance

@property
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging

from homeassistant.components.climate import HVACAction
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
Expand Down Expand Up @@ -104,7 +105,7 @@ def _get_hvac_power_tolerance(self, is_temperature: bool) -> int:
)

def update_hvac_power(
self, strategy: HvacEnvStrategy, target_env_attr: str
self, strategy: HvacEnvStrategy, target_env_attr: str, hvac_action: HVACAction
) -> None:
"""updates the hvac power level based on the strategy and the target environment attribute"""

Expand All @@ -113,7 +114,15 @@ def update_hvac_power(
goal_reached = strategy.hvac_goal_reached
goal_not_reached = strategy.hvac_goal_not_reached

if goal_reached:
_LOGGER.debug("goal reached: %s", goal_reached)
_LOGGER.debug("goal not reached: %s", goal_not_reached)
_LOGGER.debug("hvac_action: %s", hvac_action)

if (
goal_reached
or hvac_action == HVACAction.OFF
or hvac_action == HVACAction.IDLE
):
_LOGGER.debug("Updating hvac power because goal reached")
self._hvac_power_level = 0
self._hvac_power_percent = 0
Expand Down Expand Up @@ -160,6 +169,13 @@ def _calculate_power_level(self, step_value: float, env_difference: float) -> in

calculated_power_level = round(env_difference / step_value)

_LOGGER.debug(
"calculated power level, max_power_level, min_power_Level: %s, %s, %s",
calculated_power_level,
self._hvac_power_max,
self._hvac_power_min,
)

return max(
self._hvac_power_min, min(calculated_power_level, self._hvac_power_max)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,27 @@ def _is_opening_open(self, opening: TIMED_OPENING_SCHEMA) -> bool: # type: igno
_is_open = True
_LOGGER.debug(
"No timeout mode for opening %s, is open: %s.",
opening_entity,
opening,
_is_open,
)
return _is_open

def _is_opening_timed_out(self, opening: TIMED_OPENING_SCHEMA) -> bool: # type: ignore
opening_entity = opening[ATTR_ENTITY_ID]
_is_open = False

_LOGGER.debug(
"Checking if opening %s is timed out, state: %s, timeout: %s, is_timed_out: %s",
opening,
self.hass.states.get(opening_entity),
opening[ATTR_TIMEOUT],
condition.state(
self.hass,
opening_entity,
STATE_OPEN,
opening[ATTR_TIMEOUT],
),
)
if condition.state(
self.hass,
opening_entity,
Expand Down
Loading

0 comments on commit de08b65

Please sign in to comment.