diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cba877ea..2dd6a39b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Ongoing - Improve readability of xml-data in POST/PUT requests via [#707](https://github.com/plugwise/python-plugwise/pull/707), [#708](https://github.com/plugwise/python-plugwise/pull/708) and [#715](https://github.com/plugwise/python-plugwise/pull/715) -- Continuous improvements via [#711](https://github.com/plugwise/python-plugwise/pull/711) and [#713](https://github.com/plugwise/python-plugwise/pull/713) +- Continuous improvements via [#711](https://github.com/plugwise/python-plugwise/pull/711), [#713](https://github.com/plugwise/python-plugwise/pull/713) and [#716](https://github.com/plugwise/python-plugwise/pull/716) ## v1.7.2 diff --git a/plugwise/__init__.py b/plugwise/__init__.py index 5674471e6..35250323d 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -18,7 +18,6 @@ STATUS, SYSTEM, GwEntityData, - SmileProps, ThermoLoc, ) from plugwise.exceptions import ( @@ -69,7 +68,6 @@ def __init__( self._opentherm_device = False self._schedule_old_states: dict[str, dict[str, str]] = {} self._smile_api: SmileAPI | SmileLegacyAPI - self._smile_props: SmileProps = {} self._stretch_v2 = False self._target_smile: str = NONE self.smile_hostname: str = NONE @@ -86,26 +84,22 @@ def __init__( @property def cooling_present(self) -> bool: """Return the cooling capability.""" - if "cooling_present" in self._smile_props: - return self._smile_props["cooling_present"] - return False + return self._smile_api.cooling_present @property def gateway_id(self) -> str: """Return the gateway-id.""" - return self._smile_props["gateway_id"] + return self._smile_api.gateway_id @property def heater_id(self) -> str: """Return the heater-id.""" - if "heater_id" in self._smile_props: - return self._smile_props["heater_id"] - return NONE + return self._smile_api.heater_id @property def item_count(self) -> int: """Return the item-count.""" - return self._smile_props["item_count"] + return self._smile_api.item_count @property def reboot(self) -> bool: @@ -162,7 +156,6 @@ async def connect(self) -> Version: self._opentherm_device, self._request, self._schedule_old_states, - self._smile_props, self.smile_hostname, self.smile_hw_version, self.smile_mac_address, @@ -179,7 +172,6 @@ async def connect(self) -> Version: self._on_off_device, self._opentherm_device, self._request, - self._smile_props, self._stretch_v2, self._target_smile, self.smile_hostname, diff --git a/plugwise/common.py b/plugwise/common.py index 03ec7c865..c261eeb4b 100644 --- a/plugwise/common.py +++ b/plugwise/common.py @@ -58,6 +58,11 @@ def __init__(self) -> None: self.smile_name: str self.smile_type: str + @property + def heater_id(self) -> str: + """Return the heater-id.""" + return self._heater_id + def smile(self, name: str) -> bool: """Helper-function checking the smile-name.""" return self.smile_name == name diff --git a/plugwise/constants.py b/plugwise/constants.py index 7d406ad94..f12c8bbd9 100644 --- a/plugwise/constants.py +++ b/plugwise/constants.py @@ -393,17 +393,6 @@ ) -class SmileProps(TypedDict, total=False): - """The SmileProps Data class.""" - - cooling_present: bool - gateway_id: str - heater_id: str - item_count: int - reboot: bool - smile_name: str - - class ModuleData(TypedDict): """The Module data class.""" diff --git a/plugwise/data.py b/plugwise/data.py index b23b4e53a..97ec5b51a 100644 --- a/plugwise/data.py +++ b/plugwise/data.py @@ -16,7 +16,6 @@ OFF, ActuatorData, GwEntityData, - SmileProps, ) from plugwise.helper import SmileHelper from plugwise.util import remove_empty_platform_dicts @@ -27,28 +26,19 @@ class SmileData(SmileHelper): def __init__(self) -> None: """Init.""" - self._smile_props: SmileProps + super().__init__() self._zones: dict[str, GwEntityData] = {} - SmileHelper.__init__(self) def _all_entity_data(self) -> None: """Helper-function for get_all_gateway_entities(). - Collect data for each entity and add to self._smile_props and self.gw_entities. + Collect data for each entity and add to self.gw_entities. """ self._update_gw_entities() if self.smile(ADAM): self._update_zones() self.gw_entities.update(self._zones) - self._smile_props["gateway_id"] = self._gateway_id - self._smile_props["item_count"] = self._count - self._smile_props["reboot"] = True - self._smile_props["smile_name"] = self.smile_name - if self._is_thermostat: - self._smile_props["heater_id"] = self._heater_id - self._smile_props["cooling_present"] = self._cooling_present - def _update_zones(self) -> None: """Helper-function for _all_entity_data() and async_update(). diff --git a/plugwise/helper.py b/plugwise/helper.py index 35472db5b..87c4e986e 100644 --- a/plugwise/helper.py +++ b/plugwise/helper.py @@ -75,6 +75,7 @@ class SmileHelper(SmileCommon): def __init__(self) -> None: """Set the constructor for this class.""" + super().__init__() self._endpoint: str self._elga: bool self._is_thermostat: bool @@ -89,7 +90,16 @@ def __init__(self) -> None: self.smile_model: str self.smile_model_id: str | None self.smile_version: version.Version - SmileCommon.__init__(self) + + @property + def gateway_id(self) -> str: + """Return the gateway-id.""" + return self._gateway_id + + @property + def item_count(self) -> int: + """Return the item-count.""" + return self._count def _all_appliances(self) -> None: """Collect all appliances with relevant info. @@ -233,7 +243,7 @@ def _appliance_info_finder(self, appl: Munch, appliance: etree.Element) -> Munch appliance, "domestic_hot_water_mode_control_functionality" ) # Skip orphaned heater_central (Core Issue #104433) - if appl.entity_id != self._heater_id: + if appl.entity_id != self.heater_id: return Munch() return appl case _ as s if s.endswith("_plug"): @@ -344,7 +354,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData: # Get non-P1 data from APPLIANCES measurements = DEVICE_MEASUREMENTS - if self._is_thermostat and entity_id == self._heater_id: + if self._is_thermostat and entity_id == self.heater_id: measurements = HEATER_CENTRAL_MEASUREMENTS # Show the allowed dhw_modes (Loria only) if self._dhw_allowed_modes: @@ -619,7 +629,7 @@ def _update_anna_cooling(self, entity_id: str, data: GwEntityData) -> None: Support added for Techneco Elga and Thercon Loria/Thermastage. """ - if entity_id != self._heater_id: + if entity_id != self.heater_id: return if "elga_status_code" in data: diff --git a/plugwise/legacy/data.py b/plugwise/legacy/data.py index 777f528a1..03ee4a014 100644 --- a/plugwise/legacy/data.py +++ b/plugwise/legacy/data.py @@ -7,7 +7,7 @@ # Dict as class # Version detection -from plugwise.constants import NONE, OFF, GwEntityData, SmileProps +from plugwise.constants import NONE, OFF, GwEntityData from plugwise.legacy.helper import SmileLegacyHelper from plugwise.util import remove_empty_platform_dicts @@ -15,22 +15,12 @@ class SmileLegacyData(SmileLegacyHelper): """The Plugwise Smile main class.""" - def __init__(self) -> None: - """Init.""" - self._smile_props: SmileProps - SmileLegacyHelper.__init__(self) - def _all_entity_data(self) -> None: """Helper-function for get_all_gateway_entities(). - Collect data for each entity and add to self._smile_props and self.gw_entities. + Collect data for each entity and add to self.gw_entities. """ self._update_gw_entities() - self._smile_props["gateway_id"] = self.gateway_id - self._smile_props["item_count"] = self._count - self._smile_props["smile_name"] = self.smile_name - if self._is_thermostat: - self._smile_props["heater_id"] = self._heater_id def _update_gw_entities(self) -> None: """Helper-function for _all_entity_data() and async_update(). diff --git a/plugwise/legacy/helper.py b/plugwise/legacy/helper.py index 5d900aa20..e22b489e5 100644 --- a/plugwise/legacy/helper.py +++ b/plugwise/legacy/helper.py @@ -64,7 +64,9 @@ class SmileLegacyHelper(SmileCommon): def __init__(self) -> None: """Set the constructor for this class.""" + super().__init__() self._appliances: etree.Element + self._gateway_id: str = NONE self._is_thermostat: bool self._loc_data: dict[str, ThermoLoc] self._locations: etree.Element @@ -75,7 +77,16 @@ def __init__(self) -> None: self.smile_model: str self.smile_version: Version self.smile_zigbee_mac_address: str | None - SmileCommon.__init__(self) + + @property + def gateway_id(self) -> str: + """Return the gateway-id.""" + return self._gateway_id + + @property + def item_count(self) -> int: + """Return the item-count.""" + return self._count def _all_appliances(self) -> None: """Collect all appliances with relevant info.""" @@ -125,7 +136,7 @@ def _all_appliances(self) -> None: continue # Skip orphaned heater_central (Core Issue #104433) - if appl.pwclass == "heater_central" and appl.entity_id != self._heater_id: + if appl.pwclass == "heater_central" and appl.entity_id != self.heater_id: continue # pragma: no cover self._create_gw_entities(appl) @@ -173,11 +184,11 @@ def _create_legacy_gateway(self) -> None: Use the home_location or FAKE_APPL as entity id. """ - self.gateway_id = self._home_loc_id + self._gateway_id = self._home_loc_id if self.smile_type == "power": - self.gateway_id = FAKE_APPL + self._gateway_id = FAKE_APPL - self.gw_entities[self.gateway_id] = {"dev_class": "gateway"} + self.gw_entities[self._gateway_id] = {"dev_class": "gateway"} self._count += 1 for key, value in { "firmware": str(self.smile_version), @@ -190,7 +201,7 @@ def _create_legacy_gateway(self) -> None: }.items(): if value is not None: gw_key = cast(ApplianceType, key) - self.gw_entities[self.gateway_id][gw_key] = value + self.gw_entities[self._gateway_id][gw_key] = value self._count += 1 def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch: @@ -268,7 +279,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData: return data measurements = DEVICE_MEASUREMENTS - if self._is_thermostat and entity_id == self._heater_id: + if self._is_thermostat and entity_id == self.heater_id: measurements = HEATER_CENTRAL_MEASUREMENTS if ( @@ -282,7 +293,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData: # Anna: the Smile outdoor_temperature is present in the Home location # For some Anna's LOCATIONS is empty, falling back to domain_objects! - if self._is_thermostat and entity_id == self.gateway_id: + if self._is_thermostat and entity_id == self._gateway_id: locator = f"./location[@id='{self._home_loc_id}']/logs/point_log[type='outdoor_temperature']/period/measurement" if (found := self._domain_objects.find(locator)) is not None: value = format_measure(found.text, NONE) diff --git a/plugwise/legacy/smile.py b/plugwise/legacy/smile.py index 2d1e42eef..eedd360f7 100644 --- a/plugwise/legacy/smile.py +++ b/plugwise/legacy/smile.py @@ -19,7 +19,6 @@ REQUIRE_APPLIANCES, RULES, GwEntityData, - SmileProps, ThermoLoc, ) from plugwise.exceptions import ConnectionFailedError, DataMissingError, PlugwiseError @@ -41,7 +40,6 @@ def __init__( _on_off_device: bool, _opentherm_device: bool, _request: Callable[..., Awaitable[Any]], - _smile_props: SmileProps, _stretch_v2: bool, _target_smile: str, smile_hostname: str, @@ -54,13 +52,13 @@ def __init__( smile_zigbee_mac_address: str | None, ) -> None: """Set the constructor for this class.""" + super().__init__() self._cooling_present = False self._is_thermostat = _is_thermostat self._loc_data = _loc_data self._on_off_device = _on_off_device self._opentherm_device = _opentherm_device self._request = _request - self._smile_props = _smile_props self._stretch_v2 = _stretch_v2 self._target_smile = _target_smile self.smile_hostname = smile_hostname @@ -71,11 +69,15 @@ def __init__( self.smile_type = smile_type self.smile_version = smile_version self.smile_zigbee_mac_address = smile_zigbee_mac_address - SmileLegacyData.__init__(self) self._first_update = True self._previous_day_number: str = "0" + @property + def cooling_present(self) -> bool: + """Return the cooling capability.""" + return False + async def full_xml_update(self) -> None: """Perform a first fetch of the Plugwise server XML data.""" self._domain_objects = await self._request(DOMAIN_OBJECTS) diff --git a/plugwise/smile.py b/plugwise/smile.py index 7fd951d71..f3b259ff8 100644 --- a/plugwise/smile.py +++ b/plugwise/smile.py @@ -18,11 +18,11 @@ LOCATIONS, MAX_SETPOINT, MIN_SETPOINT, + NONE, NOTIFICATIONS, OFF, RULES, GwEntityData, - SmileProps, ThermoLoc, ) from plugwise.data import SmileData @@ -51,7 +51,6 @@ def __init__( _opentherm_device: bool, _request: Callable[..., Awaitable[Any]], _schedule_old_states: dict[str, dict[str, str]], - _smile_props: SmileProps, smile_hostname: str | None, smile_hw_version: str | None, smile_mac_address: str | None, @@ -62,6 +61,7 @@ def __init__( smile_version: Version, ) -> None: """Set the constructor for this class.""" + super().__init__() self._cooling_present = _cooling_present self._elga = _elga self._is_thermostat = _is_thermostat @@ -71,7 +71,6 @@ def __init__( self._opentherm_device = _opentherm_device self._request = _request self._schedule_old_states = _schedule_old_states - self._smile_props = _smile_props self.smile_hostname = smile_hostname self.smile_hw_version = smile_hw_version self.smile_mac_address = smile_mac_address @@ -81,7 +80,11 @@ def __init__( self.smile_type = smile_type self.smile_version = smile_version self.therms_with_offset_func: list[str] = [] - SmileData.__init__(self) + + @property + def cooling_present(self) -> bool: + """Return the cooling capability.""" + return self._cooling_present async def full_xml_update(self) -> None: """Perform a first fetch of the Plugwise server XML data.""" @@ -121,8 +124,8 @@ async def async_update(self) -> dict[str, GwEntityData]: self.get_all_gateway_entities() # Set self._cooling_enabled - required for set_temperature(), # also, check for a failed data-retrieval - if "heater_id" in self._smile_props: - heat_cooler = self.gw_entities[self._smile_props["heater_id"]] + if self.heater_id != NONE: + heat_cooler = self.gw_entities[self.heater_id] if ( "binary_sensors" in heat_cooler and "cooling_enabled" in heat_cooler["binary_sensors"] @@ -131,7 +134,7 @@ async def async_update(self) -> dict[str, GwEntityData]: "cooling_enabled" ] else: # cover failed data-retrieval for P1 - _ = self.gw_entities[self._smile_props["gateway_id"]]["location"] + _ = self.gw_entities[self.gateway_id]["location"] except KeyError as err: raise DataMissingError("No Plugwise actual data received") from err @@ -273,7 +276,7 @@ async def set_gateway_mode(self, mode: str) -> None: f"{valid}" "" ) - uri = f"{APPLIANCES};id={self._smile_props['gateway_id']}/gateway_mode_control" + uri = f"{APPLIANCES};id={self.gateway_id}/gateway_mode_control" await self.call_request(uri, method="put", data=data) async def set_regulation_mode(self, mode: str) -> None: diff --git a/pyproject.toml b/pyproject.toml index e5ca6ede0..4b8283c23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "plugwise" -version = "1.7.3a2" +version = "1.7.3a3" license = {file = "LICENSE"} description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3." readme = "README.md" @@ -75,7 +75,6 @@ init-hook = """\ load-plugins = [ "pylint.extensions.code_style", "pylint.extensions.typing", - "pylint_per_file_ignores", ] persistent = false extension-pkg-allow-list = [ @@ -366,12 +365,6 @@ enable = [ #"useless-suppression", # temporarily every now and then to clean them up "use-symbolic-message-instead", ] -per-file-ignores = [ - # redefined-outer-name: Tests reference fixtures in the test function - # use-implicit-booleaness-not-comparison: Tests need to validate that a list - # or a dict is returned - "/tests/:redefined-outer-name,use-implicit-booleaness-not-comparison", -] [tool.pylint.REPORTS] score = false