ramses-rf 0.52.2__py3-none-any.whl → 0.52.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.
- ramses_rf/binding_fsm.py +18 -4
- ramses_rf/database.py +2 -2
- ramses_rf/device/heat.py +3 -6
- ramses_rf/entity_base.py +89 -35
- ramses_rf/system/zones.py +1 -1
- ramses_rf/version.py +1 -1
- {ramses_rf-0.52.2.dist-info → ramses_rf-0.52.3.dist-info}/METADATA +1 -1
- {ramses_rf-0.52.2.dist-info → ramses_rf-0.52.3.dist-info}/RECORD +16 -16
- ramses_tx/gateway.py +3 -0
- ramses_tx/logger.py +8 -0
- ramses_tx/schemas.py +4 -0
- ramses_tx/transport.py +14 -3
- ramses_tx/version.py +1 -1
- {ramses_rf-0.52.2.dist-info → ramses_rf-0.52.3.dist-info}/WHEEL +0 -0
- {ramses_rf-0.52.2.dist-info → ramses_rf-0.52.3.dist-info}/entry_points.txt +0 -0
- {ramses_rf-0.52.2.dist-info → ramses_rf-0.52.3.dist-info}/licenses/LICENSE +0 -0
ramses_rf/binding_fsm.py
CHANGED
|
@@ -178,6 +178,8 @@ class BindContextBase:
|
|
|
178
178
|
self, state: type[BindStateBase], result: asyncio.Future[Message] | None = None
|
|
179
179
|
) -> None:
|
|
180
180
|
"""Transition the State of the Context, and process the result, if any."""
|
|
181
|
+
# Ensure prev_state is always available, not only during debugging
|
|
182
|
+
prev_state = self._state
|
|
181
183
|
|
|
182
184
|
# if False and result:
|
|
183
185
|
# try:
|
|
@@ -185,10 +187,6 @@ class BindContextBase:
|
|
|
185
187
|
# except exc.BindingError as err:
|
|
186
188
|
# self._fut.set_result(err)
|
|
187
189
|
|
|
188
|
-
if _DBG_MAINTAIN_STATE_CHAIN: # HACK for debugging
|
|
189
|
-
# if prev_state in (None, )
|
|
190
|
-
prev_state = self._state
|
|
191
|
-
|
|
192
190
|
self._state = state(self)
|
|
193
191
|
if not self.is_binding:
|
|
194
192
|
self._is_respondent = None
|
|
@@ -197,6 +195,14 @@ class BindContextBase:
|
|
|
197
195
|
elif state is SuppSendOfferWaitForAccept:
|
|
198
196
|
self._is_respondent = False
|
|
199
197
|
|
|
198
|
+
# Log binding completion transitions
|
|
199
|
+
if isinstance(
|
|
200
|
+
self._state, (RespHasBoundAsRespondent, SuppHasBoundAsSupplicant)
|
|
201
|
+
):
|
|
202
|
+
_LOGGER.info(
|
|
203
|
+
f"{self._dev.id}: Binding process completed: {type(prev_state).__name__} -> {state.__name__} (role: {self.role})"
|
|
204
|
+
)
|
|
205
|
+
|
|
200
206
|
if _DBG_MAINTAIN_STATE_CHAIN: # HACK for debugging
|
|
201
207
|
setattr(self._state, "_prev_state", prev_state) # noqa: B010
|
|
202
208
|
|
|
@@ -663,6 +669,10 @@ class RespHasBoundAsRespondent(BindStateBase):
|
|
|
663
669
|
|
|
664
670
|
_attr_role = BindRole.IS_DORMANT
|
|
665
671
|
|
|
672
|
+
def __init__(self, context: BindContextBase) -> None:
|
|
673
|
+
super().__init__(context)
|
|
674
|
+
_LOGGER.info(f"{context._dev.id}: Binding completed as respondent")
|
|
675
|
+
|
|
666
676
|
|
|
667
677
|
class RespIsWaitingForAddenda(_DevIsWaitingForMsg, BindStateBase):
|
|
668
678
|
"""Respondent has received a Confirm & is waiting for an Addenda."""
|
|
@@ -715,6 +725,10 @@ class SuppHasBoundAsSupplicant(BindStateBase):
|
|
|
715
725
|
|
|
716
726
|
_attr_role = BindRole.IS_DORMANT
|
|
717
727
|
|
|
728
|
+
def __init__(self, context: BindContextBase) -> None:
|
|
729
|
+
super().__init__(context)
|
|
730
|
+
_LOGGER.info(f"{context._dev.id}: Binding completed as supplicant")
|
|
731
|
+
|
|
718
732
|
|
|
719
733
|
class SuppIsReadyToSendAddenda(
|
|
720
734
|
_DevIsReadyToSendCmd, BindStateBase
|
ramses_rf/database.py
CHANGED
|
@@ -334,7 +334,7 @@ class MessageIndex:
|
|
|
334
334
|
payload_keys(msg.payload),
|
|
335
335
|
),
|
|
336
336
|
)
|
|
337
|
-
_LOGGER.debug(f"Added {msg} to gwy.msg_db")
|
|
337
|
+
# _LOGGER.debug(f"Added {msg} to gwy.msg_db")
|
|
338
338
|
|
|
339
339
|
return _old_msgs[0] if _old_msgs else None
|
|
340
340
|
|
|
@@ -435,7 +435,7 @@ class MessageIndex:
|
|
|
435
435
|
|
|
436
436
|
def qry_dtms(self, **kwargs: bool | dt | str) -> list[Any]:
|
|
437
437
|
"""
|
|
438
|
-
Select from the
|
|
438
|
+
Select from the MessageIndex a list of dtms that match the provided arguments.
|
|
439
439
|
|
|
440
440
|
:param kwargs: data table field names and criteria
|
|
441
441
|
:return: list of unformatted dtms that match, useful for msg lookup, or an empty list if 0 matches
|
ramses_rf/device/heat.py
CHANGED
|
@@ -120,7 +120,7 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
120
120
|
|
|
121
121
|
class Actuator(DeviceHeat): # 3EF0, 3EF1 (for 10:/13:)
|
|
122
122
|
# .I --- 13:109598 --:------ 13:109598 3EF0 003 00C8FF # event-driven, 00/C8
|
|
123
|
-
# RP --- 13:109598 18:002563 --:------ 0008 002 00C8 # 00/C8, as
|
|
123
|
+
# RP --- 13:109598 18:002563 --:------ 0008 002 00C8 # 00/C8, as above
|
|
124
124
|
# RP --- 13:109598 18:002563 --:------ 3EF1 007 0000BF-00BFC8FF # 00/C8, as above
|
|
125
125
|
|
|
126
126
|
# RP --- 10:048122 18:140805 --:------ 3EF1 007 007FFF-003C2A10 # 10:s only RP, always 7FFF
|
|
@@ -668,11 +668,8 @@ class OtbGateway(Actuator, HeatDemand): # OTB (10): 3220 (22D9, others)
|
|
|
668
668
|
self._child_id = FC # NOTE: domain_id
|
|
669
669
|
|
|
670
670
|
# TODO(eb): cleanup
|
|
671
|
-
# should fix src/ramses_rf/database.py _add_record try/except when activating next line
|
|
672
671
|
if self._gwy.msg_db:
|
|
673
|
-
self._add_record(
|
|
674
|
-
address=self.addr, code=Code._3220, verb="RP"
|
|
675
|
-
) # << essential?
|
|
672
|
+
self._add_record(address=self.addr, code=Code._3220, verb="RP")
|
|
676
673
|
# adds a "sim" RP opentherm_msg to the SQLite MessageIndex with code _3220
|
|
677
674
|
# causes exc when fetching ALL, when no "real" msg was added to _msgs_. We skip those.
|
|
678
675
|
else:
|
|
@@ -1411,7 +1408,7 @@ class UfhCircuit(Child, Entity): # FIXME
|
|
|
1411
1408
|
def __init__(self, ufc: UfhController, ufh_idx: str) -> None:
|
|
1412
1409
|
super().__init__(ufc._gwy)
|
|
1413
1410
|
|
|
1414
|
-
# FIXME:
|
|
1411
|
+
# FIXME: gwy.msg_db entities must know their parent device ID and their own idx
|
|
1415
1412
|
self._z_id = ufc.id
|
|
1416
1413
|
self._z_idx = ufh_idx
|
|
1417
1414
|
|
ramses_rf/entity_base.py
CHANGED
|
@@ -67,8 +67,7 @@ if TYPE_CHECKING:
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
_QOS_TX_LIMIT = 12 # TODO: needs work
|
|
70
|
-
_ID_SLICE = 9
|
|
71
|
-
_SQL_SLICE = 12 # msg_db dst field query 12
|
|
70
|
+
_ID_SLICE = 9
|
|
72
71
|
_SZ_LAST_PKT: Final = "last_msg"
|
|
73
72
|
_SZ_NEXT_DUE: Final = "next_due"
|
|
74
73
|
_SZ_TIMEOUT: Final = "timeout"
|
|
@@ -248,6 +247,7 @@ class _MessageDB(_Entity):
|
|
|
248
247
|
"For %s (z_id %s) add msg %s, src %s, dst %s to msg_db.",
|
|
249
248
|
self.id,
|
|
250
249
|
self._z_id,
|
|
250
|
+
msg,
|
|
251
251
|
msg.src,
|
|
252
252
|
msg.dst,
|
|
253
253
|
)
|
|
@@ -291,7 +291,7 @@ class _MessageDB(_Entity):
|
|
|
291
291
|
|
|
292
292
|
@property
|
|
293
293
|
def _msg_list(self) -> list[Message]:
|
|
294
|
-
"""Return a flattened list of all messages logged on device."""
|
|
294
|
+
"""Return a flattened list of all messages logged on this device."""
|
|
295
295
|
# (only) used in gateway.py#get_state() and in tests/tests/test_eavesdrop_schema.py
|
|
296
296
|
if self._gwy.msg_db:
|
|
297
297
|
msg_list_qry: list[Message] = []
|
|
@@ -302,6 +302,8 @@ class _MessageDB(_Entity):
|
|
|
302
302
|
# safeguard against lookup failures ("sim" packets?)
|
|
303
303
|
msg_list_qry.append(self._msgs[c])
|
|
304
304
|
else:
|
|
305
|
+
# evohome has these errors
|
|
306
|
+
# _msg_list could not fetch self._msgs[7FFF] for 18:072981 (z_id 18:072981)
|
|
305
307
|
_LOGGER.debug(
|
|
306
308
|
"_msg_list could not fetch self._msgs[%s] for %s (z_id %s)",
|
|
307
309
|
c,
|
|
@@ -428,7 +430,7 @@ class _MessageDB(_Entity):
|
|
|
428
430
|
:param code: filter messages by Code or a tuple of Codes, optional
|
|
429
431
|
:param verb: filter on I, RQ, RP, optional, only with a single Code
|
|
430
432
|
:param key: value keyword to retrieve, not together with verb RQ
|
|
431
|
-
:param kwargs:
|
|
433
|
+
:param kwargs: extra filter, e.g. zone_idx='01'
|
|
432
434
|
:return: a dict containing key: value pairs, or a list of those
|
|
433
435
|
"""
|
|
434
436
|
assert not isinstance(code, tuple) or verb is None, (
|
|
@@ -444,7 +446,9 @@ class _MessageDB(_Entity):
|
|
|
444
446
|
key = None
|
|
445
447
|
try:
|
|
446
448
|
if self._gwy.msg_db: # central SQLite MessageIndex, use verb= kwarg
|
|
447
|
-
code = Code(
|
|
449
|
+
code = Code(
|
|
450
|
+
self._msg_qry_by_code_key(code, key, **kwargs, verb=verb)
|
|
451
|
+
)
|
|
448
452
|
msg = self._msgs.get(code)
|
|
449
453
|
else: # deprecated lookup in nested _msgz
|
|
450
454
|
msgs = self._msgz[code][verb]
|
|
@@ -456,7 +460,9 @@ class _MessageDB(_Entity):
|
|
|
456
460
|
msgs = [m for m in self._msgs.values() if m.code in code]
|
|
457
461
|
msg = max(msgs) if msgs else None
|
|
458
462
|
# return highest = latest? value found in code:value pairs
|
|
459
|
-
else:
|
|
463
|
+
else: # single Code
|
|
464
|
+
# for Zones, this doesn't work, returns first result = often wrong
|
|
465
|
+
# TODO fix in _msg_qry_by_code_key()
|
|
460
466
|
msg = self._msgs.get(code)
|
|
461
467
|
|
|
462
468
|
return self._msg_value_msg(msg, key=key, **kwargs)
|
|
@@ -531,19 +537,37 @@ class _MessageDB(_Entity):
|
|
|
531
537
|
|
|
532
538
|
:return: list of Codes or empty list when query returned empty
|
|
533
539
|
"""
|
|
540
|
+
|
|
534
541
|
if self._gwy.msg_db:
|
|
535
542
|
# SQLite query on MessageIndex
|
|
536
|
-
sql = """
|
|
537
|
-
SELECT code from messages WHERE verb in (' I', 'RP')
|
|
538
|
-
AND (src = ? OR dst = ?)
|
|
539
|
-
"""
|
|
540
543
|
res: list[Code] = []
|
|
544
|
+
if self.id[_ID_SLICE:] == "_HW":
|
|
545
|
+
sql = """
|
|
546
|
+
SELECT code from messages WHERE
|
|
547
|
+
verb in (' I', 'RP')
|
|
548
|
+
AND (src = ? OR dst = ?)
|
|
549
|
+
AND (ctx IN ('FC', 'FA', 'F9', 'FA') OR plk LIKE ?)
|
|
550
|
+
"""
|
|
551
|
+
_ctx_qry = "%dhw_idx%" # syntax error ?
|
|
552
|
+
else:
|
|
553
|
+
sql = """
|
|
554
|
+
SELECT code from messages WHERE
|
|
555
|
+
verb in (' I', 'RP')
|
|
556
|
+
AND (src = ? OR dst = ?)
|
|
557
|
+
AND ctx LIKE ?
|
|
558
|
+
"""
|
|
559
|
+
_ctx_qry = f"%{self.id[_ID_SLICE + 1 :]}%"
|
|
541
560
|
|
|
542
561
|
for rec in self._gwy.msg_db.qry_field(
|
|
543
|
-
sql, (self.id[:
|
|
562
|
+
sql, (self.id[:_ID_SLICE], self.id[:_ID_SLICE], _ctx_qry)
|
|
544
563
|
):
|
|
545
|
-
_LOGGER.debug(
|
|
546
|
-
|
|
564
|
+
_LOGGER.debug(
|
|
565
|
+
"Fetched from index: %s for %s (z_id %s)",
|
|
566
|
+
rec[0],
|
|
567
|
+
self.id,
|
|
568
|
+
self._z_id,
|
|
569
|
+
)
|
|
570
|
+
# Example: "Fetched from index: code 1FD4 for 01:123456 (z_id 01)"
|
|
547
571
|
res.append(Code(str(rec[0])))
|
|
548
572
|
return res
|
|
549
573
|
else:
|
|
@@ -566,32 +590,48 @@ class _MessageDB(_Entity):
|
|
|
566
590
|
:return: Code of most recent query result message or None when query returned empty
|
|
567
591
|
"""
|
|
568
592
|
if self._gwy.msg_db:
|
|
569
|
-
code_qry: str = ""
|
|
593
|
+
code_qry: str = "= "
|
|
570
594
|
if code is None:
|
|
571
|
-
code_qry = "
|
|
595
|
+
code_qry = "LIKE '%'" # wildcard
|
|
572
596
|
elif isinstance(code, tuple):
|
|
573
597
|
for cd in code:
|
|
574
598
|
code_qry += f"'{str(cd)}' OR code = '"
|
|
575
599
|
code_qry = code_qry[:-13] # trim last OR
|
|
576
600
|
else:
|
|
577
|
-
code_qry
|
|
578
|
-
key = "*" if key is None else f"%{key}%"
|
|
601
|
+
code_qry += str(code)
|
|
579
602
|
if kwargs["verb"] and kwargs["verb"] in (" I", "RP"):
|
|
580
603
|
vb = f"('{str(kwargs['verb'])}',)"
|
|
581
604
|
else:
|
|
582
605
|
vb = "(' I', 'RP',)"
|
|
606
|
+
ctx_qry = "%"
|
|
607
|
+
if kwargs["zone_idx"]:
|
|
608
|
+
ctx_qry = f"%{kwargs['zone_idx']}%"
|
|
609
|
+
elif kwargs["dhw_idx"]: # DHW
|
|
610
|
+
ctx_qry = f"%{kwargs['dhw_idx']}%"
|
|
611
|
+
key_qry = "%" if key is None else f"%{key}%"
|
|
612
|
+
|
|
583
613
|
# SQLite query on MessageIndex
|
|
584
614
|
sql = """
|
|
585
|
-
SELECT dtm, code from messages WHERE
|
|
615
|
+
SELECT dtm, code from messages WHERE
|
|
616
|
+
verb in ?
|
|
586
617
|
AND (src = ? OR dst = ?)
|
|
587
|
-
AND (code
|
|
618
|
+
AND (code ?)
|
|
619
|
+
AND (ctx LIKE ?)
|
|
588
620
|
AND (plk LIKE ?)
|
|
589
621
|
"""
|
|
590
622
|
latest: dt = dt(0, 0, 0)
|
|
591
623
|
res = None
|
|
592
624
|
|
|
593
625
|
for rec in self._gwy.msg_db.qry_field(
|
|
594
|
-
sql,
|
|
626
|
+
sql,
|
|
627
|
+
(
|
|
628
|
+
vb,
|
|
629
|
+
self.id[:_ID_SLICE],
|
|
630
|
+
self.id[:_ID_SLICE],
|
|
631
|
+
code_qry,
|
|
632
|
+
ctx_qry,
|
|
633
|
+
key_qry,
|
|
634
|
+
),
|
|
595
635
|
):
|
|
596
636
|
_LOGGER.debug(
|
|
597
637
|
"_msg_qry_by_code_key fetched rec: %s, code: %s", rec, code_qry
|
|
@@ -654,7 +694,7 @@ class _MessageDB(_Entity):
|
|
|
654
694
|
# """SELECT code from messages WHERE verb in (' I', 'RP') AND (src = ? OR dst = ?)
|
|
655
695
|
# AND (code = '31DA' OR ...) AND (plk LIKE '%{SZ_FAN_INFO}%' OR ...)""" = 2 params
|
|
656
696
|
for rec in self._gwy.msg_db.qry_field(
|
|
657
|
-
sql, (self.id[:
|
|
697
|
+
sql, (self.id[:_ID_SLICE], self.id[:_ID_SLICE])
|
|
658
698
|
):
|
|
659
699
|
_pl = self._msgs[Code(rec[0])].payload
|
|
660
700
|
# add payload dict to res(ults)
|
|
@@ -694,24 +734,38 @@ class _MessageDB(_Entity):
|
|
|
694
734
|
# _LOGGER.warning("Missing MessageIndex")
|
|
695
735
|
# raise NotImplementedError
|
|
696
736
|
|
|
697
|
-
if self.id[:3] == "18:": # HGI, confirm this is correct, tests suggest so
|
|
698
|
-
|
|
737
|
+
# if self.id[:3] == "18:": # HGI, confirm this is correct, tests suggest so
|
|
738
|
+
# return {}
|
|
699
739
|
|
|
700
|
-
|
|
701
|
-
SELECT dtm from messages WHERE verb in (' I', 'RP') AND (src = ? OR dst = ?)
|
|
702
|
-
"""
|
|
703
|
-
|
|
704
|
-
# handy routine to debug dict creation, see test_systems.py
|
|
740
|
+
# a routine to debug dict creation, see test_systems.py:
|
|
705
741
|
# print(f"Create _msgs for {self.id}:")
|
|
706
742
|
# results = self._gwy.msg_db._cu.execute("SELECT dtm, src, code from messages WHERE verb in (' I', 'RP') and code is '3150'")
|
|
707
743
|
# for r in results:
|
|
708
744
|
# print(r)
|
|
709
745
|
|
|
710
|
-
|
|
746
|
+
if self.id[_ID_SLICE:] == "_HW":
|
|
747
|
+
sql = """
|
|
748
|
+
SELECT dtm from messages WHERE
|
|
749
|
+
verb in (' I', 'RP')
|
|
750
|
+
AND (src = ? OR dst = ?)
|
|
751
|
+
AND (ctx IN ('FC', 'FA', 'F9', 'FA') OR plk LIKE ?)
|
|
752
|
+
"""
|
|
753
|
+
_ctx_qry = "%dhw_idx%"
|
|
754
|
+
# TODO add Children messages? self.ctl.dhw
|
|
755
|
+
else:
|
|
756
|
+
sql = """
|
|
757
|
+
SELECT dtm from messages WHERE
|
|
758
|
+
verb in (' I', 'RP')
|
|
759
|
+
AND (src = ? OR dst = ?)
|
|
760
|
+
AND ctx LIKE ?
|
|
761
|
+
"""
|
|
762
|
+
_ctx_qry = f"%{self.id[_ID_SLICE + 1 :]}%"
|
|
763
|
+
|
|
764
|
+
_msg_dict = { # since 0.52.3 use ctx (context) instead of just the address
|
|
711
765
|
m.code: m
|
|
712
766
|
for m in self._gwy.msg_db.qry(
|
|
713
|
-
sql, (self.id[:
|
|
714
|
-
) # e.g. 01:123456_HW
|
|
767
|
+
sql, (self.id[:_ID_SLICE], self.id[:_ID_SLICE], _ctx_qry)
|
|
768
|
+
) # e.g. 01:123456_HW, 01:123456_02 (Zone)
|
|
715
769
|
}
|
|
716
770
|
# if CTL, remove 3150, 3220 heat_demand, both are only stored on children
|
|
717
771
|
# HACK
|
|
@@ -786,7 +840,7 @@ class _Discovery(_MessageDB):
|
|
|
786
840
|
code: CODES_SCHEMA[code][SZ_NAME]
|
|
787
841
|
for code in sorted(
|
|
788
842
|
self._gwy.msg_db.get_rp_codes(
|
|
789
|
-
(self.id[:
|
|
843
|
+
(self.id[:_ID_SLICE], self.id[:_ID_SLICE])
|
|
790
844
|
)
|
|
791
845
|
)
|
|
792
846
|
if self._is_not_deprecated_cmd(code)
|
|
@@ -818,7 +872,7 @@ class _Discovery(_MessageDB):
|
|
|
818
872
|
AND (src = ? OR dst = ?)
|
|
819
873
|
"""
|
|
820
874
|
for rec in self._gwy.msg_db.qry_field(
|
|
821
|
-
sql, (self.id[:
|
|
875
|
+
sql, (self.id[:_ID_SLICE], self.id[:_ID_SLICE])
|
|
822
876
|
):
|
|
823
877
|
_LOGGER.debug("Fetched OT ctx from index: %s", rec[0])
|
|
824
878
|
res.append(rec[0])
|
|
@@ -949,8 +1003,8 @@ class _Discovery(_MessageDB):
|
|
|
949
1003
|
sql,
|
|
950
1004
|
(
|
|
951
1005
|
task[_SZ_COMMAND].code,
|
|
952
|
-
self.tcs.id[:_ID_SLICE],
|
|
953
|
-
self.tcs.id[:_ID_SLICE],
|
|
1006
|
+
self.tcs.id[:_ID_SLICE],
|
|
1007
|
+
self.tcs.id[:_ID_SLICE],
|
|
954
1008
|
),
|
|
955
1009
|
)[0] # expect 1 Message in returned tuple
|
|
956
1010
|
else: # TODO(eb) remove next Q1 2026
|
ramses_rf/system/zones.py
CHANGED
|
@@ -233,7 +233,7 @@ class DhwZone(ZoneSchedule): # CS92A
|
|
|
233
233
|
# def eavesdrop_dhw_sensor(this: Message, *, prev: Message | None = None) -> None:
|
|
234
234
|
# """Eavesdrop packets, or pairs of packets, to maintain the system state.
|
|
235
235
|
|
|
236
|
-
# There are only 2 ways to
|
|
236
|
+
# There are only 2 ways to find a controller's DHW sensor:
|
|
237
237
|
# 1. The 10A0 RQ/RP *from/to a 07:* (1x/4h) - reliable
|
|
238
238
|
# 2. Use sensor temp matching - non-deterministic
|
|
239
239
|
|
ramses_rf/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ramses_rf
|
|
3
|
-
Version: 0.52.
|
|
3
|
+
Version: 0.52.3
|
|
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
|
|
@@ -5,26 +5,26 @@ ramses_cli/discovery.py,sha256=MWoahBnAAVzfK2S7EDLsY2WYqN_ZK9L-lktrj8_4cb0,12978
|
|
|
5
5
|
ramses_cli/utils/cat_slow.py,sha256=AhUpM5gnegCitNKU-JGHn-DrRzSi-49ZR1Qw6lxe_t8,607
|
|
6
6
|
ramses_cli/utils/convert.py,sha256=D_YiCyX5na9pgC-_NhBlW9N1dgRKUK-uLtLBfofjzZM,1804
|
|
7
7
|
ramses_rf/__init__.py,sha256=vp2TyFGqc1fGQHsevhmaw0QEmSSCnZx7fqizKiEwHtw,1245
|
|
8
|
-
ramses_rf/binding_fsm.py,sha256=
|
|
8
|
+
ramses_rf/binding_fsm.py,sha256=fuqvcc9YW-wr8SPH8zadpPqrHAvzl_eeWF-IBtlLppY,26632
|
|
9
9
|
ramses_rf/const.py,sha256=L3z31CZ-xqno6oZp_h-67CB_5tDDqTwSWXsqRtsjMcs,5460
|
|
10
|
-
ramses_rf/database.py,sha256=
|
|
10
|
+
ramses_rf/database.py,sha256=rMfEJvapc3Zh6SFqjPjntuuaYynuZiAdYTw1pcXsJPE,20344
|
|
11
11
|
ramses_rf/dispatcher.py,sha256=YjEU-QrBLo9IfoEhJo2ikg_FxOaMYoWvzelr9Vi-JZ8,11398
|
|
12
|
-
ramses_rf/entity_base.py,sha256=
|
|
12
|
+
ramses_rf/entity_base.py,sha256=uN8QGGv0cutCYTT-oyDkvzv4xpBEObWF4jo9ArtvbLE,57640
|
|
13
13
|
ramses_rf/exceptions.py,sha256=mt_T7irqHSDKir6KLaf6oDglUIdrw0S40JbOrWJk5jc,3657
|
|
14
14
|
ramses_rf/gateway.py,sha256=VYZqMppU_kDYhT3EUmqpHf0LuLXPMH7ASx9jylAopWE,21218
|
|
15
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=jvpx0hZiMhaogyxbxnrbxS7m2GekKK4DFfVTNs7h-WQ,13476
|
|
18
|
-
ramses_rf/version.py,sha256=
|
|
18
|
+
ramses_rf/version.py,sha256=E3rkZTOmbKgrnpOmzEdweYaquvnmc18LcdiXXdsnakM,125
|
|
19
19
|
ramses_rf/device/__init__.py,sha256=sUbH5dhbYFXSoM_TPFRutpRutBRpup7_cQ9smPtDTy8,4858
|
|
20
20
|
ramses_rf/device/base.py,sha256=Yx0LZwMEb49naY8FolZ8HEBFb6XCPQBTVN_TWyO2nKg,17777
|
|
21
|
-
ramses_rf/device/heat.py,sha256=
|
|
21
|
+
ramses_rf/device/heat.py,sha256=tjORTbjxBKFzgPQbfpLuj74IlrVtOmj9GpzslK9j0A0,54569
|
|
22
22
|
ramses_rf/device/hvac.py,sha256=gdpVACUvtq6ERMI0mwRhqIJtKYEmybzJA2NeyN1ELrs,48431
|
|
23
23
|
ramses_rf/system/__init__.py,sha256=uZLKio3gLlBzePa2aDQ1nxkcp1YXOGrn6iHTG8LiNIw,711
|
|
24
24
|
ramses_rf/system/faultlog.py,sha256=GdGmVGT3137KsTlV_nhccgIFEmYu6DFsLTn4S-8JSok,12799
|
|
25
25
|
ramses_rf/system/heat.py,sha256=3jaFEChU-HlWCRMY1y7u09s7AH4hT0pC63hnqwdmZOc,39223
|
|
26
26
|
ramses_rf/system/schedule.py,sha256=Ts6tdZPTQLV5NkgwA73tPa5QUsnZNIIuYoKC-8VsXDk,18808
|
|
27
|
-
ramses_rf/system/zones.py,sha256=
|
|
27
|
+
ramses_rf/system/zones.py,sha256=YN_HAbeaa2YioUOjafEpp-0IHmIwmKNSK_77pPcjtns,36072
|
|
28
28
|
ramses_tx/__init__.py,sha256=sqnjM7pUGJDmec6igTtKViSB8FLX49B5gwhAmcY9ERY,3596
|
|
29
29
|
ramses_tx/address.py,sha256=F5ZE-EbPNNom1fW9XXUILvD7DYSMBxNJvsHVliT5gjw,8452
|
|
30
30
|
ramses_tx/command.py,sha256=tqVECwd_QokEcRv2MSk7TUU4JSBzCZcJh1eQ0jIGgoY,125122
|
|
@@ -32,9 +32,9 @@ ramses_tx/const.py,sha256=pnxq5upXvLUizv9Ye_I1llD9rAa3wddHgsSkc91AIUc,30300
|
|
|
32
32
|
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=GzNsXr15YLeidJYGtk_xPqsZQh4ehDDlUCtT6rTDhT8,22046
|
|
35
|
-
ramses_tx/gateway.py,sha256=
|
|
35
|
+
ramses_tx/gateway.py,sha256=Fl6EqAUU2DnLOiA2_87sS7VPBEyxA1a_ICCmg55WMMA,11494
|
|
36
36
|
ramses_tx/helpers.py,sha256=J4OCRckp3JshGQTvvqEskFjB1hPS7uA_opVsuIqmZds,32915
|
|
37
|
-
ramses_tx/logger.py,sha256=
|
|
37
|
+
ramses_tx/logger.py,sha256=1iKRHKUaqHqGd76CkE_6mCVR0sYODtxshRRwfY61fTk,10426
|
|
38
38
|
ramses_tx/message.py,sha256=-moQ8v3HVlNSl-x3U0DDfDcj8WQ7vLqclMNxsohbmnw,13449
|
|
39
39
|
ramses_tx/opentherm.py,sha256=58PXz9l5x8Ou6Fm3y-R_UnGHCYahoi2RKIDdYStUMzk,42378
|
|
40
40
|
ramses_tx/packet.py,sha256=_qHiPFWpQpKueZOgf1jJ93Y09iZjo3LZWStLglVkXg4,7370
|
|
@@ -43,13 +43,13 @@ ramses_tx/protocol.py,sha256=9R3aCzuiWEyXmugmB5tyR_RhBlgfnpUXj7AsMP9BzzU,28867
|
|
|
43
43
|
ramses_tx/protocol_fsm.py,sha256=ZKtehCr_4TaDdfdlfidFLJaOVTYtaEq5h4tLqNIhb9s,26827
|
|
44
44
|
ramses_tx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
ramses_tx/ramses.py,sha256=NG81GBNZlap-Gi9ac-r6OFE-KaHvXsgPDWy-I2Irr-4,53698
|
|
46
|
-
ramses_tx/schemas.py,sha256=
|
|
47
|
-
ramses_tx/transport.py,sha256=
|
|
46
|
+
ramses_tx/schemas.py,sha256=bqKW_V0bR6VbBD8ZQiBExNtVdXs0fryVKe3GEhupgIo,13424
|
|
47
|
+
ramses_tx/transport.py,sha256=oVClKNnCfHioIk5tF0TGmYspJhpggQ6EspOYeyBBR4g,58841
|
|
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.52.
|
|
52
|
-
ramses_rf-0.52.
|
|
53
|
-
ramses_rf-0.52.
|
|
54
|
-
ramses_rf-0.52.
|
|
55
|
-
ramses_rf-0.52.
|
|
50
|
+
ramses_tx/version.py,sha256=OmZAmWYXnodOMX2FqbBZjLsKSaBVpA4Y37368OIox1o,123
|
|
51
|
+
ramses_rf-0.52.3.dist-info/METADATA,sha256=u8gl35WcjLN5rO1P_BTfchK23MayeJLDQxFEhHOM-v4,4000
|
|
52
|
+
ramses_rf-0.52.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
53
|
+
ramses_rf-0.52.3.dist-info/entry_points.txt,sha256=NnyK29baOCNg8DinPYiZ368h7MTH7bgTW26z2A1NeIE,50
|
|
54
|
+
ramses_rf-0.52.3.dist-info/licenses/LICENSE,sha256=-Kc35W7l1UkdiQ4314_yVWv7vDDrg7IrJfMLUiq6Nfs,1074
|
|
55
|
+
ramses_rf-0.52.3.dist-info/RECORD,,
|
ramses_tx/gateway.py
CHANGED
|
@@ -34,6 +34,7 @@ from .schemas import (
|
|
|
34
34
|
SZ_DISABLE_QOS,
|
|
35
35
|
SZ_DISABLE_SENDING,
|
|
36
36
|
SZ_ENFORCE_KNOWN_LIST,
|
|
37
|
+
SZ_LOG_ALL_MQTT,
|
|
37
38
|
SZ_PACKET_LOG,
|
|
38
39
|
SZ_PORT_CONFIG,
|
|
39
40
|
SZ_PORT_NAME,
|
|
@@ -114,6 +115,7 @@ class Engine:
|
|
|
114
115
|
self._exclude,
|
|
115
116
|
)
|
|
116
117
|
self._sqlite_index = kwargs.pop(SZ_SQLITE_INDEX, False) # default True?
|
|
118
|
+
self._log_all_mqtt = kwargs.pop(SZ_LOG_ALL_MQTT, False)
|
|
117
119
|
self._kwargs: dict[str, Any] = kwargs # HACK
|
|
118
120
|
|
|
119
121
|
self._engine_lock = Lock() # FIXME: threading lock, or asyncio lock?
|
|
@@ -197,6 +199,7 @@ class Engine:
|
|
|
197
199
|
self._protocol,
|
|
198
200
|
disable_sending=self._disable_sending,
|
|
199
201
|
loop=self._loop,
|
|
202
|
+
log_all=self._log_all_mqtt,
|
|
200
203
|
**pkt_source,
|
|
201
204
|
**self._kwargs, # HACK: odd/misc params, e.g. comms_params
|
|
202
205
|
)
|
ramses_tx/logger.py
CHANGED
|
@@ -162,6 +162,14 @@ class StdOutFilter(logging.Filter): # record.levelno < logging.WARNING
|
|
|
162
162
|
return record.levelno < logging.WARNING
|
|
163
163
|
|
|
164
164
|
|
|
165
|
+
class BlockMqttFilter(logging.Filter):
|
|
166
|
+
"""Block mqtt traffic"""
|
|
167
|
+
|
|
168
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
169
|
+
"""Return True if the record is to be processed."""
|
|
170
|
+
return not record.getMessage().startswith("mq Rx: ")
|
|
171
|
+
|
|
172
|
+
|
|
165
173
|
class TimedRotatingFileHandler(_TimedRotatingFileHandler):
|
|
166
174
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
167
175
|
super().__init__(*args, **kwargs)
|
ramses_tx/schemas.py
CHANGED
|
@@ -413,6 +413,7 @@ SZ_EVOFW_FLAG: Final = "evofw_flag"
|
|
|
413
413
|
SZ_SQLITE_INDEX: Final = (
|
|
414
414
|
"sqlite_index" # temporary 0.52.x SQLite dev config option in ramses_cc
|
|
415
415
|
)
|
|
416
|
+
SZ_LOG_ALL_MQTT: Final = "log_all_mqtt"
|
|
416
417
|
SZ_USE_REGEX: Final = "use_regex"
|
|
417
418
|
|
|
418
419
|
SCH_ENGINE_DICT = {
|
|
@@ -427,6 +428,9 @@ SCH_ENGINE_DICT = {
|
|
|
427
428
|
vol.Optional(
|
|
428
429
|
SZ_SQLITE_INDEX, default=False
|
|
429
430
|
): bool, # temporary 0.52.x dev config option
|
|
431
|
+
vol.Optional(
|
|
432
|
+
SZ_LOG_ALL_MQTT, default=False
|
|
433
|
+
): bool, # log all incoming MQTT traffic config option
|
|
430
434
|
vol.Optional(SZ_USE_REGEX): dict, # vol.All(ConvertNullToDict(), dict),
|
|
431
435
|
vol.Optional(SZ_COMMS_PARAMS): SCH_COMMS_PARAMS,
|
|
432
436
|
}
|
ramses_tx/transport.py
CHANGED
|
@@ -1024,6 +1024,7 @@ class PortTransport(_RegHackMixin, _FullTransport, _PortTransportAbstractor): #
|
|
|
1024
1024
|
|
|
1025
1025
|
class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
1026
1026
|
"""Send/receive packets to/from ramses_esp via MQTT.
|
|
1027
|
+
For full RX logging, turn on debug logging.
|
|
1027
1028
|
|
|
1028
1029
|
See: https://github.com/IndaloTech/ramses_esp
|
|
1029
1030
|
"""
|
|
@@ -1066,6 +1067,9 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1066
1067
|
self._max_tokens: float = self._MAX_TOKENS * 2 # allow for the initial burst
|
|
1067
1068
|
self._num_tokens: float = self._MAX_TOKENS * 2
|
|
1068
1069
|
|
|
1070
|
+
# set log MQTT flag
|
|
1071
|
+
self._log_all = kwargs.pop("log_all", False)
|
|
1072
|
+
|
|
1069
1073
|
# instantiate a paho mqtt client
|
|
1070
1074
|
self.client = mqtt.Client(
|
|
1071
1075
|
protocol=mqtt.MQTTv5, callback_api_version=CallbackAPIVersion.VERSION2
|
|
@@ -1283,8 +1287,9 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1283
1287
|
|
|
1284
1288
|
if _DBG_FORCE_FRAME_LOGGING:
|
|
1285
1289
|
_LOGGER.warning("Rx: %s", msg.payload)
|
|
1286
|
-
elif _LOGGER.getEffectiveLevel() == logging.INFO:
|
|
1287
|
-
|
|
1290
|
+
elif self._log_all and _LOGGER.getEffectiveLevel() == logging.INFO:
|
|
1291
|
+
# log for INFO not DEBUG
|
|
1292
|
+
_LOGGER.info("mq Rx: %s", msg.payload) # TODO remove mq marker?
|
|
1288
1293
|
|
|
1289
1294
|
if msg.topic[-3:] != "/rx": # then, e.g. 'RAMSES/GATEWAY/18:017804'
|
|
1290
1295
|
if msg.payload == b"offline":
|
|
@@ -1507,6 +1512,7 @@ async def transport_factory(
|
|
|
1507
1512
|
disable_sending: bool | None = False,
|
|
1508
1513
|
extra: dict[str, Any] | None = None,
|
|
1509
1514
|
loop: asyncio.AbstractEventLoop | None = None,
|
|
1515
|
+
log_all: bool = False,
|
|
1510
1516
|
**kwargs: Any, # HACK: odd/misc params
|
|
1511
1517
|
) -> RamsesTransportT:
|
|
1512
1518
|
"""Create and return a Ramses-specific async packet Transport."""
|
|
@@ -1558,19 +1564,24 @@ async def transport_factory(
|
|
|
1558
1564
|
"Packet source must be exactly one of: packet_dict, packet_log, port_name"
|
|
1559
1565
|
)
|
|
1560
1566
|
|
|
1567
|
+
# File
|
|
1561
1568
|
if (pkt_source := packet_log or packet_dict) is not None:
|
|
1562
1569
|
return FileTransport(pkt_source, protocol, extra=extra, loop=loop, **kwargs)
|
|
1563
1570
|
|
|
1564
1571
|
assert port_name is not None # mypy check
|
|
1565
1572
|
assert port_config is not None # mypy check
|
|
1566
1573
|
|
|
1574
|
+
# MQTT
|
|
1567
1575
|
if port_name[:4] == "mqtt": # TODO: handle disable_sending
|
|
1568
|
-
transport = MqttTransport(
|
|
1576
|
+
transport = MqttTransport(
|
|
1577
|
+
port_name, protocol, extra=extra, loop=loop, log_all=log_all, **kwargs
|
|
1578
|
+
)
|
|
1569
1579
|
|
|
1570
1580
|
# TODO: remove this? better to invoke timeout after factory returns?
|
|
1571
1581
|
await protocol.wait_for_connection_made(timeout=_DEFAULT_TIMEOUT_MQTT)
|
|
1572
1582
|
return transport
|
|
1573
1583
|
|
|
1584
|
+
# Serial
|
|
1574
1585
|
ser_instance = get_serial_instance(port_name, port_config)
|
|
1575
1586
|
|
|
1576
1587
|
if os.name == "nt" or ser_instance.portstr[:7] in ("rfc2217", "socket:"):
|
ramses_tx/version.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|