Skip to content

Commit dd03a01

Browse files
authored
Merge pull request #516 from plugwise/improve-3
More improvements
2 parents 45840e5 + e24bf38 commit dd03a01

File tree

15 files changed

+250
-322
lines changed

15 files changed

+250
-322
lines changed

fixtures/legacy_anna/all_data.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
{
22
"devices": {
33
"0000aaaa0000aaaa0000aaaa0000aa00": {
4-
"binary_sensors": {
5-
"plugwise_notification": false
6-
},
74
"dev_class": "gateway",
85
"firmware": "1.8.22",
96
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
@@ -67,7 +64,7 @@
6764
"cooling_present": false,
6865
"gateway_id": "0000aaaa0000aaaa0000aaaa0000aa00",
6966
"heater_id": "04e4cbfe7f4340f090f85ec3b9e6a950",
70-
"item_count": 44,
67+
"item_count": 43,
7168
"notifications": {},
7269
"smile_name": "Smile Anna"
7370
}

fixtures/legacy_anna_2/all_data.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@
2626
"vendor": "Plugwise"
2727
},
2828
"be81e3f8275b4129852c4d8d550ae2eb": {
29-
"binary_sensors": {
30-
"plugwise_notification": false
31-
},
3229
"dev_class": "gateway",
3330
"firmware": "1.8.22",
3431
"location": "be81e3f8275b4129852c4d8d550ae2eb",
@@ -69,7 +66,7 @@
6966
"cooling_present": false,
7067
"gateway_id": "be81e3f8275b4129852c4d8d550ae2eb",
7168
"heater_id": "ea5d8a7177e541b0a4b52da815166de4",
72-
"item_count": 44,
69+
"item_count": 43,
7370
"notifications": {},
7471
"smile_name": "Smile Anna"
7572
}

plugwise/__init__.py

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,7 @@
1818
PlugwiseData,
1919
ThermoLoc,
2020
)
21-
from plugwise.exceptions import (
22-
InvalidSetupError,
23-
PlugwiseError,
24-
ResponseError,
25-
UnsupportedDeviceError,
26-
)
21+
from plugwise.exceptions import InvalidSetupError, ResponseError, UnsupportedDeviceError
2722
from plugwise.helper import SmileComm
2823
from plugwise.legacy.smile import SmileLegacyAPI
2924
from plugwise.smile import SmileAPI
@@ -326,58 +321,33 @@ async def set_preset(self, loc_id: str, preset: str) -> None:
326321

327322
async def set_temperature(self, loc_id: str, items: dict[str, float]) -> None:
328323
"""Set the given Temperature on the relevant Thermostat."""
329-
try:
330-
await self._smile_api.set_temperature(loc_id, items)
331-
except PlugwiseError as exc:
332-
raise PlugwiseError(
333-
"Plugwise: failed setting temperature: no valid input provided"
334-
) from exc
324+
await self._smile_api.set_temperature(loc_id, items)
335325

336326
async def set_number_setpoint(self, key: str, _: str, temperature: float) -> None:
337327
"""Set the max. Boiler or DHW setpoint on the Central Heating boiler."""
338-
try:
339-
await self._smile_api.set_number_setpoint(key, temperature)
340-
except PlugwiseError as exc:
341-
raise PlugwiseError(f"Plugwise: cannot change setpoint, {key} not found.") from exc
328+
await self._smile_api.set_number_setpoint(key, temperature)
342329

343330
async def set_temperature_offset(self, _: str, dev_id: str, offset: float) -> None:
344331
"""Set the Temperature offset for thermostats that support this feature."""
345-
try:
346-
await self._smile_api.set_temperature_offset(dev_id, offset)
347-
except PlugwiseError as exc:
348-
raise PlugwiseError(
349-
"Plugwise: this device does not have temperature-offset capability."
350-
) from exc
332+
await self._smile_api.set_temperature_offset(dev_id, offset)
351333

352334
async def set_switch_state(
353335
self, appl_id: str, members: list[str] | None, model: str, state: str
354336
) -> None:
355337
"""Set the given State of the relevant Switch."""
356-
try:
357-
await self._smile_api.set_switch_state(appl_id, members, model, state)
358-
except PlugwiseError as exc:
359-
raise PlugwiseError("Plugwise: the locked Relay was not switched.") from exc
338+
await self._smile_api.set_switch_state(appl_id, members, model, state)
360339

361340
async def set_gateway_mode(self, mode: str) -> None:
362341
"""Set the gateway mode."""
363-
try:
364-
await self._smile_api.set_gateway_mode(mode)
365-
except PlugwiseError as exc:
366-
raise PlugwiseError("Plugwise: invalid gateway mode.") from exc
342+
await self._smile_api.set_gateway_mode(mode)
367343

368344
async def set_regulation_mode(self, mode: str) -> None:
369345
"""Set the heating regulation mode."""
370-
try:
371-
await self._smile_api.set_regulation_mode(mode)
372-
except PlugwiseError as exc:
373-
raise PlugwiseError("Plugwise: invalid regulation mode.") from exc
346+
await self._smile_api.set_regulation_mode(mode)
374347

375348
async def set_dhw_mode(self, mode: str) -> None:
376349
"""Set the domestic hot water heating regulation mode."""
377-
try:
378-
await self._smile_api.set_dhw_mode(mode)
379-
except PlugwiseError as exc:
380-
raise PlugwiseError("Plugwise: invalid dhw mode.") from exc
350+
await self._smile_api.set_dhw_mode(mode)
381351

382352
async def delete_notification(self) -> None:
383353
"""Delete the active Plugwise Notification."""

plugwise/common.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""Use of this source code is governed by the MIT license found in the LICENSE file.
2+
3+
Plugwise Smile protocol helpers.
4+
"""
5+
from __future__ import annotations
6+
7+
from plugwise.constants import ModelData
8+
from plugwise.util import (
9+
check_heater_central,
10+
check_model,
11+
get_vendor_name,
12+
return_valid,
13+
)
14+
15+
from defusedxml import ElementTree as etree
16+
from munch import Munch
17+
18+
19+
class SmileCommon:
20+
"""The SmileCommon class."""
21+
22+
def __init__(self) -> None:
23+
"""Init."""
24+
self._appliances: etree
25+
self._domain_objects: etree
26+
self._cooling_present: bool
27+
self._heater_id: str
28+
self._on_off_device: bool
29+
self._opentherm_device: bool
30+
self.smile_name: str
31+
32+
def smile(self, name: str) -> bool:
33+
"""Helper-function checking the smile-name."""
34+
return self.smile_name == name
35+
36+
def _appl_thermostat_info(self, appl: Munch, xml_1: etree, xml_2: etree = None) -> Munch:
37+
"""Helper-function for _appliance_info_finder()."""
38+
locator = "./logs/point_log[type='thermostat']/thermostat"
39+
mod_type = "thermostat"
40+
xml_2 = return_valid(xml_2, self._domain_objects)
41+
module_data = self._get_module_data(xml_1, locator, mod_type, xml_2)
42+
appl.vendor_name = module_data["vendor_name"]
43+
appl.model = check_model(module_data["vendor_model"], appl.vendor_name)
44+
appl.hardware = module_data["hardware_version"]
45+
appl.firmware = module_data["firmware_version"]
46+
appl.zigbee_mac = module_data["zigbee_mac_address"]
47+
48+
return appl
49+
50+
def _appl_heater_central_info(
51+
self,
52+
appl: Munch,
53+
xml_1: etree,
54+
xml_2: etree = None,
55+
xml_3: etree = None,
56+
) -> Munch:
57+
"""Helper-function for _appliance_info_finder()."""
58+
# Remove heater_central when no active device present
59+
if not self._opentherm_device and not self._on_off_device:
60+
return None
61+
62+
# Find the valid heater_central
63+
# xml_2 self._appliances for legacy, self._domain_objects for actual
64+
xml_2 = return_valid(xml_2, self._domain_objects)
65+
self._heater_id = check_heater_central(xml_2)
66+
67+
# Info for On-Off device
68+
if self._on_off_device:
69+
appl.name = "OnOff" # pragma: no cover
70+
appl.vendor_name = None # pragma: no cover
71+
appl.model = "Unknown" # pragma: no cover
72+
return appl # pragma: no cover
73+
74+
# Info for OpenTherm device
75+
appl.name = "OpenTherm"
76+
locator_1 = "./logs/point_log[type='flame_state']/boiler_state"
77+
locator_2 = "./services/boiler_state"
78+
mod_type = "boiler_state"
79+
# xml_1: appliance
80+
# xml_3: self._modules for legacy, self._domain_objects for actual
81+
xml_3 = return_valid(xml_3, self._domain_objects)
82+
module_data = self._get_module_data(xml_1, locator_1, mod_type, xml_3)
83+
if not module_data["contents"]:
84+
module_data = self._get_module_data(xml_1, locator_2, mod_type, xml_3)
85+
appl.vendor_name = module_data["vendor_name"]
86+
appl.hardware = module_data["hardware_version"]
87+
appl.model = module_data["vendor_model"]
88+
if appl.model is None:
89+
appl.model = (
90+
"Generic heater/cooler"
91+
if self._cooling_present
92+
else "Generic heater"
93+
)
94+
95+
return appl
96+
97+
def _get_module_data(
98+
self,
99+
xml_1: etree,
100+
locator: str,
101+
mod_type: str,
102+
xml_2: etree = None,
103+
legacy: bool = False,
104+
) -> ModelData:
105+
"""Helper-function for _energy_device_info_finder() and _appliance_info_finder().
106+
107+
Collect requested info from MODULES.
108+
"""
109+
model_data: ModelData = {
110+
"contents": False,
111+
"firmware_version": None,
112+
"hardware_version": None,
113+
"reachable": None,
114+
"vendor_name": None,
115+
"vendor_model": None,
116+
"zigbee_mac_address": None,
117+
}
118+
# xml_1: appliance
119+
if (appl_search := xml_1.find(locator)) is not None:
120+
link_id = appl_search.attrib["id"]
121+
loc = f".//services/{mod_type}[@id='{link_id}']...."
122+
if legacy:
123+
loc = f".//{mod_type}[@id='{link_id}']...."
124+
# Not possible to walrus for some reason...
125+
# xml_2: self._modules for legacy, self._domain_objects for actual
126+
search = return_valid(xml_2, self._domain_objects)
127+
module = search.find(loc)
128+
if module is not None: # pylint: disable=consider-using-assignment-expr
129+
model_data["contents"] = True
130+
get_vendor_name(module, model_data)
131+
model_data["vendor_model"] = module.find("vendor_model").text
132+
model_data["hardware_version"] = module.find("hardware_version").text
133+
model_data["firmware_version"] = module.find("firmware_version").text
134+
self._get_zigbee_data(module, model_data, legacy)
135+
136+
return model_data
137+
138+
def _get_zigbee_data(self, module: etree, model_data: ModelData, legacy: bool) -> None:
139+
"""Helper-function for _get_model_data()."""
140+
if legacy:
141+
# Stretches
142+
if (router := module.find("./protocols/network_router")) is not None:
143+
model_data["zigbee_mac_address"] = router.find("mac_address").text
144+
# Also look for the Circle+/Stealth M+
145+
if (coord := module.find("./protocols/network_coordinator")) is not None:
146+
model_data["zigbee_mac_address"] = coord.find("mac_address").text
147+
# Adam
148+
elif (zb_node := module.find("./protocols/zig_bee_node")) is not None:
149+
model_data["zigbee_mac_address"] = zb_node.find("mac_address").text
150+
model_data["reachable"] = zb_node.find("reachable").text == "true"
151+

plugwise/data.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ def _all_device_data(self) -> None:
9090
Collect data for each device and add to self.gw_data and self.gw_devices.
9191
"""
9292
self._update_gw_devices()
93-
self.device_items = self._count
9493
self.gw_data.update(
9594
{
9695
"gateway_id": self.gateway_id,

0 commit comments

Comments
 (0)