diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f97c0f90..a52eff569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Ongoing + +- Code optimizations via PR [#837](https://github.com/plugwise/python-plugwise/pull/837) + ## v1.11.0 - Extend feature: support pumping group, add group sensors diff --git a/plugwise/common.py b/plugwise/common.py index 9722975e6..795d68ed3 100644 --- a/plugwise/common.py +++ b/plugwise/common.py @@ -175,7 +175,7 @@ def _reorder_devices(self) -> None: break self.gw_entities = {**reordered, **self.gw_entities} - def _entity_switching_group(self, entity: GwEntityData, data: GwEntityData) -> None: + def _entity_switching_group(self, entity: GwEntityData) -> None: """Helper-function for _get_device_zone_data(). Determine switching group device data. @@ -185,7 +185,7 @@ def _entity_switching_group(self, entity: GwEntityData, data: GwEntityData) -> N for member in entity["members"]: if self.gw_entities[member]["switches"].get("relay"): counter += 1 - data["switches"]["relay"] = counter != 0 + entity["switches"]["relay"] = counter != 0 self._count += 1 def _get_groups(self) -> dict[str, GwEntityData]: diff --git a/plugwise/data.py b/plugwise/data.py index 3ab9f53f4..fc45138fb 100644 --- a/plugwise/data.py +++ b/plugwise/data.py @@ -45,8 +45,7 @@ def _update_zones(self) -> None: Collect data for each zone/location and add to self._zones. """ for location_id, zone in self._zones.items(): - data = self._get_location_data(location_id) - zone.update(data) + self._get_location_data(location_id, zone) def _update_gw_entities(self) -> None: """Helper-function for _all_entities_data() and async_update(). @@ -55,12 +54,11 @@ def _update_gw_entities(self) -> None: """ mac_list: list[str] = [] for entity_id, entity in self.gw_entities.items(): - data = self._get_entity_data(entity_id) + self._get_entity_data(entity_id, entity) if entity_id == self._gateway_id: mac_list = self._detect_low_batteries() - self._add_or_update_notifications(entity_id, entity, data) + self._add_or_update_notifications(entity_id, entity) - entity.update(data) is_battery_low = ( mac_list and "low_battery" in entity["binary_sensors"] @@ -106,7 +104,7 @@ def _detect_low_batteries(self) -> list[str]: return mac_address_list def _add_or_update_notifications( - self, entity_id: str, entity: GwEntityData, data: GwEntityData + self, entity_id: str, entity: GwEntityData ) -> None: """Helper-function adding or updating the Plugwise notifications.""" if ( @@ -116,8 +114,10 @@ def _add_or_update_notifications( "binary_sensors" in entity and "plugwise_notification" in entity["binary_sensors"] ): - data["binary_sensors"]["plugwise_notification"] = bool(self._notifications) - data["notifications"] = self._notifications + entity["binary_sensors"]["plugwise_notification"] = bool( + self._notifications + ) + entity["notifications"] = self._notifications self._count += 2 def _update_for_cooling(self, entity: GwEntityData) -> None: @@ -154,82 +154,76 @@ def _update_for_cooling(self, entity: GwEntityData) -> None: 3 # add 4 total, remove 1, count the conditional remove separately ) - def _get_location_data(self, loc_id: str) -> GwEntityData: + def _get_location_data(self, loc_id: str, zone: GwEntityData) -> None: """Helper-function for _all_entity_data() and async_update(). Provide entity-data, based on Location ID (= loc_id). """ - zone = self._zones[loc_id] - data = self._get_zone_data(loc_id) - self._regulation_control(data) + self._get_zone_data(loc_id, zone) + self._regulation_control(zone) - data["control_state"] = "idle" + zone["control_state"] = "idle" self._count += 1 - if (ctrl_state := self._control_state(data)) and ctrl_state in ( + if (ctrl_state := self._control_state(zone)) and ctrl_state in ( "cooling", "heating", "preheating", ): - data["control_state"] = str(ctrl_state) + zone["control_state"] = str(ctrl_state) - if "setpoint" in data["sensors"]: - data["sensors"].pop("setpoint") # remove, only used in _control_state() + if "setpoint" in zone["sensors"]: + zone["sensors"].pop("setpoint") # remove, only used in _control_state() self._count -= 1 # Thermostat data (presets, temperatures etc) - self._climate_data(loc_id, zone, data) - - return data + self._climate_data(loc_id, zone) - def _get_entity_data(self, entity_id: str) -> GwEntityData: + def _get_entity_data(self, entity_id: str, entity: GwEntityData) -> None: """Helper-function for _update_gw_entities() and async_update(). Provide entity-data, based on appliance_id (= entity_id). """ - entity = self.gw_entities[entity_id] - data = self._get_measurement_data(entity_id) + self._get_measurement_data(entity_id, entity) # Check availability of wired-connected entities # Smartmeter self._check_availability( - entity, "smartmeter", data, "P1 does not seem to be connected" + entity, "smartmeter", "P1 does not seem to be connected" ) # OpenTherm entity if entity["name"] != "OnOff": self._check_availability( - entity, "heater_central", data, "no OpenTherm communication" + entity, "heater_central", "no OpenTherm communication" ) # Switching groups data - self._entity_switching_group(entity, data) + self._entity_switching_group(entity) # Adam data if self.check_name(ADAM): - self._get_adam_data(entity, data) + self._get_adam_data(entity) # Thermostat data for Anna (presets, temperatures etc) if self.check_name(ANNA) and entity["dev_class"] == "thermostat": - self._climate_data(entity_id, entity, data) - self._get_anna_control_state(data) - - return data + self._climate_data(entity_id, entity) + self._get_anna_control_state(entity) def _check_availability( - self, entity: GwEntityData, dev_class: str, data: GwEntityData, message: str + self, entity: GwEntityData, dev_class: str, message: str ) -> None: """Helper-function for _get_entity_data(). Provide availability status for the wired-connected devices. """ if entity["dev_class"] == dev_class: - data["available"] = True + entity["available"] = True self._count += 1 for item in self._notifications.values(): for msg in item.values(): if message in msg: - data["available"] = False + entity["available"] = False break - def _get_adam_data(self, entity: GwEntityData, data: GwEntityData) -> None: + def _get_adam_data(self, entity: GwEntityData) -> None: """Helper-function for _get_entity_data(). Determine Adam heating-status for on-off heating via valves, @@ -239,28 +233,26 @@ def _get_adam_data(self, entity: GwEntityData, data: GwEntityData) -> None: if entity["dev_class"] == "heater_central": # Indicate heating_state based on valves being open in case of city-provided heating if self._on_off_device and isinstance(self._heating_valves(), int): - data["binary_sensors"]["heating_state"] = self._heating_valves() != 0 + entity["binary_sensors"]["heating_state"] = self._heating_valves() != 0 # Add cooling_enabled binary_sensor if ( - "binary_sensors" in data - and "cooling_enabled" not in data["binary_sensors"] + "binary_sensors" in entity + and "cooling_enabled" not in entity["binary_sensors"] and self._cooling_present ): - data["binary_sensors"]["cooling_enabled"] = self._cooling_enabled + entity["binary_sensors"]["cooling_enabled"] = self._cooling_enabled self._count += 1 # Show the allowed regulation_modes and gateway_modes if entity["dev_class"] == "gateway": if self._reg_allowed_modes: - data["regulation_modes"] = self._reg_allowed_modes + entity["regulation_modes"] = self._reg_allowed_modes self._count += 1 if self._gw_allowed_modes: - data["gateway_modes"] = self._gw_allowed_modes + entity["gateway_modes"] = self._gw_allowed_modes self._count += 1 - def _climate_data( - self, location_id: str, entity: GwEntityData, data: GwEntityData - ) -> None: + def _climate_data(self, location_id: str, entity: GwEntityData) -> None: """Helper-function for _get_entity_data(). Determine climate-control entity data. @@ -270,38 +262,38 @@ def _climate_data( loc_id = entity["location"] # Presets - data["preset_modes"] = None - data["active_preset"] = None + entity["preset_modes"] = None + entity["active_preset"] = None self._count += 2 if presets := self._presets(loc_id): - data["preset_modes"] = list(presets) - data["active_preset"] = self._preset(loc_id) + entity["preset_modes"] = list(presets) + entity["active_preset"] = self._preset(loc_id) # Schedule - data["available_schedules"] = [] - data["select_schedule"] = None + entity["available_schedules"] = [] + entity["select_schedule"] = None self._count += 2 avail_schedules, sel_schedule = self._schedules(loc_id) if avail_schedules != [NONE]: - data["available_schedules"] = avail_schedules - data["select_schedule"] = sel_schedule + entity["available_schedules"] = avail_schedules + entity["select_schedule"] = sel_schedule # Set HA climate HVACMode: auto, heat, heat_cool, cool and off - data["climate_mode"] = "auto" + entity["climate_mode"] = "auto" self._count += 1 if sel_schedule in (NONE, OFF): - data["climate_mode"] = "heat" + entity["climate_mode"] = "heat" if self._cooling_present: - data["climate_mode"] = ( + entity["climate_mode"] = ( "cool" if self.check_reg_mode("cooling") else "heat_cool" ) if self.check_reg_mode("off"): - data["climate_mode"] = "off" + entity["climate_mode"] = "off" if NONE not in avail_schedules: self._get_schedule_states_with_off( - loc_id, avail_schedules, sel_schedule, data + loc_id, avail_schedules, sel_schedule, entity ) def check_reg_mode(self, mode: str) -> bool: @@ -326,7 +318,7 @@ def _get_anna_control_state(self, data: GwEntityData) -> None: data["control_state"] = "cooling" def _get_schedule_states_with_off( - self, location: str, schedules: list[str], selected: str, data: GwEntityData + self, location: str, schedules: list[str], selected: str, entity: GwEntityData ) -> None: """Collect schedules with states for each thermostat. @@ -335,11 +327,11 @@ def _get_schedule_states_with_off( all_off = True self._schedule_old_states[location] = {} for schedule in schedules: - active: bool = schedule == selected and data["climate_mode"] == "auto" + active: bool = schedule == selected and entity["climate_mode"] == "auto" self._schedule_old_states[location][schedule] = "off" if active: self._schedule_old_states[location][schedule] = "on" all_off = False if all_off: - data["select_schedule"] = OFF + entity["select_schedule"] = OFF diff --git a/plugwise/helper.py b/plugwise/helper.py index 475eabd32..0a05864ae 100644 --- a/plugwise/helper.py +++ b/plugwise/helper.py @@ -305,13 +305,12 @@ def _get_appliances_with_offset_functionality(self) -> list[str]: return therm_list - def _get_zone_data(self, loc_id: str) -> GwEntityData: + def _get_zone_data(self, loc_id: str, zone: GwEntityData) -> None: """Helper-function for smile.py: _get_entity_data(). - Collect the location-data based on location id. + Collect the location/zone-data based on location id. """ data: GwEntityData = {"sensors": {}} - zone = self._zones[loc_id] measurements = ZONE_MEASUREMENTS if ( location := self._domain_objects.find(f'./location[@id="{loc_id}"]') @@ -319,25 +318,24 @@ def _get_zone_data(self, loc_id: str) -> GwEntityData: self._appliance_measurements(location, data, measurements) self._get_actuator_functionalities(location, zone, data) - return data + zone.update(data) - def _get_measurement_data(self, entity_id: str) -> GwEntityData: + def _get_measurement_data(self, entity_id: str, entity: GwEntityData) -> None: """Helper-function for smile.py: _get_entity_data(). Collect the appliance-data based on entity_id. """ data: GwEntityData = {"binary_sensors": {}, "sensors": {}, "switches": {}} - entity = self.gw_entities[entity_id] # Get P1 smartmeter data from LOCATIONS + is_smartmeter = entity.get("dev_class") == "smartmeter" smile_is_power = self.smile.type == "power" - if (smile_is_power or self.smile.anna_p1) and entity.get( - "dev_class" - ) == "smartmeter": + if is_smartmeter and (smile_is_power or self.smile.anna_p1): data.update(self._power_data_from_location()) if smile_is_power and not self.smile.anna_p1: - return data + entity.update(data) + return # Get group data if "members" in entity: @@ -372,7 +370,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData: self._cleanup_data(data) - return data + entity.update(data) def _collect_group_sensors( self, diff --git a/plugwise/legacy/data.py b/plugwise/legacy/data.py index c5cde29a7..ace3fa135 100644 --- a/plugwise/legacy/data.py +++ b/plugwise/legacy/data.py @@ -28,67 +28,63 @@ def _update_gw_entities(self) -> None: Collect data for each entity and add to self.gw_entities. """ for entity_id, entity in self.gw_entities.items(): - data = self._get_entity_data(entity_id) - entity.update(data) + self._get_entity_data(entity_id, entity) remove_empty_platform_dicts(entity) - def _get_entity_data(self, entity_id: str) -> GwEntityData: + def _get_entity_data(self, entity_id: str, entity: GwEntityData) -> None: """Helper-function for _all_entity_data() and async_update(). Provide entity-data, based on Location ID (= entity_id), from APPLIANCES. """ - entity = self.gw_entities[entity_id] - data = self._get_measurement_data(entity_id) + self._get_measurement_data(entity_id, entity) # Switching groups data - self._entity_switching_group(entity, data) + self._entity_switching_group(entity) # Skip obtaining data when not a thermostat if entity["dev_class"] != "thermostat": - return data + return # Thermostat data (presets, temperatures etc) - self._climate_data(entity, data) - self._get_anna_control_state(data) + self._climate_data(entity) + self._get_anna_control_state(entity) - return data - - def _climate_data(self, entity: GwEntityData, data: GwEntityData) -> None: + def _climate_data(self, entity: GwEntityData) -> None: """Helper-function for _get_entity_data(). Determine climate-control entity data. """ # Presets - data["preset_modes"] = None - data["active_preset"] = None + entity["preset_modes"] = None + entity["active_preset"] = None self._count += 2 if presets := self._presets(): - data["preset_modes"] = list(presets) - data["active_preset"] = self._preset() + entity["preset_modes"] = list(presets) + entity["active_preset"] = self._preset() # Schedule - data["available_schedules"] = [] - data["select_schedule"] = None + entity["available_schedules"] = [] + entity["select_schedule"] = None self._count += 2 avail_schedules, sel_schedule = self._schedules() if avail_schedules != [NONE]: - data["available_schedules"] = avail_schedules - data["select_schedule"] = sel_schedule + entity["available_schedules"] = avail_schedules + entity["select_schedule"] = sel_schedule # Set HA climate HVACMode: auto, heat - data["climate_mode"] = "auto" + entity["climate_mode"] = "auto" self._count += 1 if sel_schedule in (NONE, OFF): - data["climate_mode"] = "heat" + entity["climate_mode"] = "heat" - def _get_anna_control_state(self, data: GwEntityData) -> None: + def _get_anna_control_state(self, entity: GwEntityData) -> None: """Set the thermostat control_state based on the opentherm/onoff device state.""" - data["control_state"] = "idle" + entity["control_state"] = "idle" self._count += 1 - for entity in self.gw_entities.values(): - if entity["dev_class"] != "heater_central": + for device in self.gw_entities.values(): + if device["dev_class"] != "heater_central": continue - binary_sensors = entity["binary_sensors"] + binary_sensors = device["binary_sensors"] if binary_sensors["heating_state"]: - data["control_state"] = "heating" + entity["control_state"] = "heating" diff --git a/plugwise/legacy/helper.py b/plugwise/legacy/helper.py index f095466d8..112ef6e8e 100644 --- a/plugwise/legacy/helper.py +++ b/plugwise/legacy/helper.py @@ -249,20 +249,20 @@ def _p1_smartmeter_info_finder(self, appl: Munch) -> None: self._create_gw_entities(appl) - def _get_measurement_data(self, entity_id: str) -> GwEntityData: + def _get_measurement_data(self, entity_id: str, entity: GwEntityData) -> None: """Helper-function for smile.py: _get_entity_data(). Collect the appliance-data based on entity_id. """ data: GwEntityData = {"binary_sensors": {}, "sensors": {}, "switches": {}} # Get P1 smartmeter data from MODULES - entity = self.gw_entities[entity_id] # !! DON'T CHANGE below two if-lines, will break stuff !! if self.smile.type == "power": - if entity["dev_class"] == "smartmeter": + if entity.get("dev_class") == "smartmeter": data.update(self._power_data_from_modules()) - return data + entity.update(data) + return measurements = DEVICE_MEASUREMENTS if self._is_thermostat and entity_id == self.heater_id: @@ -290,7 +290,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData: data.pop("c_heating_state") self._count -= 1 - return data + entity.update(data) def _power_data_from_modules(self) -> GwEntityData: """Helper-function for smile.py: _get_entity_data().