plugwise 1.6.1__py3-none-any.whl → 1.6.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
plugwise/__init__.py CHANGED
@@ -147,6 +147,7 @@ class Smile(SmileComm):
147
147
  self.smile_model_id,
148
148
  self.smile_name,
149
149
  self.smile_type,
150
+ self.smile_version,
150
151
  self._port,
151
152
  self._username,
152
153
  ) if not self.smile_legacy else SmileLegacyAPI(
plugwise/constants.py CHANGED
@@ -196,6 +196,7 @@ ZONE_MEASUREMENTS: Final[dict[str, DATA | UOM]] = {
196
196
  "electricity_produced": UOM(POWER_WATT),
197
197
  "relay": UOM(NONE),
198
198
  "temperature": UOM(TEMP_CELSIUS), # HA Core thermostat current_temperature
199
+ "thermostat": DATA("setpoint", TEMP_CELSIUS), # HA Core thermostat setpoint
199
200
  }
200
201
 
201
202
  # Literals
@@ -566,7 +567,7 @@ class GwEntityData(TypedDict, total=False):
566
567
 
567
568
  climate_mode: str
568
569
  # Extra for Adam Master Thermostats
569
- control_state: str | bool
570
+ control_state: str
570
571
 
571
572
  # Dict-types
572
573
  binary_sensors: SmileBinarySensors
plugwise/data.py CHANGED
@@ -160,9 +160,16 @@ class SmileData(SmileHelper):
160
160
  """
161
161
  zone = self._zones[loc_id]
162
162
  data = self._get_zone_data(loc_id)
163
- if ctrl_state := self._control_state(loc_id):
164
- data["control_state"] = ctrl_state
165
- self._count += 1
163
+ if ctrl_state := self._control_state(data, loc_id):
164
+ if str(ctrl_state) in ("cooling", "heating", "preheating"):
165
+ data["control_state"] = str(ctrl_state)
166
+ self._count += 1
167
+ if str(ctrl_state) == "off":
168
+ data["control_state"] = "idle"
169
+ self._count += 1
170
+
171
+ data["sensors"].pop("setpoint") # remove, only used in _control_state()
172
+ self._count -= 1
166
173
 
167
174
  # Thermostat data (presets, temperatures etc)
168
175
  self._climate_data(loc_id, zone, data)
@@ -191,7 +198,8 @@ class SmileData(SmileHelper):
191
198
  # Switching groups data
192
199
  self._entity_switching_group(entity, data)
193
200
  # Adam data
194
- self._get_adam_data(entity, data)
201
+ if self.smile(ADAM):
202
+ self._get_adam_data(entity, data)
195
203
 
196
204
  # Thermostat data for Anna (presets, temperatures etc)
197
205
  if self.smile(ANNA) and entity["dev_class"] == "thermostat":
@@ -218,26 +226,26 @@ class SmileData(SmileHelper):
218
226
  """Helper-function for _get_entity_data().
219
227
 
220
228
  Determine Adam heating-status for on-off heating via valves,
221
- available regulations_modes and thermostat control_states.
229
+ available regulations_modes and thermostat control_states,
230
+ and add missing cooling_enabled when required.
222
231
  """
223
- if self.smile(ADAM):
232
+ if entity["dev_class"] == "heater_central":
224
233
  # Indicate heating_state based on valves being open in case of city-provided heating
225
- if (
226
- entity["dev_class"] == "heater_central"
227
- and self._on_off_device
228
- and isinstance(self._heating_valves(), int)
229
- ):
234
+ if self._on_off_device and isinstance(self._heating_valves(), int):
230
235
  data["binary_sensors"]["heating_state"] = self._heating_valves() != 0
231
-
232
- # Show the allowed regulation_modes and gateway_modes
233
- if entity["dev_class"] == "gateway":
234
- if self._reg_allowed_modes:
235
- data["regulation_modes"] = self._reg_allowed_modes
236
- self._count += 1
237
- if self._gw_allowed_modes:
238
- data["gateway_modes"] = self._gw_allowed_modes
239
- self._count += 1
240
-
236
+ # Add cooling_enabled binary_sensor
237
+ if "binary_sensors" in data:
238
+ if "cooling_enabled" not in data["binary_sensors"] and self._cooling_present:
239
+ data["binary_sensors"]["cooling_enabled"] = self._cooling_enabled
240
+
241
+ # Show the allowed regulation_modes and gateway_modes
242
+ if entity["dev_class"] == "gateway":
243
+ if self._reg_allowed_modes:
244
+ data["regulation_modes"] = self._reg_allowed_modes
245
+ self._count += 1
246
+ if self._gw_allowed_modes:
247
+ data["gateway_modes"] = self._gw_allowed_modes
248
+ self._count += 1
241
249
 
242
250
  def _climate_data(
243
251
  self,
plugwise/helper.py CHANGED
@@ -64,7 +64,7 @@ from dateutil import tz
64
64
  from dateutil.parser import parse
65
65
  from defusedxml import ElementTree as etree
66
66
  from munch import Munch
67
- from packaging.version import Version
67
+ from packaging import version
68
68
 
69
69
 
70
70
  class SmileComm:
@@ -252,13 +252,14 @@ class SmileHelper(SmileCommon):
252
252
  self.gateway_id: str
253
253
  self.gw_data: GatewayData = {}
254
254
  self.gw_entities: dict[str, GwEntityData] = {}
255
- self.smile_fw_version: Version | None
255
+ self.smile_fw_version: version.Version | None
256
256
  self.smile_hw_version: str | None
257
257
  self.smile_mac_address: str | None
258
258
  self.smile_model: str
259
259
  self.smile_model_id: str | None
260
260
  self.smile_name: str
261
261
  self.smile_type: str
262
+ self.smile_version: version.Version | None
262
263
  self.smile_zigbee_mac_address: str | None
263
264
  self.therms_with_offset_func: list[str] = []
264
265
  self._zones: dict[str, GwEntityData] = {}
@@ -797,7 +798,9 @@ class SmileHelper(SmileCommon):
797
798
  # Techneco Elga has cooling-capability
798
799
  self._cooling_present = True
799
800
  data["model"] = "Generic heater/cooler"
800
- self._cooling_enabled = data["elga_status_code"] in (8, 9)
801
+ # Cooling_enabled in xml does NOT show the correct status!
802
+ # Setting it specifically:
803
+ self._cooling_enabled = data["binary_sensors"]["cooling_enabled"] = data["elga_status_code"] in (8, 9)
801
804
  data["binary_sensors"]["cooling_state"] = self._cooling_active = (
802
805
  data["elga_status_code"] == 8
803
806
  )
@@ -811,11 +814,13 @@ class SmileHelper(SmileCommon):
811
814
 
812
815
  def _update_loria_cooling(self, data: GwEntityData) -> None:
813
816
  """Loria/Thermastage: base cooling-related on cooling_state and modulation_level."""
814
- self._cooling_enabled = data["binary_sensors"]["cooling_state"]
817
+ # For Loria/Thermastage it's not clear if cooling_enabled in xml shows the correct status,
818
+ # setting it specifically:
819
+ self._cooling_enabled = data["binary_sensors"]["cooling_enabled"] = data["binary_sensors"]["cooling_state"]
815
820
  self._cooling_active = data["sensors"]["modulation_level"] == 100
816
821
  # For Loria the above does not work (pw-beta issue #301)
817
822
  if "cooling_ena_switch" in data["switches"]:
818
- self._cooling_enabled = data["switches"]["cooling_ena_switch"]
823
+ self._cooling_enabled = data["binary_sensors"]["cooling_enabled"] = data["switches"]["cooling_ena_switch"]
819
824
  self._cooling_active = data["binary_sensors"]["cooling_state"]
820
825
 
821
826
  def _cleanup_data(self, data: GwEntityData) -> None:
@@ -917,7 +922,7 @@ class SmileHelper(SmileCommon):
917
922
  else:
918
923
  thermo_loc["secondary"].append(appliance_id)
919
924
 
920
- def _control_state(self, loc_id: str) -> str | bool:
925
+ def _control_state(self, data: GwEntityData, loc_id: str) -> str | bool:
921
926
  """Helper-function for _get_adam_data().
922
927
 
923
928
  Adam: find the thermostat control_state of a location, from DOMAIN_OBJECTS.
@@ -930,7 +935,20 @@ class SmileHelper(SmileCommon):
930
935
  if (ctrl_state := location.find(locator)) is not None:
931
936
  return str(ctrl_state.text)
932
937
 
933
- return False
938
+ # Handle missing control_state in regulation_mode off for firmware >= 3.2.0 (issue #776)
939
+ # In newer firmware versions, default to "off" when control_state is not present
940
+ if self.smile_version is not None:
941
+ if self.smile_version >= version.parse("3.2.0"):
942
+ return "off"
943
+
944
+ # Older Adam firmware does not have the control_state xml-key
945
+ # Work around this by comparing the reported temperature and setpoint for a location
946
+ setpoint = data["sensors"]["setpoint"]
947
+ temperature = data["sensors"]["temperature"]
948
+ # No cooling available in older firmware
949
+ return "heating" if temperature < setpoint else "off"
950
+
951
+ return False # pragma: no cover
934
952
 
935
953
  def _heating_valves(self) -> int | bool:
936
954
  """Helper-function for smile.py: _get_adam_data().
plugwise/smile.py CHANGED
@@ -66,6 +66,7 @@ class SmileAPI(SmileData):
66
66
  smile_model_id: str | None,
67
67
  smile_name: str,
68
68
  smile_type: str,
69
+ smile_version: Version | None,
69
70
  port: int = DEFAULT_PORT,
70
71
  username: str = DEFAULT_USERNAME,
71
72
  ) -> None:
@@ -90,6 +91,7 @@ class SmileAPI(SmileData):
90
91
  self.smile_model_id = smile_model_id
91
92
  self.smile_name = smile_name
92
93
  self.smile_type = smile_type
94
+ self.smile_version = smile_version
93
95
  SmileData.__init__(self)
94
96
 
95
97
 
@@ -129,6 +131,8 @@ class SmileAPI(SmileData):
129
131
  try:
130
132
  await self.full_xml_update()
131
133
  self.get_all_gateway_entities()
134
+ # Set self._cooling_enabled -required for set_temperature,
135
+ #also, check for a failed data-retrieval
132
136
  if "heater_id" in self.gw_data:
133
137
  heat_cooler = self.gw_entities[self.gw_data["heater_id"]]
134
138
  if (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plugwise
3
- Version: 1.6.1
3
+ Version: 1.6.3
4
4
  Summary: Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3.
5
5
  Home-page: https://github.com/plugwise/python-plugwise
6
6
  Author: Plugwise device owners
@@ -0,0 +1,17 @@
1
+ plugwise/__init__.py,sha256=GzkiJTPI0vFUIjGcIlvL_KS1lIHad_cOIKzCXwY3Eaw,17183
2
+ plugwise/common.py,sha256=vyiAbn5SJgcL5A9DYIj2ixHBbPO_6EFa16bK1VJ3In4,13040
3
+ plugwise/constants.py,sha256=yTR9uxFyWi0S5-KDtUGbtMI3eb2dGC3ekMxvL8X0qEY,17203
4
+ plugwise/data.py,sha256=kFdmCW9UEX7mqdBoGWH6TCiwb7vzdm-es5ZMwJsdBQA,12095
5
+ plugwise/exceptions.py,sha256=Ce-tO9uNsMB-8FP6VAxBvsHNJ-NIM9F0onUZOdZI4Ys,1110
6
+ plugwise/helper.py,sha256=v0sli2AE1s3ax0aAZoZw3Gmu7N9gImAol7S4l8FcuRY,45790
7
+ plugwise/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ plugwise/smile.py,sha256=fyKo60PtOnW8bK3WpIu26R0mnXmHmsdjokTjVNS0j4A,19057
9
+ plugwise/util.py,sha256=kt7JNcrTQaLT3eW_fzO4YmGsZzRull2Ge_OmHKl-rHk,8054
10
+ plugwise/legacy/data.py,sha256=wHNcRQ_qF4A1rUdxn-1MoW1Z1gUwLqOvYvIkN6tJ_sk,3088
11
+ plugwise/legacy/helper.py,sha256=ARIJytJNFiIR5G7Bp75DIULqgt56m0pxUXy6Ze8Te-4,18173
12
+ plugwise/legacy/smile.py,sha256=RCQ0kHQwmPjq_G3r6aCe75RIvJt339jilzqEKydNopo,11286
13
+ plugwise-1.6.3.dist-info/LICENSE,sha256=mL22BjmXtg_wnoDnnaqps5_Bg_VGj_yHueX5lsKwbCc,1144
14
+ plugwise-1.6.3.dist-info/METADATA,sha256=OHR2k69qRTnfT8bl5jFpVRMiDDsnY7VCUgARvRKemCc,9148
15
+ plugwise-1.6.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
16
+ plugwise-1.6.3.dist-info/top_level.txt,sha256=MYOmktMFf8ZmX6_OE1y9MoCZFfY-L8DA0F2tA2IvE4s,9
17
+ plugwise-1.6.3.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- plugwise/__init__.py,sha256=iMNBAFzwPGoCue0i3NrWekZKHFMJ5gzeStNGSR_L8F8,17151
2
- plugwise/common.py,sha256=vyiAbn5SJgcL5A9DYIj2ixHBbPO_6EFa16bK1VJ3In4,13040
3
- plugwise/constants.py,sha256=vVn407-iivZIZ1ZqwHsnWJ4KjK3PSFRFUhOfDl9Qn6E,17129
4
- plugwise/data.py,sha256=7av0Ditk_dW9L7Ojoj7xo4-pI4FHkh1KhkBsl2nmP9Q,11537
5
- plugwise/exceptions.py,sha256=Ce-tO9uNsMB-8FP6VAxBvsHNJ-NIM9F0onUZOdZI4Ys,1110
6
- plugwise/helper.py,sha256=R85dRvIgjjLx2q02iQXdW34HFl4ibS1-sJfadijBnxI,44604
7
- plugwise/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- plugwise/smile.py,sha256=tDpoAkkdY8OATmCqAfR5M-rtEvV_L3iic_929dXJwOI,18851
9
- plugwise/util.py,sha256=kt7JNcrTQaLT3eW_fzO4YmGsZzRull2Ge_OmHKl-rHk,8054
10
- plugwise/legacy/data.py,sha256=wHNcRQ_qF4A1rUdxn-1MoW1Z1gUwLqOvYvIkN6tJ_sk,3088
11
- plugwise/legacy/helper.py,sha256=ARIJytJNFiIR5G7Bp75DIULqgt56m0pxUXy6Ze8Te-4,18173
12
- plugwise/legacy/smile.py,sha256=RCQ0kHQwmPjq_G3r6aCe75RIvJt339jilzqEKydNopo,11286
13
- plugwise-1.6.1.dist-info/LICENSE,sha256=mL22BjmXtg_wnoDnnaqps5_Bg_VGj_yHueX5lsKwbCc,1144
14
- plugwise-1.6.1.dist-info/METADATA,sha256=U9kZpCeve8EIJpa6UHQnPzsppsbtTbXVkj9bRLenXjg,9148
15
- plugwise-1.6.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
16
- plugwise-1.6.1.dist-info/top_level.txt,sha256=MYOmktMFf8ZmX6_OE1y9MoCZFfY-L8DA0F2tA2IvE4s,9
17
- plugwise-1.6.1.dist-info/RECORD,,