diff --git a/custom_components/peaqhvac/binary_sensor.py b/custom_components/peaqhvac/binary_sensor.py index fc7c270b..d6bed3a3 100644 --- a/custom_components/peaqhvac/binary_sensor.py +++ b/custom_components/peaqhvac/binary_sensor.py @@ -1,4 +1,4 @@ -from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import BinarySensorEntity, BinarySensorDeviceClass from homeassistant.core import HomeAssistant from .const import DOMAIN, PEAQENABLED @@ -13,8 +13,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities): hub = hass.data[DOMAIN]["hub"] - peaqsensors = [] - peaqsensors.append(PeaqBinarySensorEnabled(hub)) + peaqsensors = [PeaqBinarySensorEnabled(hub)] async_add_entities(peaqsensors) diff --git a/custom_components/peaqhvac/sensor.py b/custom_components/peaqhvac/sensor.py index a9e54986..b298e680 100644 --- a/custom_components/peaqhvac/sensor.py +++ b/custom_components/peaqhvac/sensor.py @@ -64,9 +64,8 @@ async def _gather_sensors(hub, config) -> list: } ] - ret = [] + ret = [OffsetSensor(hub, config.entry_id, "calculated hvac offset")] - ret.append(OffsetSensor(hub, config.entry_id, "calculated hvac offset")) for a in AVERAGESENSORS: ret.append(AverageSensor(hub, config.entry_id, a)) for sensor in TRENDSENSORS: diff --git a/custom_components/peaqhvac/sensors/min_maxsensor.py b/custom_components/peaqhvac/sensors/min_maxsensor.py index d2add85e..952087ff 100644 --- a/custom_components/peaqhvac/sensors/min_maxsensor.py +++ b/custom_components/peaqhvac/sensors/min_maxsensor.py @@ -48,12 +48,8 @@ def update(self) -> None: @property def extra_state_attributes(self) -> dict: - attr_dict = {} - - attr_dict["max"] = float(self._max) - attr_dict["min"] = float(self._min) - attr_dict["median"] = float(self._median) - attr_dict["values"] = list(self._all_values) + attr_dict = {"max": float(self._max), "min": float(self._min), "median": float(self._median), + "values": list(self._all_values)} return attr_dict diff --git a/custom_components/peaqhvac/sensors/offsetsensor.py b/custom_components/peaqhvac/sensors/offsetsensor.py index 7bf3a1f1..dd0a71da 100644 --- a/custom_components/peaqhvac/sensors/offsetsensor.py +++ b/custom_components/peaqhvac/sensors/offsetsensor.py @@ -19,6 +19,7 @@ def __init__(self, hub, entry_id, name): self._peaks_today = [] self._peaks_tomorrow = [] self._prognosis = [] + self._aux_dict = {} @property def unit_of_measurement(self): diff --git a/custom_components/peaqhvac/sensors/trendsensor.py b/custom_components/peaqhvac/sensors/trendsensor.py index 3cbdbcc3..d7145123 100644 --- a/custom_components/peaqhvac/sensors/trendsensor.py +++ b/custom_components/peaqhvac/sensors/trendsensor.py @@ -37,12 +37,9 @@ def icon(self) -> str: @property def extra_state_attributes(self) -> dict: - attr_dict = {} - attr_dict["samples"] = self._samples - attr_dict["oldest_sample"] = self._oldest_sample - attr_dict["newest_sample"] = self._newest_sample - attr_dict["samples_raw"] = self._samples_raw - attr_dict["latest_restart"] = self._latest_restart + attr_dict = {"samples": self._samples, "oldest_sample": self._oldest_sample, + "newest_sample": self._newest_sample, "samples_raw": self._samples_raw, + "latest_restart": self._latest_restart} for k, v in self._extra_attributes.items(): attr_dict[k] = v[0](v[1]) return attr_dict diff --git a/custom_components/peaqhvac/service/hub/hub.py b/custom_components/peaqhvac/service/hub/hub.py index 9e3f1639..b4f7dd3d 100644 --- a/custom_components/peaqhvac/service/hub/hub.py +++ b/custom_components/peaqhvac/service/hub/hub.py @@ -33,6 +33,7 @@ class Hub: def __init__(self, hass: HomeAssistant, hub_options: ConfigModel): self._is_initialized = False self.state_machine = hass + self.trackerentities = [] self.observer = Observer(hass) #todo: move to creation factory self.options = hub_options self.peaqev_discovered: bool = self.get_peaqev() @@ -59,7 +60,6 @@ async def async_setup(self) -> None: await self.prognosis.async_update_weather() async def async_setup_trackers(self): - self.trackerentities = [] self.trackerentities.append(self.spotprice.entity) self.trackerentities.extend(self.options.indoor_tempsensors) self.trackerentities.extend(self.options.outdoor_tempsensors) @@ -68,13 +68,6 @@ async def async_setup_trackers(self): self.state_machine, self.trackerentities, self._async_on_change ) - def price_below_min(self, hour:datetime) -> bool: - try: - return self.spotprice.model.prices[hour.hour] <= self.sensors.peaqev_facade.min_price - except: - _LOGGER.warning(f"Unable to get price for hour {hour}. min_price: {self.sensors.peaqev_facade.min_price}, num_prices_today: {len(self.spotprice.model.prices)}") - return False - @property def is_initialized(self) -> bool: if self._is_initialized: @@ -125,11 +118,6 @@ async def call_enable_peaq(self): async def call_disable_peaq(self): self.sensors.peaqhvac_enabled.value = False - async def call_set_mode(self, mode): - # match towards enum. set hub to that state. - pass - - async def async_get_internal_sensor(self, entity): lookup = { LATEST_WATER_BOOST: partial(getattr, self.hvac.water_heater, "latest_boost_call"), diff --git a/custom_components/peaqhvac/service/hub/target_temp.py b/custom_components/peaqhvac/service/hub/target_temp.py index 387986d1..1a99c0e1 100644 --- a/custom_components/peaqhvac/service/hub/target_temp.py +++ b/custom_components/peaqhvac/service/hub/target_temp.py @@ -15,15 +15,15 @@ def adjusted_tolerances(offset: int, min_tolerance, max_tolerance) -> Tuple[float, float]: # if abs(offset) <= 1: return min_tolerance, max_tolerance - _max_tolerance = ( - max_tolerance + (offset / 15) if offset > 0 else max_tolerance - ) - _min_tolerance = ( - min_tolerance + (abs(offset) / 10) - if offset < 0 - else min_tolerance - ) - return max(_min_tolerance, 0.1), max(_max_tolerance, 0.1) + # _max_tolerance = ( + # max_tolerance + (offset / 15) if offset > 0 else max_tolerance + # ) + # _min_tolerance = ( + # min_tolerance + (abs(offset) / 10) + # if offset < 0 + # else min_tolerance + # ) + # return max(_min_tolerance, 0.1), max(_max_tolerance, 0.1) class TargetTemp(ObserverBroadcaster): @@ -106,7 +106,8 @@ def _init_tolerances(self, preset: HvacPresets = HvacPresets.Normal): - def _minmax(self, desired_temp) -> float: + @staticmethod + def _minmax(desired_temp) -> float: if desired_temp < MINTEMP: return MINTEMP if desired_temp > MAXTEMP: diff --git a/custom_components/peaqhvac/service/hub/weather_prognosis.py b/custom_components/peaqhvac/service/hub/weather_prognosis.py index 55ba82ae..ceb584fc 100644 --- a/custom_components/peaqhvac/service/hub/weather_prognosis.py +++ b/custom_components/peaqhvac/service/hub/weather_prognosis.py @@ -49,6 +49,7 @@ async def async_update_weather(self, *args): if ret != self._weather_export_model: self.observer.broadcast(ObserverTypes.PrognosisChanged) self._weather_export_model = ret + _LOGGER.debug("Weather-prognosis updated", ret) async def update_weather_prognosis(self): try: @@ -93,18 +94,15 @@ def get_hvac_prognosis(self, current_temperature: float) -> list: corrected_temp_delta = 0 now = datetime.now(timezone.utc).replace(minute=0, second=0, microsecond=0) - valid_progs = [ - p for idx, p in enumerate(self.prognosis_list) if p.DT >= now - ] + valid_progs = [p for idx, p in enumerate(self.prognosis_list) if p.DT >= now] if len(valid_progs) == 0: return ret for p in valid_progs: c = p.DT - now if c.seconds == 0: - corrected_temp_delta = round( - self._current_temperature - p.Temperature, 2 - ) + corrected_temp_delta = round(self._current_temperature - p.Temperature, 2) continue + temp = self._get_temp(p, corrected_temp_delta, c) hourdiff = int(c.seconds / 3600) hour_prognosis = PrognosisExportModel( @@ -115,12 +113,14 @@ def get_hvac_prognosis(self, current_temperature: float) -> list: TimeDelta=hourdiff, _base_temp = self._current_temperature ) + #_LOGGER.debug(f"Hour prognosis: {hour_prognosis.prognosis_temp}, {hour_prognosis.corrected_temp}, {hour_prognosis.DT}, {hour_prognosis.TimeDelta}") ret.append(hour_prognosis) self._hvac_prognosis_list = ret return ret - def _get_temp(self, p, corrected_temp_delta, c): + @staticmethod + def _get_temp(p, corrected_temp_delta, c): if 3600 <= c.seconds <= 14400: decay_factor = 1 / (c.seconds / 3600) corr = corrected_temp_delta * decay_factor @@ -129,6 +129,7 @@ def _get_temp(self, p, corrected_temp_delta, c): return p.Temperature def _get_weatherprognosis_hourly_adjustment(self, hour, offset) -> int: + _LOGGER.debug(f"Getting weatherprognosis adjustment for hour {hour} with offset {offset}") try: now = datetime.now().replace(hour=hour, minute=0, second=0, microsecond=0) proghour = now @@ -142,31 +143,37 @@ def _get_weatherprognosis_hourly_adjustment(self, hour, offset) -> int: adjustment_divisor = 2.5 if _next_prognosis.windchill_temp > -2 else 2 adj = (int(round((_next_prognosis.delta_temp_from_now / adjustment_divisor) * divisor, 0)) * -1) ret = offset + adj + else: + _LOGGER.debug(f"Could not find next prognosis for hour {hour}") return ret except Exception as e: _LOGGER.error(f"Could not get weatherprognosis adjustment: {e}") return offset def _set_prognosis(self, import_list: list): - ret = [] - for i in import_list: - ret.append( - WeatherObject( - _DTstr=i["datetime"], - WeatherCondition=i["condition"], - Temperature=i["temperature"], - Wind_Speed=i["wind_speed"], - Wind_Bearing=i["wind_bearing"], - Precipitation_Probability=i["precipitation_probability"], - Precipitation=i["precipitation"], + try: + ret = [] + for i in import_list: + ret.append( + WeatherObject( + _DTstr=i["datetime"], + WeatherCondition=i["condition"], + Temperature=i["temperature"], + Wind_Speed=i["wind_speed"], + Wind_Bearing=i["wind_bearing"], + Precipitation_Probability=i["precipitation_probability"], + Precipitation=i["precipitation"], + ) ) - ) - if ret != self.prognosis_list: - self.prognosis_list = ret - self.observer.broadcast(ObserverTypes.PrognosisChanged) + if ret != self.prognosis_list: + self.prognosis_list = ret + self.observer.broadcast(ObserverTypes.PrognosisChanged) + except Exception as e: + _LOGGER.error(f"Could not finalize _set_prognosis: {e}") + @staticmethod def _correct_temperature_for_windchill( - self, temp: float, windspeed: float + temp: float, windspeed: float ) -> float: windspeed_corrected = windspeed ret = 13.12 diff --git a/custom_components/peaqhvac/service/hvac/house_heater/house_heater_coordinator.py b/custom_components/peaqhvac/service/hvac/house_heater/house_heater_coordinator.py index 6a78432c..4bfbf738 100644 --- a/custom_components/peaqhvac/service/hvac/house_heater/house_heater_coordinator.py +++ b/custom_components/peaqhvac/service/hvac/house_heater/house_heater_coordinator.py @@ -14,6 +14,8 @@ from custom_components.peaqhvac.service.models.enums.demand import Demand from peaqevcore.common.models.observer_types import ObserverTypes +from custom_components.peaqhvac.service.models.enums.hvacoperations import HvacOperations + _LOGGER = logging.getLogger(__name__) OFFSET_MIN_VALUE = -10 @@ -114,8 +116,8 @@ async def async_calculated_offsetdata(self, current_offset: int) -> CalculatedOf current_temp_trend_offset=temptrend) if ret != self._calculated_offsetdata: self._calculated_offsetdata = ret - _LOGGER.debug("Calculated offsetdata updated, so pushing update operation.") - await self.observer.async_broadcast(ObserverTypes.UpdateOperation, None) + # _LOGGER.debug("Calculated offsetdata updated, so pushing update operation.") + # await self.observer.async_broadcast(ObserverTypes.UpdateOperation, (HvacOperations.Offset, ret.sum_values())) return ret async def async_update_operation(self): diff --git a/custom_components/peaqhvac/service/hvac/house_heater/house_heater_helpers.py b/custom_components/peaqhvac/service/hvac/house_heater/house_heater_helpers.py index 5fd4fd50..31cd8a65 100644 --- a/custom_components/peaqhvac/service/hvac/house_heater/house_heater_helpers.py +++ b/custom_components/peaqhvac/service/hvac/house_heater/house_heater_helpers.py @@ -65,24 +65,6 @@ def helper_get_demand(self) -> Demand: ) return Demand.ErrorDemand - def _keep_compressor_running(self, offsetdata: CalculatedOffsetModel, force_update: bool) -> bool: - """in certain conditions, up the offset to keep the compressor running for energy savings""" - dm_zero_prediction = self._hvac.hub.sensors.dm_trend.predicted_time_at_value(0) - now = datetime.now() - if dm_zero_prediction is not None: - if all([ - self._hvac.hvac_mode is HvacMode.Heat, - self._hvac.compressor_frequency > 0, - self._hvac.hub.sensors.average_temp_outdoors.value < 0, - dm_zero_prediction < now + timedelta(hours=1) - ]): - offsetdata.current_offset += 1 - force_update = True - self.aux_offset_adjustments[OffsetAdjustments.KeepCompressorRunning] = 1 - else: - self.aux_offset_adjustments[OffsetAdjustments.KeepCompressorRunning] = 0 - return force_update - def temporarily_lower_offset(self, offsetdata: CalculatedOffsetModel) -> bool: if self._wait_timer_breach.is_timeout(): if any([self._lower_offset_threshold_breach(), self._lower_offset_addon()]): diff --git a/custom_components/peaqhvac/service/hvac/house_ventilation.py b/custom_components/peaqhvac/service/hvac/house_ventilation.py index d2283e71..e76d8ca7 100644 --- a/custom_components/peaqhvac/service/hvac/house_ventilation.py +++ b/custom_components/peaqhvac/service/hvac/house_ventilation.py @@ -59,7 +59,7 @@ def _check_hvac_fan_speed(self) -> None: ) self._latest_seen_fan_speed = self._hvac.fan_speed - async def async_check_vent_boost(self, caller=None) -> None: + async def async_check_vent_boost(self, *args) -> None: if self._hvac.hub.sensors.temp_trend_indoors.samples > 0 and time.time() - self._wait_timer_boost.value > WAITTIMER_VENT: if self._vent_boost_warmth(): await self.async_vent_boost_start("Vent boosting because of warmth.") diff --git a/custom_components/peaqhvac/service/hvac/hvactypes/nibe.py b/custom_components/peaqhvac/service/hvac/hvactypes/nibe.py index 2c5a4d9a..7b2f3efd 100644 --- a/custom_components/peaqhvac/service/hvac/hvactypes/nibe.py +++ b/custom_components/peaqhvac/service/hvac/hvactypes/nibe.py @@ -12,6 +12,7 @@ NIBE_MAX_THRESHOLD = 10 NIBE_MIN_THRESHOLD = -10 + class Nibe(IHvac): domain = "Nibe" water_heater_entity = None @@ -27,7 +28,6 @@ def get_sensor(self, sensor: SensorType = None): types = { SensorType.HvacMode: f"sensor.{self.hub.options.systemid}_priority", SensorType.Offset: f"number.{self.hub.options.systemid}_heating_offset_climate_system_1", - #SensorType.DegreeMinutes: f"sensor.{self.hub.options.systemid}_degree_minutes_40941", SensorType.DegreeMinutes: f"number.{self.hub.options.systemid}_current_value", SensorType.WaterTemp: f"sensor.{self.hub.options.systemid}_hot_water_charging_bt6", SensorType.HvacTemp: f"sensor.{self.hub.options.systemid}_supply_line_bt2", @@ -51,6 +51,7 @@ def fan_speed(self) -> float: speed = self.get_sensor(SensorType.FanSpeed) return float(self._handle_sensor(speed)) except Exception as e: + _LOGGER.exception(e) return 0 @property @@ -63,59 +64,8 @@ def delta_return_temp(self): _LOGGER.debug(f"Unable to calculate delta return: {e}") return 0 - @property - def hvac_mode(self) -> HvacMode: - """ - 'enumValues': [ - { - 'value': '10', - 'text': 'Off', - 'icon': '' - }, - { - 'value': '20', - 'text': 'Hot water', - 'icon': '' - }, - { - 'value': '30', - 'text': 'Heating', - 'icon': '' - }, - { - 'value': '40', - 'text': 'Pool', - 'icon': '' - }, - { - 'value': '41', - 'text': 'Pool 2', - 'icon': '' - }, - { - 'value': '50', - 'text': 'Transfer', - 'icon': '' - }, - { - 'value': '60', - 'text': 'Cooling', - 'icon': '' - } - ], - """ - value_lookup = { - "Off": HvacMode.Idle, - "Hot water": HvacMode.Water, - "Heating": HvacMode.Heat, - } - sensor = self.get_sensor(SensorType.HvacMode) - ret = self._handle_sensor(sensor) - if ret is not None: - return value_lookup.get(ret, HvacMode.Unknown) - return HvacMode.Unknown - - def _service_domain_per_operation(self, operation: HvacOperations) -> str: + @staticmethod + def _service_domain_per_operation(operation: HvacOperations) -> str: match operation: case HvacOperations.Offset: return "number" @@ -123,7 +73,8 @@ def _service_domain_per_operation(self, operation: HvacOperations) -> str: return "switch" raise ValueError(f"Operation {operation} not supported") - def _transform_servicecall_value(self, value: any, operation: HvacOperations) -> any: + @staticmethod + def _transform_servicecall_value(value: any, operation: HvacOperations) -> any: match operation: case HvacOperations.Offset: return "set_value" diff --git a/custom_components/peaqhvac/service/hvac/interfaces/ihvac.py b/custom_components/peaqhvac/service/hvac/interfaces/ihvac.py index fda5bd9f..91299246 100644 --- a/custom_components/peaqhvac/service/hvac/interfaces/ihvac.py +++ b/custom_components/peaqhvac/service/hvac/interfaces/ihvac.py @@ -3,7 +3,7 @@ import logging from abc import abstractmethod import time -from datetime import datetime, timedelta +from datetime import timedelta from typing import TYPE_CHECKING, Tuple from homeassistant.helpers.event import async_track_time_interval @@ -33,6 +33,19 @@ HvacOperations.VentBoost: 1800, } +ADDON_VALUE_CONVERSION = { + "Alarm": False, + "Blocked": False, + "Off": False, + "Active": True, + } + +HVACMODE_LOOKUP = { + "Off": HvacMode.Idle, + "Hot water": HvacMode.Water, + "Heating": HvacMode.Heat, + } + class IHvac: _force_update: bool = False @@ -47,8 +60,6 @@ def __init__(self, hass: HomeAssistant, hub: Hub, observer: IObserver): self.hub = hub self.observer = observer self._hass = hass - self._hvac_dm: int = None - self.raw_offset: int = 0 self.house_heater = HouseHeaterCoordinator(hvac=self, hub=hub, observer=observer) self.water_heater = WaterHeater(hub=hub, observer=observer) self.house_ventilation = HouseVentilation(hvac=self, observer=observer) @@ -66,9 +77,45 @@ def delta_return_temp(self): pass @property - @abstractmethod def hvac_mode(self) -> HvacMode: - pass + """ + 'enumValues': [ + { + 'value': '10', + 'text': 'Off', + }, + { + 'value': '20', + 'text': 'Hot water', + }, + { + 'value': '30', + 'text': 'Heating', + }, + { + 'value': '40', + 'text': 'Pool', + }, + { + 'value': '41', + 'text': 'Pool 2', + }, + { + 'value': '50', + 'text': 'Transfer', + }, + { + 'value': '60', + 'text': 'Cooling', + } + ], + """ + + sensor = self.get_sensor(SensorType.HvacMode) + ret = self._handle_sensor(sensor) + if ret is not None: + return HVACMODE_LOOKUP.get(ret, HvacMode.Unknown) + return HvacMode.Unknown @property @abstractmethod @@ -94,8 +141,8 @@ def hvac_dm(self) -> int: ret = self.get_value(SensorType.DegreeMinutes, int) if ret not in range(-10000, 101): _LOGGER.warning(f"DM is out of range: {ret}") - if self._hvac_dm != ret: - self._hvac_dm = ret + if self.model.hvac_dm != ret: + self.model.hvac_dm = ret self.hub.sensors.dm_trend.add_reading(ret, time.time()) return ret @@ -105,14 +152,8 @@ def compressor_frequency(self) -> int: @property def hvac_electrical_addon(self) -> bool: - value_conversion = { - "Alarm": False, - "Blocked": False, - "Off": False, - "Active": True, - } ret = self.get_value(SensorType.ElectricalAddition, str) - return value_conversion.get(ret, False) + return ADDON_VALUE_CONVERSION.get(ret, False) @property def hvac_compressor_start(self) -> int: @@ -131,8 +172,8 @@ async def async_update_hvac(self) -> None: async def async_update_offset(self, raw_offset:int|None = None) -> bool: if raw_offset: - if int(raw_offset) != self.raw_offset: - self.raw_offset = int(raw_offset) + if int(raw_offset) != self.model.raw_offset: + self.model.raw_offset = int(raw_offset) ret = False if self.hub.sensors.peaqev_installed: if len(self.hub.sensors.peaqev_facade.offsets.get("today", {})) < 20: @@ -140,10 +181,10 @@ async def async_update_offset(self, raw_offset:int|None = None) -> bool: try: _hvac_offset = self.hvac_offset new_offset, force_update = await self.house_heater.async_adjusted_offset( - self.raw_offset + self.model.raw_offset ) if new_offset != self.model.current_offset: - _LOGGER.debug(f"Offset changed from {self.model.current_offset} to {new_offset}, with raw input {self.raw_offset}.") + _LOGGER.debug(f"Offset changed from {self.model.current_offset} to {new_offset}, with raw input {self.model.raw_offset}.") self.model.current_offset = new_offset self._force_update = force_update if self.model.current_offset != _hvac_offset: diff --git a/custom_components/peaqhvac/service/hvac/offset/offset_cache.py b/custom_components/peaqhvac/service/hvac/offset/offset_cache.py deleted file mode 100644 index 4ce52f69..00000000 --- a/custom_components/peaqhvac/service/hvac/offset/offset_cache.py +++ /dev/null @@ -1,77 +0,0 @@ -from datetime import datetime, date, timedelta -from dataclasses import dataclass, field -from typing import List -import logging -import uuid - -_LOGGER = logging.getLogger(__name__) - - -@dataclass -class CacheDict: - id: uuid = field(init=False) - today: bool - prices: List[float] - offsets: dict[int, float] - dt: date - - def __post_init__(self): - self.id = uuid.uuid4() - - -_offsetCache: List[CacheDict] = [] - - -def get_cache(dt: date) -> CacheDict: - for h in _offsetCache: - if h.dt == dt: - return h - return None - - -def get_cache_for_today(dt: date, prices: list) -> CacheDict: - for h in _offsetCache: - if h.dt == dt and h.prices == prices: - h.today = True - for h2 in _offsetCache: - if h2.id != h.id: - h2.today = False - return h - return None - - -def update_cache(list_dt: date, prices: List[float], offsets: dict[int, float], now_dt: datetime = datetime.now()): - global _offsetCache - if len(prices) < 1 or len(offsets) < 1: - """Don't update cache if no data is available""" - return - - data = [h.dt for h in _offsetCache] - - if now_dt.date() == list_dt: - """This item is regarding today""" - if list_dt in data: - for h in _offsetCache: - if h.dt == list_dt and not h.today: - _LOGGER.debug("Updating existing today-item") - h.today = True - elif now_dt.date() not in data: - _offsetCache.append(CacheDict(True, prices, offsets, now_dt.date())) - else: - """This item is regarding tomorrow""" - if list_dt not in data: - _offsetCache.append(CacheDict(False, prices, offsets, list_dt)) - else: - for h in _offsetCache: - if h.dt != now_dt: - h.today = False - """Remove old items""" - _offsetCache = [h for h in _offsetCache if h.dt >= now_dt.date() - timedelta(days=2)] - -# Usage -# update_cache(now_dt=datetime(2023, 1, 1, 0, 0, 3), list_dt=date(2023, 1, 1), prices=[1], offsets=[1, 2, 3]) -# update_cache(now_dt=datetime(2023, 1, 1, 13, 0, 3), list_dt=date(2023, 1, 2), prices=[2], offsets=[1, 2, 3]) -# update_cache(now_dt=datetime(2023, 1, 2, 0, 0, 3), list_dt=date(2023, 1, 2), prices=[3], offsets=[1, 2, 3]) -# -# for i in _offsetCache: -# print(i) \ No newline at end of file diff --git a/custom_components/peaqhvac/service/hvac/offset/offset_coordinator.py b/custom_components/peaqhvac/service/hvac/offset/offset_coordinator.py index b6ad8a13..0bbb7af5 100644 --- a/custom_components/peaqhvac/service/hvac/offset/offset_coordinator.py +++ b/custom_components/peaqhvac/service/hvac/offset/offset_coordinator.py @@ -1,11 +1,8 @@ -from __future__ import annotations - import logging from abc import abstractmethod from datetime import datetime, timedelta from peaqevcore.common.models.observer_types import ObserverTypes from peaqevcore.services.hourselection.hoursselection import Hoursselection -import custom_components.peaqhvac.service.hvac.offset.offset_cache as cache from custom_components.peaqhvac.service.hvac.offset.offset_utils import ( max_price_lower_internal, offset_per_day, set_offset_dict) from custom_components.peaqhvac.service.hvac.offset.peakfinder import ( @@ -14,10 +11,8 @@ from custom_components.peaqhvac.service.observer.iobserver_coordinator import IObserver from homeassistant.helpers.event import async_track_time_interval - _LOGGER = logging.getLogger(__name__) - class OffsetCoordinator: """The class that provides the offsets for the hvac""" def __init__(self, hub, observer: IObserver, hours_type: Hoursselection = None): #type: ignore @@ -25,17 +20,20 @@ def __init__(self, hub, observer: IObserver, hours_type: Hoursselection = None): self.observer = observer self.model = OffsetModel(hub) self.hours = hours_type - self._current_raw_offset: int|None = None #move from here? + self._current_raw_offset: int|None = None self.latest_raw_offset_update_hour: int = -1 - self.observer.add(ObserverTypes.PrognosisChanged, self._update_prognosis) - self.observer.add(ObserverTypes.HvacPresetChanged, self._set_offset) - self.observer.add(ObserverTypes.SetTemperatureChanged, self._set_offset) - self.observer.add("ObserverTypes.OffsetPreRecalculation", self._set_offset) + self._initialize_observers() async_track_time_interval( self._hub.state_machine, self._create_current_raw_offset, timedelta(seconds=20) ) self._create_current_raw_offset() + def _initialize_observers(self): + self.observer.add(ObserverTypes.PrognosisChanged, self._update_prognosis) + self.observer.add(ObserverTypes.HvacPresetChanged, self._set_offset) + self.observer.add(ObserverTypes.SetTemperatureChanged, self._set_offset) + self.observer.add("ObserverTypes.OffsetPreRecalculation", self._set_offset) + @property @abstractmethod def prices(self) -> list: @@ -66,15 +64,13 @@ def _create_current_raw_offset(self, *args) -> None: ret = 0 initialized = False try: - if len(self.model.raw_offsets): + if self.model.raw_offsets: latest_key = max((key for key in self.model.raw_offsets if key <= datetime.now()), default=None) if latest_key is not None: ret = self.model.raw_offsets[latest_key] initialized = True except KeyError as e: - _LOGGER.error( - f"Unable to get current offset: {e}. raw_offsets: {self.model.raw_offsets}" - ) + _LOGGER.error(f"Unable to get current offset: {e}. raw_offsets: {self.model.raw_offsets}") finally: if self.current_offset is not None or initialized: if self.current_offset != ret: @@ -83,7 +79,7 @@ def _create_current_raw_offset(self, *args) -> None: def _update_prognosis(self) -> None: self.model.prognosis = self._hub.prognosis.prognosis - _LOGGER.debug("prognosis updated to", self.model.prognosis) + _LOGGER.debug(f"prognosis updated to {self.model.prognosis}") self._set_offset() @abstractmethod @@ -95,20 +91,16 @@ def max_price_lower(self, tempdiff: float) -> bool: def _update_offset(self, weather_adjusted_today: dict | None = None) -> dict: try: - all_values = set_offset_dict(self.prices+self.prices_tomorrow, datetime.now(), self.min_price,{}) + all_values = set_offset_dict(self.prices + self.prices_tomorrow, datetime.now(), self.min_price, {}) offsets_per_day = self._calculate_offset_per_day(all_values, weather_adjusted_today) tolerance = self.model.tolerance if self.model.tolerance is not None else 3 for k, v in offsets_per_day.items(): if v > tolerance: offsets_per_day[k] = tolerance - elif v < -self.model.tolerance: + elif v < -tolerance: offsets_per_day[k] = -tolerance - return smooth_transitions( - vals=offsets_per_day, - tolerance=self.model.tolerance, - ) - + return smooth_transitions(vals=offsets_per_day, tolerance=tolerance) except Exception as e: _LOGGER.exception(f"Exception while trying to calculate offset: {e}") return {} @@ -117,7 +109,7 @@ def _calculate_offset_per_day(self, day_values: dict, weather_adjusted_today: di if weather_adjusted_today is None: indoors_preset = self._hub.sensors.set_temp_indoors.preset return offset_per_day( - all_prices=self.prices+self.prices_tomorrow, + all_prices=self.prices + self.prices_tomorrow, day_values=day_values, tolerance=self.model.tolerance, indoors_preset=indoors_preset, @@ -126,29 +118,22 @@ def _calculate_offset_per_day(self, day_values: dict, weather_adjusted_today: di return weather_adjusted_today def _set_offset(self) -> None: - if self.prices is None: + if not self.prices: if self._hub.is_initialized: - _LOGGER.warning(f"Hub is ready but I'm unable to set offset. Prices num:{len(self.prices) if self.prices else 0}") + _LOGGER.warning(f"Hub is ready but I'm unable to set offset. Prices num: {len(self.prices) if self.prices else 0}") return self.model.raw_offsets = self._update_offset() self.model.calculated_offsets = self.model.raw_offsets - if len(self._hub.prognosis.prognosis) > 0: + if self._hub.prognosis.prognosis: try: _weather_dict = self._hub.prognosis.get_weatherprognosis_adjustment(self.model.raw_offsets) - if len(_weather_dict.items()) > 0: + if _weather_dict: self.model.calculated_offsets = self._update_offset(_weather_dict) except Exception as e: - _LOGGER.warning( - f"Unable to calculate prognosis-offsets. Setting normal calculation: {e}" - ) - #if len(self.model.raw_offsets): - # if not self.current_offset: - # self._create_current_raw_offset() - # if self.current_offset: - # self.observer.broadcast(ObserverTypes.OffsetRecalculation, self.current_offset) - # else: - # _LOGGER.warning(f"Unable to set offset. current_offset: {self.current_offset}. raw_offsets: {self.model.raw_offsets}") + _LOGGER.warning(f"Unable to calculate prognosis-offsets. Setting normal calculation: {e}") + else: + _LOGGER.debug("No prognosis available, setting normal calculation.") def _update_model(self) -> None: self.model.peaks_today = identify_peaks(self.prices) diff --git a/custom_components/peaqhvac/service/hvac/water_heater/models/next_water_boost_model.py b/custom_components/peaqhvac/service/hvac/water_heater/models/next_water_boost_model.py index 16d1db88..3bcf9982 100644 --- a/custom_components/peaqhvac/service/hvac/water_heater/models/next_water_boost_model.py +++ b/custom_components/peaqhvac/service/hvac/water_heater/models/next_water_boost_model.py @@ -1,14 +1,10 @@ from datetime import datetime, timedelta -from dataclasses import dataclass, field -from statistics import stdev, mean +from statistics import mean -# from custom_components.peaqhvac.service.hvac.water_heater.models.group import Group -# from custom_components.peaqhvac.service.models.enums.group_type import GroupType +from custom_components.peaqhvac.service.hvac.water_heater.models.water_boost_data import WaterBoostData from custom_components.peaqhvac.service.models.enums.demand import Demand from custom_components.peaqhvac.service.models.enums.hvac_presets import HvacPresets - - HOUR_LIMIT = 18 DELAY_LIMIT = 48 MIN_DEMAND = 26 @@ -38,7 +34,6 @@ } } - def get_demand(temp) -> Demand: if temp is None: return Demand.NoDemand @@ -54,116 +49,89 @@ def get_demand(temp) -> Demand: return Demand.HighDemand return Demand.ErrorDemand -from dataclasses import dataclass, field -from datetime import datetime, timedelta - -@dataclass class NextWaterBoostModel: - min_price: float = None # type: ignore - non_hours_raw: list[int] = field(default_factory=lambda: [], repr=False, compare=False) - demand_hours_raw: list[int] = field(default_factory=lambda: [], repr=False, compare=False) - initialized: bool = False - price_dict:dict = field(default_factory=lambda: {}) - preset: HvacPresets = HvacPresets.Normal - _now_dt: datetime = None # type: ignore - latest_boost: datetime = None # type: ignore - - temp_trend: float = DEFAULT_TEMP_TREND # type: ignore - current_temp: float = None # type: ignore - target_temp: float = None # type: ignore - - floating_mean: float = field(default=None, init=False) - non_hours: set = field(default_factory=lambda: [], init=False) - demand_hours: set = field(default_factory=lambda: {}, init=False) - - latest_calculation: datetime = field(default=None, init=False) - latest_override_demand: int = field(default=None, init=False) - should_update: bool = field(default=True, init=False) - - def __post_init__(self): - self._now_dt = datetime.now() if self.now_dt is None else self.now_dt - self.latest_boost = self.now_dt if self.latest_boost is None else self.latest_boost - self.min_price = -float('inf') if self.min_price is None else self.min_price + def __init__(self, data: WaterBoostData): + self.data = data @property def cold_limit(self) -> datetime: if self.is_cold: - return self.now_dt + return self.data.now_dt try: - hourdiff = (self.current_temp - self.target_temp) / -self.temp_trend + hour_diff = (self.data.current_temp - self.data.target_temp) / -self.data.temp_trend except ZeroDivisionError: - hourdiff = DELAY_LIMIT - return max(self.now_dt + timedelta(hours=hourdiff), self._now_dt) + hour_diff = DELAY_LIMIT + return max(self.data.now_dt + timedelta(hours=hour_diff), self.data.now_dt) @property def is_cold(self) -> bool: - return self.current_temp < self.target_temp + return self.data.current_temp < self.data.target_temp @property def demand(self) -> Demand: - return get_demand(self.current_temp) + return get_demand(self.data.current_temp) @property def demand_minutes(self) -> int: - return DEMAND_MINUTES[self.preset][self.demand] + return DEMAND_MINUTES[self.data.preset][self.demand] @property def now_dt(self) -> datetime: - return self._now_dt.replace(second=0, microsecond=0) if self._now_dt else None + return self.data.now_dt.replace(second=0, microsecond=0) if self.data.now_dt else None def _create_price_dict(self, prices) -> dict: startofday = self.now_dt.replace(hour=0, minute=0) return {startofday + timedelta(hours=i): prices[i] for i in range(0, len(prices))} def update(self, temp, temp_trend, target_temp, prices_today: list, prices_tomorrow: list, preset: HvacPresets, - now_dt=None, latest_boost: datetime = None) -> None: + now_dt=None, latest_boost: datetime = None) -> None: _old_dt = self.now_dt self.set_now_dt(now_dt) new_price_dict = self._create_price_dict(prices_today + prices_tomorrow) - if new_price_dict != self.price_dict: + if new_price_dict != self.data.price_dict: if all([ any([k for k in new_price_dict.keys() if k.date() != self.now_dt.date()]), - not any([k for k in self.price_dict.keys() if k.date() != self.now_dt.date()]) + not any([k for k in self.data.price_dict.keys() if k.date() != self.now_dt.date()]) ]): - self.latest_calculation = None - self.price_dict = new_price_dict - self.should_update = True - new_non_hours = self._set_hours(self.non_hours_raw, preset) - new_demand_hours = self._set_hours(self.demand_hours_raw, preset) + self.data.latest_calculation = None + self.data.price_dict = new_price_dict + self.data.should_update = True + new_non_hours = self._set_hours(self.data.non_hours_raw, preset) + new_demand_hours = self._set_hours(self.data.demand_hours_raw, preset) new_temp_trend = DEFAULT_TEMP_TREND if temp_trend > DEFAULT_TEMP_TREND else temp_trend if any([ _old_dt.hour != self.now_dt.hour, - self.latest_boost != latest_boost, - self.non_hours != new_non_hours, - self.demand_hours != new_demand_hours, - self.preset != preset, - self.temp_trend != new_temp_trend, - self.current_temp != temp, - self.target_temp != target_temp - ]) and not self.should_update: - self.should_update = True - - self.latest_boost = latest_boost - self.non_hours = new_non_hours - self.demand_hours = new_demand_hours + self.data.latest_boost != latest_boost, + self.data.non_hours != new_non_hours, + self.data.demand_hours != new_demand_hours, + self.data.preset != preset, + self.data.temp_trend != new_temp_trend, + self.data.current_temp != temp, + self.data.target_temp != target_temp + ]) and not self.data.should_update: + self.data.should_update = True + + self.data.latest_boost = latest_boost + self.data.non_hours = new_non_hours + self.data.demand_hours = new_demand_hours self.set_floating_mean() - self.preset = preset - self.temp_trend = new_temp_trend - self.current_temp = temp - self.target_temp = target_temp - self.initialized = True + self.data.preset = preset + self.data.temp_trend = new_temp_trend + self.data.current_temp = temp + self.data.target_temp = target_temp + self.data.initialized = True def get_demand_minutes(self, expected_temp) -> int: - return DEMAND_MINUTES[self.preset][get_demand(expected_temp)] + return DEMAND_MINUTES[self.data.preset][get_demand(expected_temp)] def _set_hours(self, input_hours: list, preset: HvacPresets) -> set: if preset == HvacPresets.Away: return set() - return {k for k in self.price_dict.keys() if k.hour in input_hours} + return {k for k in self.data.price_dict.keys() if k.hour in input_hours} def set_now_dt(self, now_dt=None) -> None: - self._now_dt = datetime.now() if now_dt is None else now_dt + self.data.now_dt = now_dt or datetime.now() - def set_floating_mean(self, now_dt=None) -> None: - self.floating_mean = mean([v for k,v in self.price_dict.items() if k >=self.now_dt])*0.9 \ No newline at end of file + def set_floating_mean(self) -> None: + self.data.floating_mean = mean([v for k, v in self.data.price_dict.items() if k >= self.now_dt]) * 0.9 \ No newline at end of file diff --git a/custom_components/peaqhvac/service/hvac/water_heater/models/water_boost_data.py b/custom_components/peaqhvac/service/hvac/water_heater/models/water_boost_data.py new file mode 100644 index 00000000..84247108 --- /dev/null +++ b/custom_components/peaqhvac/service/hvac/water_heater/models/water_boost_data.py @@ -0,0 +1,28 @@ +from datetime import datetime +from dataclasses import dataclass, field +from custom_components.peaqhvac.service.models.enums.hvac_presets import HvacPresets + +@dataclass +class WaterBoostData: + min_price: float = None # type: ignore + non_hours_raw: list[int] = field(default_factory=lambda: [], repr=False, compare=False) + demand_hours_raw: list[int] = field(default_factory=lambda: [], repr=False, compare=False) + initialized: bool = False + price_dict: dict = field(default_factory=lambda: {}) + preset: HvacPresets = HvacPresets.Normal + now_dt: datetime = None # type: ignore + latest_boost: datetime = None # type: ignore + temp_trend: float = -0.5 # type: ignore + current_temp: float = None # type: ignore + target_temp: float = None # type: ignore + floating_mean: float = field(default=None, init=False) + non_hours: set = field(default_factory=lambda: [], init=False) + demand_hours: set = field(default_factory=lambda: {}, init=False) + latest_calculation: datetime | None = field(default=None, init=False) + latest_override_demand: int = field(default=None, init=False) + should_update: bool = field(default=True, init=False) + + def __post_init__(self): + self.now_dt = datetime.now() if self.now_dt is None else self.now_dt + self.latest_boost = self.now_dt if self.latest_boost is None else self.latest_boost + self.min_price = -float('inf') if self.min_price is None else self.min_price \ No newline at end of file diff --git a/custom_components/peaqhvac/service/hvac/water_heater/water_heater_next_start.py b/custom_components/peaqhvac/service/hvac/water_heater/water_heater_next_start.py index 0946d1a6..d35dbc90 100644 --- a/custom_components/peaqhvac/service/hvac/water_heater/water_heater_next_start.py +++ b/custom_components/peaqhvac/service/hvac/water_heater/water_heater_next_start.py @@ -75,7 +75,8 @@ def get_next_start(self, model: NextStartPostModel) -> NextStartExportModel: selected = self.get_final_selected(filtered, selected) return NextStartExportModel(selected.time, selected.target_temp) - def _calculate_target_temp_for_hour(self, temp_at_time: float, is_demand: bool, price: float, price_spread:float, min_price:float) -> int: + @staticmethod + def _calculate_target_temp_for_hour(temp_at_time: float, is_demand: bool, price: float, price_spread:float, min_price:float) -> int: target = TARGET_TEMP if price > min_price else MAX_TARGET_TEMP if int(target - temp_at_time) <= 0: return target @@ -93,7 +94,8 @@ def _calculate_target_temp_for_hour(self, temp_at_time: float, is_demand: bool, return min(int(temp_at_time+add_temp), target) - def _get_temperature_at_datetime(self, now_dt, target_dt, current_temp, temp_trend) -> float: + @staticmethod + def _get_temperature_at_datetime(now_dt, target_dt, current_temp, temp_trend) -> float: delay = (target_dt - now_dt).total_seconds() / 3600 return max(10,round(current_temp + (delay * temp_trend), 1)) @@ -129,7 +131,8 @@ def _calculate_is_cold(self, temp_at_time: float, second_hour: datetime, model: return temp_at_time <= calculated_water_limit - def reset_hour(self, dt) -> datetime: + @staticmethod + def reset_hour(dt) -> datetime: return dt.replace(minute=0,second=0,microsecond=0) def get_data(self, model: NextStartPostModel) -> list: diff --git a/custom_components/peaqhvac/service/hvac/water_heater/water_heater_offset.py b/custom_components/peaqhvac/service/hvac/water_heater/water_heater_offset.py deleted file mode 100644 index e81930c5..00000000 --- a/custom_components/peaqhvac/service/hvac/water_heater/water_heater_offset.py +++ /dev/null @@ -1,28 +0,0 @@ -prices = [0.34, 0.32, 0.32, 0.31, 0.32, 0.35, 0.37, 0.45, 0.51, 0.57, 0.56, 0.52, 0.5, 0.46, 0.45, 0.45, 0.45, 0.49, - 0.53, 0.54, 0.53, 0.46, 0.38, 0.36] -prices_tomorrow = [0.36, 0.35, 0.34, 0.34, 0.35, 0.35, 0.39, 0.45, 0.48, 0.48, 0.48, 0.47, 0.46, 0.44, 0.42, 0.43, 0.45, - 0.48, 0.48, 0.51, 0.5, 0.48, 0.43, 0.42] - -from datetime import datetime, timedelta - - -def get_hourly_price_category(current_hour, prices_today, prices_tomorrow): - prices = prices_today + prices_tomorrow - current_price = prices[current_hour] - next_three_hours_prices = prices[current_hour + 1:current_hour + 4] + prices[:3] - next_three_hours_avg_price = sum(next_three_hours_prices) / len(next_three_hours_prices) - price_range = max(prices) - min(prices) - category_size = price_range / 3 - if current_price < min(prices) + category_size: - return 'low' - elif current_price < min(prices) + 2 * category_size: - return 'mid' - else: - if current_price > next_three_hours_avg_price: - return 'high' - else: - return 'mid' - - -for i in range(0, 24): - print(i, get_hourly_price_category(i, prices, prices_tomorrow)) \ No newline at end of file diff --git a/custom_components/peaqhvac/service/models/config_model.py b/custom_components/peaqhvac/service/models/config_model.py index cca785fe..6ac02c7a 100644 --- a/custom_components/peaqhvac/service/models/config_model.py +++ b/custom_components/peaqhvac/service/models/config_model.py @@ -52,7 +52,8 @@ def hvac_tolerance(self, val) -> None: # "tried to broadcast an update from hvac-tolerance but referenced hub was None." # ) - def set_hvacbrand(self, configstring: str) -> HvacBrand: + @staticmethod + def set_hvacbrand(configstring: str) -> HvacBrand: branddict = { HVACBRAND_NIBE: HvacBrand.Nibe, HVACBRAND_IVT: HvacBrand.IVT, @@ -70,7 +71,8 @@ def set_sensors_from_string(self, inputstr: str) -> list: result_list.append(self._set_single_sensor(inputstr)) return result_list - def _set_single_sensor(self, sensor: str): + @staticmethod + def _set_single_sensor(sensor: str): ret = sensor if not sensor.startswith("sensor."): ret = f"sensor.{sensor}" diff --git a/custom_components/peaqhvac/service/models/ihvac_model.py b/custom_components/peaqhvac/service/models/ihvac_model.py index 4f0e7995..61c0dae8 100644 --- a/custom_components/peaqhvac/service/models/ihvac_model.py +++ b/custom_components/peaqhvac/service/models/ihvac_model.py @@ -4,9 +4,7 @@ @dataclass class IHvacModel: current_offset: int = 0 - # current_offset_dict: dict = field(default_factory=lambda: {}) - # current_offset_dict_tomorrow: dict = field(default_factory=lambda: {}) - # current_offset_dict_combined: dict = field(default_factory=lambda: {}) + hvac_dm: int | None = None + raw_offset: int = 0 - listenerentities: list = field(default_factory=lambda: []) diff --git a/custom_components/peaqhvac/service/models/offsets_exportmodel.py b/custom_components/peaqhvac/service/models/offsets_exportmodel.py index 0e298851..71887894 100644 --- a/custom_components/peaqhvac/service/models/offsets_exportmodel.py +++ b/custom_components/peaqhvac/service/models/offsets_exportmodel.py @@ -1,44 +1,52 @@ -from typing import Tuple +from typing import Tuple, List, Dict from dataclasses import dataclass, field from datetime import datetime @dataclass class OffsetsExportModel: - peaks: Tuple[list, list] - _raw_offsets: list = field(default_factory=lambda: []) - _current_offset: list = field(default_factory=lambda: []) - _current_offset_tomorrow: list = field(default_factory=lambda: []) + peaks: Tuple[List, List] + _raw_offsets: List[int] = field(default_factory=list) + _current_offset: List[int] = field(default_factory=list) + _current_offset_tomorrow: List[int] = field(default_factory=list) @property - def raw_offsets(self) -> list: + def raw_offsets(self) -> List[int]: + """Returns the raw offsets list.""" return self._raw_offsets @raw_offsets.setter - def raw_offsets(self, val:dict) -> None: + def raw_offsets(self, val: Dict) -> None: + """Sets the raw offsets list from a dictionary.""" self._raw_offsets = self._offset_dict_to_list(val) @property def current_raw_offset(self) -> int: - if len(self._raw_offsets) == 0: + """Returns the current raw offset based on the current hour.""" + if not self._raw_offsets: return 0 return self._raw_offsets[datetime.now().hour] @property - def current_offset(self) -> list: + def current_offset(self) -> List[int]: + """Returns the current offset list.""" return self._current_offset @current_offset.setter - def current_offset(self, val:dict) -> None: + def current_offset(self, val: Dict) -> None: + """Sets the current offset list from a dictionary.""" self._current_offset = self._offset_dict_to_list(val) @property - def current_offset_tomorrow(self) -> list: + def current_offset_tomorrow(self) -> List[int]: + """Returns the current offset list for tomorrow.""" return self._current_offset_tomorrow @current_offset_tomorrow.setter - def current_offset_tomorrow(self, val:dict) -> None: + def current_offset_tomorrow(self, val: Dict) -> None: + """Sets the current offset list for tomorrow from a dictionary.""" self._current_offset_tomorrow = self._offset_dict_to_list(val) @staticmethod - def _offset_dict_to_list(input: dict) -> list: - return [i for i in input.values()] \ No newline at end of file + def _offset_dict_to_list(input: Dict) -> List[int]: + """Converts a dictionary of offsets to a list.""" + return list(input.values()) \ No newline at end of file diff --git a/custom_components/peaqhvac/service/observer/iobserver_coordinator.py b/custom_components/peaqhvac/service/observer/iobserver_coordinator.py index 50369742..abfcc161 100644 --- a/custom_components/peaqhvac/service/observer/iobserver_coordinator.py +++ b/custom_components/peaqhvac/service/observer/iobserver_coordinator.py @@ -40,7 +40,8 @@ def activate(self, init_broadcast: ObserverTypes = None) -> None: def deactivate(self) -> None: self.model.active = False - def _check_and_convert_enum_type(self, command) -> ObserverTypes|str: + @staticmethod + def _check_and_convert_enum_type(command) -> ObserverTypes | str: if isinstance(command, str): try: command = ObserverTypes(command) diff --git a/custom_components/peaqhvac/service/peaqev_facade.py b/custom_components/peaqhvac/service/peaqev_facade.py index ff713b47..56c86dbd 100644 --- a/custom_components/peaqhvac/service/peaqev_facade.py +++ b/custom_components/peaqhvac/service/peaqev_facade.py @@ -88,7 +88,7 @@ def below_start_threshold(self) -> bool: try: start = self._peaqevhub.threshold.start current = self.exact_threshold - return current < (start) + return current < start except Exception as e: _LOGGER.exception(f"Error on below_start_threshold {e}") return False diff --git a/custom_components/peaqhvac/services.py b/custom_components/peaqhvac/services.py index c42ffd96..34a6c222 100644 --- a/custom_components/peaqhvac/services.py +++ b/custom_components/peaqhvac/services.py @@ -10,11 +10,6 @@ async def servicehandler_disable(call): # pylint:disable=unused-argument await hub.call_disable_peaq() - async def servicehandler_set_mode(call): - mode = call.data.get("mode") - await hub.call_set_mode(mode) - - async def servicehandler_boost_water(call): target = call.data.get("targettemp") if 10 < target < 60: @@ -23,5 +18,4 @@ async def servicehandler_boost_water(call): hass.services.async_register(DOMAIN, "enable", servicehandler_enable) hass.services.async_register(DOMAIN, "disable", servicehandler_disable) - hass.services.async_register(DOMAIN, "set_mode", servicehandler_set_mode) hass.services.async_register(DOMAIN, "boost_water", servicehandler_boost_water)