Skip to content

Commit e2e7524

Browse files
authored
Merge pull request #764 from plugwise/testing
Limit amount of __init__ arguments
2 parents f6eb523 + c95b88d commit e2e7524

File tree

15 files changed

+143
-190
lines changed

15 files changed

+143
-190
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Ongoing
44

5-
- Implement async file-open in tests
5+
- Implement code quality improvements as suggested by SonarCloud
66

77
## v1.7.6
88

plugwise/__init__.py

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
from __future__ import annotations
77

8+
from typing import cast
9+
810
from plugwise.constants import (
911
DEFAULT_LEGACY_TIMEOUT,
1012
DEFAULT_PORT,
@@ -36,6 +38,7 @@
3638

3739
import aiohttp
3840
from defusedxml import ElementTree as etree
41+
from munch import Munch
3942
from packaging.version import Version, parse
4043

4144

@@ -72,16 +75,17 @@ def __init__(
7275
self._smile_api: SmileAPI | SmileLegacyAPI
7376
self._stretch_v2 = False
7477
self._target_smile: str = NONE
75-
self.smile_hostname: str = NONE
76-
self.smile_hw_version: str | None = None
77-
self.smile_legacy = False
78-
self.smile_mac_address: str | None = None
79-
self.smile_model: str = NONE
80-
self.smile_model_id: str | None = None
81-
self.smile_name: str = NONE
82-
self.smile_type: str = NONE
83-
self.smile_version: Version = Version("0.0.0")
84-
self.smile_zigbee_mac_address: str | None = None
78+
self.smile: Munch = Munch()
79+
self.smile.hostname = NONE
80+
self.smile.hw_version = None
81+
self.smile.legacy = False
82+
self.smile.mac_address = None
83+
self.smile.model = NONE
84+
self.smile.model_id = None
85+
self.smile.name = NONE
86+
self.smile.type = NONE
87+
self.smile.version = Version("0.0.0")
88+
self.smile.zigbee_mac_address = None
8589

8690
@property
8791
def cooling_present(self) -> bool:
@@ -109,7 +113,7 @@ def reboot(self) -> bool:
109113
110114
All non-legacy devices support gateway-rebooting.
111115
"""
112-
return not self.smile_legacy
116+
return not self.smile.legacy
113117

114118
async def connect(self) -> Version:
115119
"""Connect to the Plugwise Gateway and determine its name, type, version, and other data."""
@@ -158,16 +162,9 @@ async def connect(self) -> Version:
158162
self._opentherm_device,
159163
self._request,
160164
self._schedule_old_states,
161-
self.smile_hostname,
162-
self.smile_hw_version,
163-
self.smile_mac_address,
164-
self.smile_model,
165-
self.smile_model_id,
166-
self.smile_name,
167-
self.smile_type,
168-
self.smile_version,
165+
self.smile,
169166
)
170-
if not self.smile_legacy
167+
if not self.smile.legacy
171168
else SmileLegacyAPI(
172169
self._is_thermostat,
173170
self._loc_data,
@@ -176,21 +173,14 @@ async def connect(self) -> Version:
176173
self._request,
177174
self._stretch_v2,
178175
self._target_smile,
179-
self.smile_hostname,
180-
self.smile_hw_version,
181-
self.smile_mac_address,
182-
self.smile_model,
183-
self.smile_name,
184-
self.smile_type,
185-
self.smile_version,
186-
self.smile_zigbee_mac_address,
176+
self.smile,
187177
)
188178
)
189179

190180
# Update all endpoints on first connect
191181
await self._smile_api.full_xml_update()
192182

193-
return self.smile_version
183+
return cast(Version, self.smile.version)
194184

195185
async def _smile_detect(
196186
self, result: etree.Element, dsmrmain: etree.Element
@@ -203,23 +193,25 @@ async def _smile_detect(
203193
if (gateway := result.find("./gateway")) is not None:
204194
if (v_model := gateway.find("vendor_model")) is not None:
205195
model = v_model.text
206-
self.smile_version = parse(gateway.find("firmware_version").text)
207-
self.smile_hw_version = gateway.find("hardware_version").text
208-
self.smile_hostname = gateway.find("hostname").text
209-
self.smile_mac_address = gateway.find("mac_address").text
210-
self.smile_model_id = gateway.find("vendor_model").text
196+
self.smile.version = parse(gateway.find("firmware_version").text)
197+
self.smile.hw_version = gateway.find("hardware_version").text
198+
self.smile.hostname = gateway.find("hostname").text
199+
self.smile.mac_address = gateway.find("mac_address").text
200+
self.smile.model_id = gateway.find("vendor_model").text
211201
else:
212202
model = await self._smile_detect_legacy(result, dsmrmain, model)
213203

214-
if model == "Unknown" or self.smile_version is None: # pragma: no cover
204+
if model == "Unknown" or self.smile.version == Version(
205+
"0.0.0"
206+
): # pragma: no cover
215207
# Corner case check
216208
LOGGER.error(
217209
"Unable to find model or version information, please create"
218210
" an issue on http://github.com/plugwise/python-plugwise"
219211
)
220212
raise UnsupportedDeviceError
221213

222-
version_major = str(self.smile_version.major)
214+
version_major = str(self.smile.version.major)
223215
self._target_smile = f"{model}_v{version_major}"
224216
LOGGER.debug("Plugwise identified as %s", self._target_smile)
225217
if self._target_smile not in SMILES:
@@ -230,7 +222,7 @@ async def _smile_detect(
230222
)
231223
raise UnsupportedDeviceError
232224

233-
if not self.smile_legacy:
225+
if not self.smile.legacy:
234226
self._timeout = DEFAULT_TIMEOUT
235227

236228
if self._target_smile in ("smile_open_therm_v2", "smile_thermo_v3"):
@@ -240,14 +232,14 @@ async def _smile_detect(
240232
) # pragma: no cover
241233
raise UnsupportedDeviceError # pragma: no cover
242234

243-
self.smile_model = "Gateway"
244-
self.smile_name = SMILES[self._target_smile].smile_name
245-
self.smile_type = SMILES[self._target_smile].smile_type
235+
self.smile.model = "Gateway"
236+
self.smile.name = SMILES[self._target_smile].smile_name
237+
self.smile.type = SMILES[self._target_smile].smile_type
246238

247-
if self.smile_type == "stretch":
239+
if self.smile.type == "stretch":
248240
self._stretch_v2 = int(version_major) == 2
249241

250-
if self.smile_type == "thermostat":
242+
if self.smile.type == "thermostat":
251243
self._is_thermostat = True
252244
# For Adam, Anna, determine the system capabilities:
253245
# Find the connected heating/cooling device (heater_central),
@@ -275,36 +267,36 @@ async def _smile_detect_legacy(
275267
return_model = model
276268
# Stretch: find the MAC of the zigbee master_controller (= Stick)
277269
if (network := result.find("./module/protocols/master_controller")) is not None:
278-
self.smile_zigbee_mac_address = network.find("mac_address").text
270+
self.smile.zigbee_mac_address = network.find("mac_address").text
279271
# Find the active MAC in case there is an orphaned Stick
280272
if zb_networks := result.findall("./network"):
281273
for zb_network in zb_networks:
282274
if zb_network.find("./nodes/network_router") is not None:
283275
network = zb_network.find("./master_controller")
284-
self.smile_zigbee_mac_address = network.find("mac_address").text
276+
self.smile.zigbee_mac_address = network.find("mac_address").text
285277

286278
# Legacy Anna or Stretch:
287279
if (
288280
result.find('./appliance[type="thermostat"]') is not None
289281
or network is not None
290282
):
291283
system = await self._request(SYSTEM)
292-
self.smile_version = parse(system.find("./gateway/firmware").text)
284+
self.smile.version = parse(system.find("./gateway/firmware").text)
293285
return_model = str(system.find("./gateway/product").text)
294-
self.smile_hostname = system.find("./gateway/hostname").text
286+
self.smile.hostname = system.find("./gateway/hostname").text
295287
# If wlan0 contains data it's active, eth0 should be checked last as is preferred
296288
for network in ("wlan0", "eth0"):
297289
locator = f"./{network}/mac"
298290
if (net_locator := system.find(locator)) is not None:
299-
self.smile_mac_address = net_locator.text
291+
self.smile.mac_address = net_locator.text
300292

301293
# P1 legacy:
302294
elif dsmrmain is not None:
303295
status = await self._request(STATUS)
304-
self.smile_version = parse(status.find("./system/version").text)
296+
self.smile.version = parse(status.find("./system/version").text)
305297
return_model = str(status.find("./system/product").text)
306-
self.smile_hostname = status.find("./network/hostname").text
307-
self.smile_mac_address = status.find("./network/mac_address").text
298+
self.smile.hostname = status.find("./network/hostname").text
299+
self.smile.mac_address = status.find("./network/mac_address").text
308300
else: # pragma: no cover
309301
# No cornercase, just end of the line
310302
LOGGER.error(
@@ -313,7 +305,7 @@ async def _smile_detect_legacy(
313305
)
314306
raise ResponseError
315307

316-
self.smile_legacy = True
308+
self.smile.legacy = True
317309
return return_model
318310

319311
async def async_update(self) -> dict[str, GwEntityData]:

plugwise/common.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,16 @@ def __init__(self) -> None:
5555
self._heater_id: str = NONE
5656
self._on_off_device: bool
5757
self.gw_entities: dict[str, GwEntityData] = {}
58-
self.smile_name: str
59-
self.smile_type: str
58+
self.smile: Munch
6059

6160
@property
6261
def heater_id(self) -> str:
6362
"""Return the heater-id."""
6463
return self._heater_id
6564

66-
def smile(self, name: str) -> bool:
65+
def check_name(self, name: str) -> bool:
6766
"""Helper-function checking the smile-name."""
68-
return self.smile_name == name
67+
return bool(self.smile.name == name)
6968

7069
def _appl_heater_central_info(
7170
self,
@@ -173,7 +172,7 @@ def _get_group_switches(self) -> dict[str, GwEntityData]:
173172
"""
174173
switch_groups: dict[str, GwEntityData] = {}
175174
# P1 and Anna don't have switchgroups
176-
if self.smile_type == "power" or self.smile(ANNA):
175+
if self.smile.type == "power" or self.check_name(ANNA):
177176
return switch_groups
178177

179178
for group in self._domain_objects.findall("./group"):

plugwise/data.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def _all_entity_data(self) -> None:
3535
Collect data for each entity and add to self.gw_entities.
3636
"""
3737
self._update_gw_entities()
38-
if self.smile(ADAM):
38+
if self.check_name(ADAM):
3939
self._update_zones()
4040
self.gw_entities.update(self._zones)
4141

@@ -111,7 +111,7 @@ def _add_or_update_notifications(
111111
"""Helper-function adding or updating the Plugwise notifications."""
112112
if (
113113
entity_id == self._gateway_id
114-
and (self._is_thermostat or self.smile_type == "power")
114+
and (self._is_thermostat or self.smile.type == "power")
115115
) or (
116116
"binary_sensors" in entity
117117
and "plugwise_notification" in entity["binary_sensors"]
@@ -124,7 +124,7 @@ def _update_for_cooling(self, entity: GwEntityData) -> None:
124124
"""Helper-function for adding/updating various cooling-related values."""
125125
# For Anna and heating + cooling, replace setpoint with setpoint_high/_low
126126
if (
127-
self.smile(ANNA)
127+
self.check_name(ANNA)
128128
and self._cooling_present
129129
and entity["dev_class"] == "thermostat"
130130
):
@@ -194,11 +194,11 @@ def _get_entity_data(self, entity_id: str) -> GwEntityData:
194194
# Switching groups data
195195
self._entity_switching_group(entity, data)
196196
# Adam data
197-
if self.smile(ADAM):
197+
if self.check_name(ADAM):
198198
self._get_adam_data(entity, data)
199199

200200
# Thermostat data for Anna (presets, temperatures etc)
201-
if self.smile(ANNA) and entity["dev_class"] == "thermostat":
201+
if self.check_name(ANNA) and entity["dev_class"] == "thermostat":
202202
self._climate_data(entity_id, entity, data)
203203
self._get_anna_control_state(data)
204204

plugwise/helper.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,7 @@ def __init__(self) -> None:
8585
self._gateway_id: str = NONE
8686
self._zones: dict[str, GwEntityData]
8787
self.gw_entities: dict[str, GwEntityData]
88-
self.smile_hw_version: str | None
89-
self.smile_mac_address: str | None
90-
self.smile_model: str
91-
self.smile_model_id: str | None
92-
self.smile_version: version.Version
88+
self.smile: Munch = Munch()
9389

9490
@property
9591
def gateway_id(self) -> str:
@@ -160,7 +156,7 @@ def _all_appliances(self) -> None:
160156

161157
self._create_gw_entities(appl)
162158

163-
if self.smile_type == "power":
159+
if self.smile.type == "power":
164160
self._get_p1_smartmeter_info()
165161

166162
# Sort the gw_entities
@@ -268,16 +264,16 @@ def _appliance_info_finder(self, appl: Munch, appliance: etree.Element) -> Munch
268264
def _appl_gateway_info(self, appl: Munch, appliance: etree.Element) -> Munch:
269265
"""Helper-function for _appliance_info_finder()."""
270266
self._gateway_id = appliance.attrib["id"]
271-
appl.firmware = str(self.smile_version)
272-
appl.hardware = self.smile_hw_version
273-
appl.mac = self.smile_mac_address
274-
appl.model = self.smile_model
275-
appl.model_id = self.smile_model_id
276-
appl.name = self.smile_name
267+
appl.firmware = str(self.smile.version)
268+
appl.hardware = self.smile.hw_version
269+
appl.mac = self.smile.mac_address
270+
appl.model = self.smile.model
271+
appl.model_id = self.smile.model_id
272+
appl.name = self.smile.name
277273
appl.vendor_name = "Plugwise"
278274

279275
# Adam: collect the ZigBee MAC address of the Smile
280-
if self.smile(ADAM):
276+
if self.check_name(ADAM):
281277
if (
282278
found := self._domain_objects.find(".//protocols/zig_bee_coordinator")
283279
) is not None:
@@ -346,7 +342,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData:
346342
# Get P1 smartmeter data from LOCATIONS
347343
entity = self.gw_entities[entity_id]
348344
# !! DON'T CHANGE below two if-lines, will break stuff !!
349-
if self.smile_type == "power":
345+
if self.smile.type == "power":
350346
if entity["dev_class"] == "smartmeter":
351347
data.update(self._power_data_from_location())
352348

@@ -383,7 +379,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData:
383379
data.pop("c_heating_state")
384380
self._count -= 1
385381

386-
if self._is_thermostat and self.smile(ANNA):
382+
if self._is_thermostat and self.check_name(ANNA):
387383
self._update_anna_cooling(entity_id, data)
388384

389385
self._cleanup_data(data)
@@ -484,7 +480,7 @@ def _get_actuator_functionalities(
484480
item == "thermostat"
485481
and (
486482
entity["dev_class"] != "climate"
487-
if self.smile(ADAM)
483+
if self.check_name(ADAM)
488484
else entity["dev_class"] != "thermostat"
489485
)
490486
):
@@ -539,7 +535,7 @@ def _get_actuator_mode(
539535
540536
Collect the requested gateway mode.
541537
"""
542-
if not (self.smile(ADAM) and entity_id == self._gateway_id):
538+
if not (self.check_name(ADAM) and entity_id == self._gateway_id):
543539
return None
544540

545541
if (search := search_actuator_functionalities(appliance, key)) is not None:
@@ -605,10 +601,10 @@ def _process_on_off_device_c_heating_state(self, data: GwEntityData) -> None:
605601
606602
Solution for Core issue #81839.
607603
"""
608-
if self.smile(ANNA):
604+
if self.check_name(ANNA):
609605
data["binary_sensors"]["heating_state"] = data["c_heating_state"]
610606

611-
if self.smile(ADAM):
607+
if self.check_name(ADAM):
612608
# First count when not present, then create and init to False.
613609
# When present init to False
614610
if "heating_state" not in data["binary_sensors"]:
@@ -799,8 +795,8 @@ def _control_state(self, data: GwEntityData, loc_id: str) -> str | bool:
799795

800796
# Handle missing control_state in regulation_mode off for firmware >= 3.2.0 (issue #776)
801797
# In newer firmware versions, default to "off" when control_state is not present
802-
if self.smile_version != version.Version("0.0.0"):
803-
if self.smile_version >= version.parse("3.2.0"):
798+
if self.smile.version != version.Version("0.0.0"):
799+
if self.smile.version >= version.parse("3.2.0"):
804800
return "off"
805801

806802
# Older Adam firmware does not have the control_state xml-key

0 commit comments

Comments
 (0)