ramses-rf 0.51.6__py3-none-any.whl → 0.51.7__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.
- ramses_rf/helpers.py +1 -1
- ramses_rf/version.py +1 -1
- {ramses_rf-0.51.6.dist-info → ramses_rf-0.51.7.dist-info}/METADATA +1 -1
- {ramses_rf-0.51.6.dist-info → ramses_rf-0.51.7.dist-info}/RECORD +12 -12
- ramses_tx/helpers.py +4 -7
- ramses_tx/logger.py +0 -27
- ramses_tx/parsers.py +21 -19
- ramses_tx/transport.py +44 -3
- ramses_tx/version.py +1 -1
- {ramses_rf-0.51.6.dist-info → ramses_rf-0.51.7.dist-info}/WHEEL +0 -0
- {ramses_rf-0.51.6.dist-info → ramses_rf-0.51.7.dist-info}/entry_points.txt +0 -0
- {ramses_rf-0.51.6.dist-info → ramses_rf-0.51.7.dist-info}/licenses/LICENSE +0 -0
ramses_rf/helpers.py
CHANGED
ramses_rf/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ramses_rf
|
|
3
|
-
Version: 0.51.
|
|
3
|
+
Version: 0.51.7
|
|
4
4
|
Summary: A stateful RAMSES-II protocol decoder & analyser.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ramses-rf/ramses_rf
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/ramses-rf/ramses_rf/issues
|
|
@@ -12,10 +12,10 @@ ramses_rf/dispatcher.py,sha256=JGkqSi1o-YhQ2rj8tNkXwYLLeJIC7F061xpHoH8sSsM,11201
|
|
|
12
12
|
ramses_rf/entity_base.py,sha256=V9m_Q5SOLP5ko3sok0NDvyz3YdYch1QsxM6tHCIE7cA,39212
|
|
13
13
|
ramses_rf/exceptions.py,sha256=rzVZDcYxFH7BjUAQ3U1fHWtgBpwk3BgjX1TO1L1iM8c,2538
|
|
14
14
|
ramses_rf/gateway.py,sha256=WdIIGgs87CYfXwSCSVb2YzqOgLC7W4bkpulWQb7PFNw,20564
|
|
15
|
-
ramses_rf/helpers.py,sha256=
|
|
15
|
+
ramses_rf/helpers.py,sha256=TNk_QkpIOB3alOp1sqnA9LOzi4fuDCeapNlW3zTzNas,4250
|
|
16
16
|
ramses_rf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
ramses_rf/schemas.py,sha256=mYOUZOH5OIDNBxRM2vd8POzDWEEmLhxh5UtqjTpFNek,13287
|
|
18
|
-
ramses_rf/version.py,sha256=
|
|
18
|
+
ramses_rf/version.py,sha256=4EfbWfYC4nSL7JCP_xnhFTpV6Yt5Vc4kNosAUW-CKNs,125
|
|
19
19
|
ramses_rf/device/__init__.py,sha256=sUbH5dhbYFXSoM_TPFRutpRutBRpup7_cQ9smPtDTy8,4858
|
|
20
20
|
ramses_rf/device/base.py,sha256=WGkBTUNjRUEe-phxdtdiXVCZnTi6-i1i_YT6g689UTM,17450
|
|
21
21
|
ramses_rf/device/heat.py,sha256=2sCsggySVcuTzyXDmgWy76QbhlU5MQWSejy3zgI5BDE,54242
|
|
@@ -33,23 +33,23 @@ ramses_tx/exceptions.py,sha256=FJSU9YkvpKjs3yeTqUJX1o3TPFSe_B01gRGIh9b3PNc,2632
|
|
|
33
33
|
ramses_tx/fingerprints.py,sha256=nfftA1E62HQnb-eLt2EqjEi_la0DAoT0wt-PtTMie0s,11974
|
|
34
34
|
ramses_tx/frame.py,sha256=9lUVh8gAMXNRAolfFw2WuWANjn24AWkmscuM9Tm5imE,22036
|
|
35
35
|
ramses_tx/gateway.py,sha256=TXLYwT6tFpmSokD29Qyj1ze7UGCxKidooeyP557Jfoo,11266
|
|
36
|
-
ramses_tx/helpers.py,sha256=
|
|
37
|
-
ramses_tx/logger.py,sha256=
|
|
36
|
+
ramses_tx/helpers.py,sha256=0VAJ505kpq4K9b9ZeskWI1o2sWwyCbdnKOKZviKFdgY,32913
|
|
37
|
+
ramses_tx/logger.py,sha256=qYbUoNPnPaFWKVsYvLG6uTVuPTdZ8HsMzBbGx0DpBqc,10177
|
|
38
38
|
ramses_tx/message.py,sha256=hl_gLfwrF79ftUNnsgNt3XGsIhM2Pts0MtZZuGjfaxk,13169
|
|
39
39
|
ramses_tx/opentherm.py,sha256=58PXz9l5x8Ou6Fm3y-R_UnGHCYahoi2RKIDdYStUMzk,42378
|
|
40
40
|
ramses_tx/packet.py,sha256=NGunaGCkEjhTp9t4mARK5e7kbqT-Z_JKCH7ibMYMJXU,7357
|
|
41
|
-
ramses_tx/parsers.py,sha256=
|
|
41
|
+
ramses_tx/parsers.py,sha256=PVTbPqcYPUko3BKDaOQoFDwIo4LWAUx5kfRb2KURAMI,109917
|
|
42
42
|
ramses_tx/protocol.py,sha256=ifj3qwcQivjQDaQUwM94xp-U8Pmef6zwSH7mav8DLWA,28867
|
|
43
43
|
ramses_tx/protocol_fsm.py,sha256=YhHkTqbl8w-myimsOjV50uIFgg9HiApwPU7xA_jg5nU,26827
|
|
44
44
|
ramses_tx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
ramses_tx/ramses.py,sha256=9R-JrInORWUNMPklrAPQWwtr_2aaruQmFqQPw5mFkrE,52223
|
|
46
46
|
ramses_tx/schemas.py,sha256=h2AcArVROy1_C4n6F0Crj4e-2BxXxH74xogFlc6nKHI,12769
|
|
47
|
-
ramses_tx/transport.py,sha256=
|
|
47
|
+
ramses_tx/transport.py,sha256=MwPnkQ0L-2qJt4mIJy3-C9XmHwBDjT7Kg-1LthPByVw,58331
|
|
48
48
|
ramses_tx/typed_dicts.py,sha256=w-0V5t2Q3GiNUOrRAWiW9GtSwbta_7luME6GfIb1zhI,10869
|
|
49
49
|
ramses_tx/typing.py,sha256=eF2SlPWhNhEFQj6WX2AhTXiyRQVXYnFutiepllYl2rI,5042
|
|
50
|
-
ramses_tx/version.py,sha256=
|
|
51
|
-
ramses_rf-0.51.
|
|
52
|
-
ramses_rf-0.51.
|
|
53
|
-
ramses_rf-0.51.
|
|
54
|
-
ramses_rf-0.51.
|
|
55
|
-
ramses_rf-0.51.
|
|
50
|
+
ramses_tx/version.py,sha256=hWp2I2S7p1_tlItYBqDNAFpsM7kL_J8xYU-6mC2e_Ws,123
|
|
51
|
+
ramses_rf-0.51.7.dist-info/METADATA,sha256=w3QiOIRJncgPc3R3h1MaxjMDOjzm0NYBHFEoeAr6o6A,3909
|
|
52
|
+
ramses_rf-0.51.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
53
|
+
ramses_rf-0.51.7.dist-info/entry_points.txt,sha256=NnyK29baOCNg8DinPYiZ368h7MTH7bgTW26z2A1NeIE,50
|
|
54
|
+
ramses_rf-0.51.7.dist-info/licenses/LICENSE,sha256=-Kc35W7l1UkdiQ4314_yVWv7vDDrg7IrJfMLUiq6Nfs,1074
|
|
55
|
+
ramses_rf-0.51.7.dist-info/RECORD,,
|
ramses_tx/helpers.py
CHANGED
|
@@ -470,7 +470,7 @@ def parse_valve_demand(
|
|
|
470
470
|
if int(value, 16) & 0xF0 == 0xF0:
|
|
471
471
|
return _faulted_device(SZ_HEAT_DEMAND, value)
|
|
472
472
|
|
|
473
|
-
result = int(value, 16) / 200 # c.f.
|
|
473
|
+
result = int(value, 16) / 200 # c.f. hex_to_percent
|
|
474
474
|
if result == 1.01: # HACK - does it mean maximum?
|
|
475
475
|
result = 1.0
|
|
476
476
|
elif result > 1.0:
|
|
@@ -606,12 +606,9 @@ def _parse_hvac_humidity(
|
|
|
606
606
|
if int(value, 16) & 0xF0 == 0xF0:
|
|
607
607
|
return _faulted_sensor(param_name, value)
|
|
608
608
|
|
|
609
|
-
percentage =
|
|
610
|
-
assert percentage <= 1.0, value # TODO: raise exception if > 1.0?
|
|
609
|
+
percentage = hex_to_percent(value, False) # TODO: confirm not /200
|
|
611
610
|
|
|
612
|
-
result: dict[str, float | str | None] = {
|
|
613
|
-
param_name: percentage
|
|
614
|
-
} # was: percent_from_hex(value, high_res=False)
|
|
611
|
+
result: dict[str, float | str | None] = {param_name: percentage}
|
|
615
612
|
if temp:
|
|
616
613
|
result |= {SZ_TEMPERATURE: hex_to_temp(temp)}
|
|
617
614
|
if dewpoint:
|
|
@@ -881,7 +878,7 @@ def _parse_fan_heater(param_name: str, value: HexStr2) -> Mapping[str, float | N
|
|
|
881
878
|
if int(value, 16) & 0xF0 == 0xF0:
|
|
882
879
|
return _faulted_sensor(param_name, value) # type: ignore[return-value]
|
|
883
880
|
|
|
884
|
-
percentage = int(value, 16) / 200 # Siber DF EVO 2 is /200, not /100 (?
|
|
881
|
+
percentage = int(value, 16) / 200 # Siber DF EVO 2 is /200, not /100 (Others?)
|
|
885
882
|
assert percentage <= 1.0, value # TODO: raise exception if > 1.0?
|
|
886
883
|
|
|
887
884
|
return {param_name: percentage} # was: percent_from_hex(value, high_res=False)
|
ramses_tx/logger.py
CHANGED
|
@@ -173,33 +173,6 @@ class TimedRotatingFileHandler(_TimedRotatingFileHandler):
|
|
|
173
173
|
# self.doRollover()
|
|
174
174
|
# return super().emit(record)
|
|
175
175
|
|
|
176
|
-
# To fix issue ramses_cc 293, test if this override is still required
|
|
177
|
-
# async def getFilesToDelete(self) -> list[str]: # zxdavb: my version
|
|
178
|
-
# """Determine the files to delete when rolling over.
|
|
179
|
-
#
|
|
180
|
-
# Overridden as old log files were not being deleted.
|
|
181
|
-
# """
|
|
182
|
-
# # See bpo-44753 (this code is as was before that commit), bpo45628, bpo-46063
|
|
183
|
-
# dirName, baseName = os.path.split(self.baseFilename)
|
|
184
|
-
# loop = asyncio.get_running_loop()
|
|
185
|
-
# # Must run async in executor to prevent HA blocking call on rollover (ramses_cc issue 293)
|
|
186
|
-
# file_names = await loop.run_in_executor(None, os.listdir, dirName) < doesn't work
|
|
187
|
-
#
|
|
188
|
-
# result = []
|
|
189
|
-
# prefix = baseName + "."
|
|
190
|
-
# plen = len(prefix)
|
|
191
|
-
# for fileName in file_names:
|
|
192
|
-
# if fileName[:plen] == prefix:
|
|
193
|
-
# suffix = fileName[plen:]
|
|
194
|
-
# if self.extMatch.match(suffix):
|
|
195
|
-
# result.append(os.path.join(dirName, fileName))
|
|
196
|
-
# if len(result) < self.backupCount:
|
|
197
|
-
# result = []
|
|
198
|
-
# else:
|
|
199
|
-
# result.sort()
|
|
200
|
-
# result = result[: len(result) - self.backupCount]
|
|
201
|
-
# return result
|
|
202
|
-
|
|
203
176
|
|
|
204
177
|
def getLogger( # permits a bespoke Logger class
|
|
205
178
|
name: str | None = None, pkt_log: bool = False
|
ramses_tx/parsers.py
CHANGED
|
@@ -1648,21 +1648,17 @@ def parser_22f3(payload: str, msg: Message) -> dict[str, Any]:
|
|
|
1648
1648
|
_LOGGER.warning(f"{msg!r} < {_INFORM_DEV_MSG} ({err})")
|
|
1649
1649
|
|
|
1650
1650
|
new_speed = { # from now, until timer expiry
|
|
1651
|
-
0x00: "fan_boost", #
|
|
1652
|
-
0x01: "per_request", #
|
|
1653
|
-
0x02: "
|
|
1651
|
+
0x00: "fan_boost", # set fan off, or 'boost' mode?
|
|
1652
|
+
0x01: "per_request?", # set fan as per payload[6:10]?
|
|
1653
|
+
0x02: "per_request", # set fan as per payload[6:10]
|
|
1654
1654
|
}.get(int(payload[2:4], 0x10) & 0x07) # 0b0000-0111
|
|
1655
1655
|
|
|
1656
|
-
fallback_speed
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
# set fan as per
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
0x08: "fan_off", # # set fan off?
|
|
1663
|
-
0x10: "per_request", # # set fan as per payload[6:10], or payload[10:]?
|
|
1664
|
-
0x18: "per_vent_speed", # set fan as per current fan mode/speed?
|
|
1665
|
-
}.get(int(payload[2:4], 0x10) & 0x38) # 0b0011-1000
|
|
1656
|
+
fallback_speed = { # after timer expiry
|
|
1657
|
+
0x00: "per_vent_speed", # set fan as per current fan mode
|
|
1658
|
+
0x08: "fan_off", # set fan off?
|
|
1659
|
+
0x10: "per_request", # set fan as per payload[10:14]
|
|
1660
|
+
0x18: "per_vent_speed?", # set fan as per current fan mode/speed?
|
|
1661
|
+
}.get(int(payload[2:4], 0x10) & 0x38) # 0b0011-1000
|
|
1666
1662
|
|
|
1667
1663
|
units = {
|
|
1668
1664
|
0x00: "minutes",
|
|
@@ -1677,15 +1673,21 @@ def parser_22f3(payload: str, msg: Message) -> dict[str, Any]:
|
|
|
1677
1673
|
result = {
|
|
1678
1674
|
"minutes" if units != "index" else "index": duration,
|
|
1679
1675
|
"flags": hex_to_flag8(payload[2:4]),
|
|
1680
|
-
"
|
|
1681
|
-
"
|
|
1676
|
+
"new_speed_mode": new_speed,
|
|
1677
|
+
"fallback_speed_mode": fallback_speed,
|
|
1682
1678
|
}
|
|
1683
1679
|
|
|
1684
|
-
if msg.
|
|
1685
|
-
result["
|
|
1680
|
+
if msg._addrs[0] == NON_DEV_ADDR and msg.len <= 3:
|
|
1681
|
+
result["_scheme"] = "itho"
|
|
1682
|
+
|
|
1683
|
+
if msg.len >= 5 and payload[6:10] != "0000": # new speed
|
|
1684
|
+
mode_info = parser_22f1(f"00{payload[6:10]}", msg)
|
|
1685
|
+
result["_scheme"] = mode_info.get("_scheme")
|
|
1686
|
+
result["fan_mode"] = mode_info.get("fan_mode")
|
|
1686
1687
|
|
|
1687
|
-
if msg.len >= 7: # fallback speed
|
|
1688
|
-
|
|
1688
|
+
if msg.len >= 7 and payload[10:14] != "0000": # fallback speed
|
|
1689
|
+
mode_info = parser_22f1(f"00{payload[10:14]}", msg)
|
|
1690
|
+
result["fallback_fan_mode"] = mode_info.get("fan_mode")
|
|
1689
1691
|
|
|
1690
1692
|
return result
|
|
1691
1693
|
|
ramses_tx/transport.py
CHANGED
|
@@ -1033,6 +1033,8 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1033
1033
|
self._topic_base = validate_topic_path(self._broker_url.path)
|
|
1034
1034
|
self._topic_pub = ""
|
|
1035
1035
|
self._topic_sub = ""
|
|
1036
|
+
# Track if we've subscribed to a wildcard data topic (e.g. ".../+/rx")
|
|
1037
|
+
self._data_wildcard_topic = ""
|
|
1036
1038
|
|
|
1037
1039
|
self._mqtt_qos = int(parse_qs(self._broker_url.query).get("qos", ["0"])[0])
|
|
1038
1040
|
|
|
@@ -1143,17 +1145,30 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1143
1145
|
# Subscribe to base topic to see 'online' messages
|
|
1144
1146
|
self.client.subscribe(self._topic_base) # hope to see 'online' message
|
|
1145
1147
|
|
|
1146
|
-
# Also subscribe to data topics with wildcard for reliability
|
|
1147
|
-
#
|
|
1148
|
-
|
|
1148
|
+
# Also subscribe to data topics with wildcard for reliability, but only
|
|
1149
|
+
# until a specific device topic is known. Once _topic_sub is set, avoid
|
|
1150
|
+
# overlapping subscriptions that would duplicate messages.
|
|
1151
|
+
if self._topic_base.endswith("/+") and not (
|
|
1152
|
+
hasattr(self, "_topic_sub") and self._topic_sub
|
|
1153
|
+
):
|
|
1149
1154
|
data_wildcard = self._topic_base.replace("/+", "/+/rx")
|
|
1150
1155
|
self.client.subscribe(data_wildcard, qos=self._mqtt_qos)
|
|
1156
|
+
self._data_wildcard_topic = data_wildcard
|
|
1151
1157
|
_LOGGER.debug(f"Subscribed to data wildcard: {data_wildcard}")
|
|
1152
1158
|
|
|
1153
1159
|
# If we already have specific topics, re-subscribe to them
|
|
1154
1160
|
if hasattr(self, "_topic_sub") and self._topic_sub:
|
|
1155
1161
|
self.client.subscribe(self._topic_sub, qos=self._mqtt_qos)
|
|
1156
1162
|
_LOGGER.debug(f"Re-subscribed to specific topic: {self._topic_sub}")
|
|
1163
|
+
# If we had a wildcard subscription, drop it to prevent duplicates
|
|
1164
|
+
if getattr(self, "_data_wildcard_topic", ""):
|
|
1165
|
+
try:
|
|
1166
|
+
self.client.unsubscribe(self._data_wildcard_topic)
|
|
1167
|
+
_LOGGER.debug(
|
|
1168
|
+
f"Unsubscribed data wildcard after specific subscribe: {self._data_wildcard_topic}"
|
|
1169
|
+
)
|
|
1170
|
+
finally:
|
|
1171
|
+
self._data_wildcard_topic = ""
|
|
1157
1172
|
|
|
1158
1173
|
def _on_connect_fail(
|
|
1159
1174
|
self,
|
|
@@ -1225,6 +1240,17 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1225
1240
|
|
|
1226
1241
|
self.client.subscribe(self._topic_sub, qos=self._mqtt_qos)
|
|
1227
1242
|
|
|
1243
|
+
# If we previously subscribed to a wildcard data topic, unsubscribe now
|
|
1244
|
+
# to avoid duplicate delivery (wildcard and specific both matching)
|
|
1245
|
+
if getattr(self, "_data_wildcard_topic", ""):
|
|
1246
|
+
try:
|
|
1247
|
+
self.client.unsubscribe(self._data_wildcard_topic)
|
|
1248
|
+
_LOGGER.debug(
|
|
1249
|
+
f"Unsubscribed data wildcard after device online: {self._data_wildcard_topic}"
|
|
1250
|
+
)
|
|
1251
|
+
finally:
|
|
1252
|
+
self._data_wildcard_topic = ""
|
|
1253
|
+
|
|
1228
1254
|
# Only call connection_made on first connection, not reconnections
|
|
1229
1255
|
if not self._connection_established:
|
|
1230
1256
|
self._connection_established = True
|
|
@@ -1295,6 +1321,21 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1295
1321
|
self._connection_established = True
|
|
1296
1322
|
self._make_connection(gwy_id=gateway_id) # type: ignore[arg-type]
|
|
1297
1323
|
|
|
1324
|
+
# Ensure we subscribe specifically to the device topic and drop the
|
|
1325
|
+
# wildcard subscription to prevent duplicates
|
|
1326
|
+
try:
|
|
1327
|
+
self.client.subscribe(self._topic_sub, qos=self._mqtt_qos)
|
|
1328
|
+
except Exception as err: # pragma: no cover - defensive
|
|
1329
|
+
_LOGGER.debug(f"Error subscribing specific topic: {err}")
|
|
1330
|
+
if getattr(self, "_data_wildcard_topic", ""):
|
|
1331
|
+
try:
|
|
1332
|
+
self.client.unsubscribe(self._data_wildcard_topic)
|
|
1333
|
+
_LOGGER.debug(
|
|
1334
|
+
f"Unsubscribed data wildcard after inferring device: {self._data_wildcard_topic}"
|
|
1335
|
+
)
|
|
1336
|
+
finally:
|
|
1337
|
+
self._data_wildcard_topic = ""
|
|
1338
|
+
|
|
1298
1339
|
try:
|
|
1299
1340
|
payload = json.loads(msg.payload)
|
|
1300
1341
|
except json.JSONDecodeError:
|
ramses_tx/version.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|