ramses-rf 0.51.8__tar.gz → 0.51.9__tar.gz
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-0.51.8 → ramses_rf-0.51.9}/PKG-INFO +1 -1
- ramses_rf-0.51.9/ramses_rf/database.py +490 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/device/hvac.py +69 -87
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/dispatcher.py +7 -5
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/version.py +1 -1
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/address.py +1 -1
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/const.py +1 -1
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/frame.py +4 -4
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/gateway.py +1 -1
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/message.py +20 -14
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/packet.py +1 -1
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/parsers.py +45 -26
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/transport.py +9 -7
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/version.py +1 -1
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/requirements_dev.txt +1 -1
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_apis_hvac.py +13 -13
- ramses_rf-0.51.9/tests/tests_rf/device/__init__.py +2 -0
- {ramses_rf-0.51.8/tests → ramses_rf-0.51.9/tests/tests_rf/device}/test_hvac_ventilator.py +15 -25
- ramses_rf-0.51.8/ramses_rf/database.py +0 -312
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.github/dependabot.yml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.github/workflows/check-lint.yml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.github/workflows/check-test.yml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.github/workflows/check-type.yml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.github/workflows/publish-hatch.yml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.gitignore +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/.pre-commit-config.yaml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/LICENSE +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/README-developers.md +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/README.md +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/client.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/misc/fingerprints.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/misc/ser2net.yaml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/misc/ti_3410/notes.sh +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/misc/ti_3410/ti_3410.fw +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/pyproject.toml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_cli/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_cli/client.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_cli/debug.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_cli/discovery.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_cli/utils/cat_slow.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_cli/utils/convert.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/binding_fsm.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/const.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/device/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/device/base.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/device/heat.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/entity_base.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/exceptions.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/gateway.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/helpers.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/py.typed +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/schemas.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/system/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/system/faultlog.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/system/heat.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/system/schedule.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_rf/system/zones.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/command.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/exceptions.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/fingerprints.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/helpers.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/logger.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/opentherm.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/protocol.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/protocol_fsm.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/py.typed +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/ramses.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/schemas.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/typed_dicts.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/ramses_tx/typing.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/requirements.txt +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/_test_apis_mock.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/_test_mock_faultlog.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/_test_mock_schedule.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/_test_packets_bad.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/_test_performance_WIP.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/_test_state_mgt.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/common.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/mocked_devices/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/mocked_devices/command.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/mocked_devices/const.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/mocked_devices/device_heat.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/mocked_devices/device_hvac.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/deprecated/mocked_devices/transport.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/heat/ctl_bdr_91t.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/heat/dts_ctl_sensor.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/heat/hcw_ctl_sensor.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/heat/rnd_ctl_sensor.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/heat/rnd_ctl_sensor.yaml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/heat/trv_ctl.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/co2_fan_itho.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/co2_fan_itho.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/co2_fan_itho.yaml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/dis_fan_orcon.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/dis_fan_orcon.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/rem_fan_climarad.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/rem_fan_nuaire.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/rem_fan_nuaire.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/rem_fan_nuaire.yaml +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/rem_fan_vasco.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/bindings/hvac/rem_fan_ventura.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/devices/device_02.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/devices/device_04.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/devices/device_10.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/devices/device_13.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/devices/device_22.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_dev_class/hvac/known_list_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_dev_class/hvac/known_list_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_dev_class/hvac/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_trv_actuator_long/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_trv_actuator_long/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_trv_actuator_long/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_trv_actuator_mixed/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_trv_actuator_mixed/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_trv_actuator_mixed/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_ufh_circuits/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_ufh_circuits/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/_ufh_circuits/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/app_cntrl/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/app_cntrl/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/app_cntrl/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/trv_actuators/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/trv_actuators/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/trv_actuators/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_000/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_000/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_000/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_001/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_001/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_001/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_002/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_002/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_002/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_003/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_003/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_003/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_004/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_004/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/eavesdrop_schema/zone_sensors_004/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/10e0_xxxx.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/_gather.sh +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/01_EvoTouch_Colour.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/01_Evo_Color.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/01_IONA_RAI_Prototype.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/02_HCE80_V3.10_061117..log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/04_HR92 Radiator Ctrl_.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/08_Jasper_EIM.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/10_R8810A_Bridge.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/10_R8820.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/30_Internet_Gateway.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/31_Jasper_Stat_TXXX.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/heat/34_T87RF2025.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/18_BRDG-02A55.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/18_HRA82.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/20.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/21_CCU-12T20.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMC-07RP01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMC-15RP01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMC-17RP01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMN-07LM01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMN-15LF01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMN-17LMP01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMS-15C16.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/29_VMS-17HB01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/30_BRDG-02EM23.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/30_BRDG-02JAS01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMC-15RPS34.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMD-15RMS64.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMD-15RMS86.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMD-17RPS01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMN-23LM33.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMN-23LMH23.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMS-15CM17.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMS-23C33.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMS-23HB33.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/32_VMZ-15V13.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/37_VMD-07RPS13.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/37_VMI-15MC01log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/37_VMI-15WSJ53.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/37_VMS-02J52.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/37_VMS-12C39.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/99_CVE-RF.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/fingerprints/hvac/99_VMS-17C01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/helpers.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/logger/packet_in.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/logger/packet_out.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/logs/pkts_bad_000.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/logs/pkts_tba_000.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/logs/system_cache.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parser_helpers/pkt_addr_set.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parser_helpers/pkt_dev_class.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0001_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0002.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0004_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0005.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0006.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0008.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0009.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_000a.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_000c.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_000e.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_01ff_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_0418.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_042f.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1030.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1060.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_10d0.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_10e0.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1260.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1298.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_12a0.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_12c0.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1300.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1f09.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1fc9.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_1fd4.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_2210.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22c9.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22d0.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22d9.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22e0.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22e5.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22e9.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22f1.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22f2.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22f3.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22f4.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_22f7.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_2309.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_2349.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_2411_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_2e04.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_2e10_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_30c9.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3110_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3120.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_313e_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3150.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_31d9.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_31da.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3200.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3210.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3220.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3222.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3ef0_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_3ef1_wip.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_4e01.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_4e02.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_4e04.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/parsers/code_4e15.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schedules/_sched_002/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schedules/_sched_002/schedule.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schedules/sched_001/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schedules/sched_001/schedule.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schedules/sched_dhw/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schedules/sched_dhw/schedule.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/jsn_files/schema_100.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/jsn_files/schema_101.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/jsn_files/schema_102.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/jsn_files/schema_103.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/jsn_files/schema_104.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/jsn_files/schema_105.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/jsn_files/schema_108.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_000.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_000.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_001.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_001.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_002.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_002.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_010.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_010.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_011.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_011.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_012.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_012.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_013.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_013.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_014.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_014.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_300.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_300.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_301.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_301.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_302.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_302.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_303.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_303.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_304.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_304.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_310.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/schemas/log_files/schema_310.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_heat_trv_00/config.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_heat_trv_00/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_heat_trv_00/schema.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_hvac_nuaire/config.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_hvac_nuaire/known_list.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_hvac_nuaire/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_hvac_nuaire/schema.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/_hvac_nuaire/status.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_otb_00/config.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_otb_00/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_otb_00/schema.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_simple/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_simple/schema.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_ufc_00/config.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_ufc_00/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_ufc_01/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_zxdavb/config.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_zxdavb/known_list.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_zxdavb/packet.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/systems/heat_zxdavb/schema.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_api_faultlog.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_api_schedule.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_apis_binding.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_apis_common.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_apis_heat.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_cli_utility.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_devices.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_eavesdrop_dev_class.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_eavesdrop_schema.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_helpers.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_parser_helpers.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_parsers.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_ramses_schema.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_schema_bits.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_schemas.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_systems.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests/test_vol_schemas.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/configs/config_heat.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/configs/config_hvac.json +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/conftest.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/logs/test_api_faultlog.log +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_api_faultlog.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_api_schedule.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_binding_fsm.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_create_stack.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_hgi_behaviors.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_protocol_fsm.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_use_regex.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/test_virt_network.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/virtual_rf/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/virtual_rf/const.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/virtual_rf/helpers.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_rf/virtual_rf/virtual_rf.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_tx/__init__.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/tests_tx/test_command.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/wip/_test_eavesdrop_dhw_sensor.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/wip/_test_eavesdrop_htg_control.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/wip/_test_eavesdrop_ufc_circuits.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/wip/_test_eavesdrop_zone_sensors.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/wip/_test_eavesdrop_zone_type.py +0 -0
- {ramses_rf-0.51.8 → ramses_rf-0.51.9}/tests/wip/test_wip_cli.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ramses_rf
|
|
3
|
-
Version: 0.51.
|
|
3
|
+
Version: 0.51.9
|
|
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
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""RAMSES RF - Message database and index."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import logging
|
|
8
|
+
import sqlite3
|
|
9
|
+
from collections import OrderedDict
|
|
10
|
+
from datetime import datetime as dt, timedelta as td
|
|
11
|
+
from typing import Any, NewType, TypedDict
|
|
12
|
+
|
|
13
|
+
from ramses_tx import Message
|
|
14
|
+
|
|
15
|
+
DtmStrT = NewType("DtmStrT", str)
|
|
16
|
+
MsgDdT = OrderedDict[DtmStrT, Message]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Params(TypedDict):
|
|
20
|
+
dtm: dt | str | None
|
|
21
|
+
verb: str | None
|
|
22
|
+
src: str | None
|
|
23
|
+
dst: str | None
|
|
24
|
+
code: str | None
|
|
25
|
+
ctx: str | None
|
|
26
|
+
hdr: str | None
|
|
27
|
+
plk: str | None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
_LOGGER = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _setup_db_adapters() -> None:
|
|
34
|
+
"""Set up the database adapters and converters."""
|
|
35
|
+
|
|
36
|
+
def adapt_datetime_iso(val: dt) -> str:
|
|
37
|
+
"""Adapt datetime.datetime to timezone-naive ISO 8601 datetime to match _msgs_ dtm keys."""
|
|
38
|
+
return val.isoformat(timespec="microseconds")
|
|
39
|
+
|
|
40
|
+
sqlite3.register_adapter(dt, adapt_datetime_iso)
|
|
41
|
+
|
|
42
|
+
def convert_datetime(val: bytes) -> dt:
|
|
43
|
+
"""Convert ISO 8601 datetime to datetime.datetime object to import dtm in msg_db."""
|
|
44
|
+
return dt.fromisoformat(val.decode())
|
|
45
|
+
|
|
46
|
+
sqlite3.register_converter("DTM", convert_datetime)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def payload_keys(parsed_payload: list[dict] | dict) -> str: # type: ignore[type-arg]
|
|
50
|
+
"""
|
|
51
|
+
Copy payload keys for fast query check.
|
|
52
|
+
|
|
53
|
+
:param parsed_payload: pre-parsed message payload dict
|
|
54
|
+
:return: string of payload keys, separated by the | char
|
|
55
|
+
"""
|
|
56
|
+
_keys: str = "|"
|
|
57
|
+
|
|
58
|
+
def append_keys(ppl: dict) -> str: # type: ignore[type-arg]
|
|
59
|
+
_ks: str = ""
|
|
60
|
+
for k, v in ppl.items():
|
|
61
|
+
if (
|
|
62
|
+
k not in _ks and k not in _keys and v is not None
|
|
63
|
+
): # ignore keys with None value
|
|
64
|
+
_ks += k + "|"
|
|
65
|
+
return _ks
|
|
66
|
+
|
|
67
|
+
if isinstance(parsed_payload, list):
|
|
68
|
+
for d in parsed_payload:
|
|
69
|
+
_keys += append_keys(d)
|
|
70
|
+
elif isinstance(parsed_payload, dict):
|
|
71
|
+
_keys += append_keys(parsed_payload)
|
|
72
|
+
return _keys
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class MessageIndex:
|
|
76
|
+
"""A simple in-memory SQLite3 database for indexing RF messages.
|
|
77
|
+
Index holds the latest message to & from all devices by header
|
|
78
|
+
(example of a hdr: 000C|RP|01:223036|0208)."""
|
|
79
|
+
|
|
80
|
+
def __init__(self, maintain: bool = True) -> None:
|
|
81
|
+
"""Instantiate a message database/index."""
|
|
82
|
+
|
|
83
|
+
self.maintain = maintain
|
|
84
|
+
self._msgs: MsgDdT = (
|
|
85
|
+
OrderedDict()
|
|
86
|
+
) # stores all messages for retrieval. Filled in housekeeping loop.
|
|
87
|
+
|
|
88
|
+
# Connect to a SQLite DB in memory
|
|
89
|
+
self._cx = sqlite3.connect(
|
|
90
|
+
":memory:", detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES
|
|
91
|
+
)
|
|
92
|
+
# detect_types should retain dt type on store/retrieve
|
|
93
|
+
self._cu = self._cx.cursor() # Create a cursor
|
|
94
|
+
|
|
95
|
+
_setup_db_adapters() # DTM adapter/converter
|
|
96
|
+
self._setup_db_schema()
|
|
97
|
+
|
|
98
|
+
if self.maintain:
|
|
99
|
+
self._lock = asyncio.Lock()
|
|
100
|
+
self._last_housekeeping: dt = None # type: ignore[assignment]
|
|
101
|
+
self._housekeeping_task: asyncio.Task[None] = None # type: ignore[assignment]
|
|
102
|
+
|
|
103
|
+
self.start()
|
|
104
|
+
|
|
105
|
+
def __repr__(self) -> str:
|
|
106
|
+
return f"MessageIndex({len(self._msgs)} messages)" # or msg_db.count()
|
|
107
|
+
|
|
108
|
+
def start(self) -> None:
|
|
109
|
+
"""Start the housekeeper loop."""
|
|
110
|
+
|
|
111
|
+
if self.maintain:
|
|
112
|
+
if self._housekeeping_task and not self._housekeeping_task.done():
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
self._housekeeping_task = asyncio.create_task(
|
|
116
|
+
self._housekeeping_loop(), name=f"{self.__class__.__name__}.housekeeper"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def stop(self) -> None:
|
|
120
|
+
"""Stop the housekeeper loop."""
|
|
121
|
+
|
|
122
|
+
if self._housekeeping_task and not self._housekeeping_task.done():
|
|
123
|
+
self._housekeeping_task.cancel() # stop the housekeeper
|
|
124
|
+
|
|
125
|
+
self._cx.commit() # just in case
|
|
126
|
+
# self._cx.close() # may still need to do queries after engine has stopped?
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def msgs(self) -> MsgDdT:
|
|
130
|
+
"""Return the messages in the index in a threadsafe way."""
|
|
131
|
+
return self._msgs
|
|
132
|
+
|
|
133
|
+
def _setup_db_schema(self) -> None:
|
|
134
|
+
"""Set up the message database schema.
|
|
135
|
+
|
|
136
|
+
messages TABLE Fields:
|
|
137
|
+
|
|
138
|
+
- dtm message timestamp
|
|
139
|
+
- verb " I", "RQ" etc.
|
|
140
|
+
- src message origin address
|
|
141
|
+
- dst message destination address
|
|
142
|
+
- code packet code aka command class e.g. _0005, _31DA
|
|
143
|
+
- ctx message context, created from payload as index + extra markers (Heat)
|
|
144
|
+
- hdr packet header e.g. 000C|RP|01:223036|0208 (see: src/ramses_tx/frame.py)
|
|
145
|
+
- plk the keys stored in the parsed payload, separated by the | char
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
self._cu.execute(
|
|
149
|
+
"""
|
|
150
|
+
CREATE TABLE messages (
|
|
151
|
+
dtm DTM NOT NULL PRIMARY KEY,
|
|
152
|
+
verb TEXT(2) NOT NULL,
|
|
153
|
+
src TEXT(9) NOT NULL,
|
|
154
|
+
dst TEXT(9) NOT NULL,
|
|
155
|
+
code TEXT(4) NOT NULL,
|
|
156
|
+
ctx TEXT,
|
|
157
|
+
hdr TEXT NOT NULL UNIQUE,
|
|
158
|
+
plk TEXT NOT NULL
|
|
159
|
+
)
|
|
160
|
+
"""
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
self._cu.execute("CREATE INDEX idx_verb ON messages (verb)")
|
|
164
|
+
self._cu.execute("CREATE INDEX idx_src ON messages (src)")
|
|
165
|
+
self._cu.execute("CREATE INDEX idx_dst ON messages (dst)")
|
|
166
|
+
self._cu.execute("CREATE INDEX idx_code ON messages (code)")
|
|
167
|
+
self._cu.execute("CREATE INDEX idx_ctx ON messages (ctx)")
|
|
168
|
+
self._cu.execute("CREATE INDEX idx_hdr ON messages (hdr)")
|
|
169
|
+
|
|
170
|
+
self._cx.commit()
|
|
171
|
+
|
|
172
|
+
async def _housekeeping_loop(self) -> None:
|
|
173
|
+
"""Periodically remove stale messages from the index,
|
|
174
|
+
unless self.maintain is False."""
|
|
175
|
+
|
|
176
|
+
async def housekeeping(dt_now: dt, _cutoff: td = td(days=1)) -> None:
|
|
177
|
+
"""
|
|
178
|
+
Delete all messages from the using the MessageIndex older than a given delta.
|
|
179
|
+
:param dt_now: current timestamp
|
|
180
|
+
:param _cutoff: the oldest timestamp to retain, default is 24 hours ago
|
|
181
|
+
"""
|
|
182
|
+
dtm = dt_now - _cutoff # .isoformat(timespec="microseconds") < needed?
|
|
183
|
+
|
|
184
|
+
self._cu.execute("SELECT dtm FROM messages WHERE dtm => ?", (dtm,))
|
|
185
|
+
rows = self._cu.fetchall()
|
|
186
|
+
|
|
187
|
+
try: # make this operation atomic, i.e. update self._msgs only on success
|
|
188
|
+
await self._lock.acquire()
|
|
189
|
+
self._cu.execute("DELETE FROM messages WHERE dtm < ?", (dtm,))
|
|
190
|
+
msgs = OrderedDict({row[0]: self._msgs[row[0]] for row in rows})
|
|
191
|
+
self._cx.commit()
|
|
192
|
+
|
|
193
|
+
except sqlite3.Error: # need to tighten?
|
|
194
|
+
self._cx.rollback()
|
|
195
|
+
else:
|
|
196
|
+
self._msgs = msgs
|
|
197
|
+
finally:
|
|
198
|
+
self._lock.release()
|
|
199
|
+
|
|
200
|
+
while True:
|
|
201
|
+
self._last_housekeeping = dt.now()
|
|
202
|
+
await asyncio.sleep(3600)
|
|
203
|
+
_LOGGER.info("Starting next MessageIndex housekeeping")
|
|
204
|
+
await housekeeping(self._last_housekeeping)
|
|
205
|
+
|
|
206
|
+
def add(self, msg: Message) -> Message | None:
|
|
207
|
+
"""
|
|
208
|
+
Add a single message to the MessageIndex.
|
|
209
|
+
Logs a warning if there is a duplicate dtm.
|
|
210
|
+
:returns: any message that was removed because it had the same header
|
|
211
|
+
"""
|
|
212
|
+
# TODO: eventually, may be better to use SqlAlchemy
|
|
213
|
+
|
|
214
|
+
dup: tuple[Message, ...] = tuple() # avoid UnboundLocalError
|
|
215
|
+
old: Message | None = None # avoid UnboundLocalError
|
|
216
|
+
|
|
217
|
+
try: # TODO: remove this, or apply only when source is a real packet log?
|
|
218
|
+
# await self._lock.acquire()
|
|
219
|
+
dup = self._delete_from( # HACK: because of contrived pkt logs
|
|
220
|
+
dtm=msg.dtm # stored as such with DTM formatter
|
|
221
|
+
)
|
|
222
|
+
old = self._insert_into(msg) # will delete old msg by hdr (not dtm!)
|
|
223
|
+
|
|
224
|
+
except (
|
|
225
|
+
sqlite3.Error
|
|
226
|
+
): # UNIQUE constraint failed: ? messages.dtm or .hdr (so: HACK)
|
|
227
|
+
self._cx.rollback()
|
|
228
|
+
|
|
229
|
+
else:
|
|
230
|
+
# _msgs dict requires a timestamp reformat
|
|
231
|
+
dtm: DtmStrT = msg.dtm.isoformat(timespec="microseconds") # type: ignore[assignment]
|
|
232
|
+
self._msgs[dtm] = msg
|
|
233
|
+
|
|
234
|
+
finally:
|
|
235
|
+
pass # self._lock.release()
|
|
236
|
+
|
|
237
|
+
if dup:
|
|
238
|
+
_LOGGER.warning(
|
|
239
|
+
"Overwrote dtm (%s) for %s: %s (contrived log?)",
|
|
240
|
+
msg.dtm,
|
|
241
|
+
msg._pkt._hdr,
|
|
242
|
+
dup[0]._pkt,
|
|
243
|
+
)
|
|
244
|
+
if old is not None:
|
|
245
|
+
_LOGGER.info("Old msg replaced: %s", old)
|
|
246
|
+
|
|
247
|
+
return old
|
|
248
|
+
|
|
249
|
+
def add_record(self, src: str, code: str = "", verb: str = "") -> None:
|
|
250
|
+
"""
|
|
251
|
+
Add a single record to the MessageIndex with timestamp now() and no Message contents.
|
|
252
|
+
"""
|
|
253
|
+
# Used by OtbGateway init, via entity_base.py
|
|
254
|
+
dtm: DtmStrT = DtmStrT(dt.strftime(dt.now(), "%Y-%m-%dT%H:%M:%S"))
|
|
255
|
+
hdr = f"{code}|{verb}|{src}|00" # dummy record has no contents
|
|
256
|
+
|
|
257
|
+
dup = self._delete_from(hdr=hdr)
|
|
258
|
+
|
|
259
|
+
sql = """
|
|
260
|
+
INSERT INTO messages (dtm, verb, src, dst, code, ctx, hdr, plk)
|
|
261
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
262
|
+
"""
|
|
263
|
+
try:
|
|
264
|
+
self._cu.execute(
|
|
265
|
+
sql,
|
|
266
|
+
(
|
|
267
|
+
dtm,
|
|
268
|
+
verb,
|
|
269
|
+
src,
|
|
270
|
+
src,
|
|
271
|
+
code,
|
|
272
|
+
None,
|
|
273
|
+
hdr,
|
|
274
|
+
"|",
|
|
275
|
+
),
|
|
276
|
+
)
|
|
277
|
+
except sqlite3.Error:
|
|
278
|
+
self._cx.rollback()
|
|
279
|
+
|
|
280
|
+
if dup: # expected when more than one heat system in schema
|
|
281
|
+
_LOGGER.debug("Replaced record with same hdr: %s", hdr)
|
|
282
|
+
|
|
283
|
+
def _insert_into(self, msg: Message) -> Message | None:
|
|
284
|
+
"""
|
|
285
|
+
Insert a message into the index.
|
|
286
|
+
:returns: any message replaced (by same hdr)
|
|
287
|
+
"""
|
|
288
|
+
assert msg._pkt._hdr is not None, "Skipping: Packet has no hdr: {msg._pkt}"
|
|
289
|
+
|
|
290
|
+
if msg._pkt._ctx is True:
|
|
291
|
+
msg_pkt_ctx = "True"
|
|
292
|
+
elif msg._pkt._ctx is False:
|
|
293
|
+
msg_pkt_ctx = "False"
|
|
294
|
+
else:
|
|
295
|
+
msg_pkt_ctx = msg._pkt._ctx # can be None
|
|
296
|
+
|
|
297
|
+
_old_msgs = self._delete_from(hdr=msg._pkt._hdr)
|
|
298
|
+
|
|
299
|
+
sql = """
|
|
300
|
+
INSERT INTO messages (dtm, verb, src, dst, code, ctx, hdr, plk)
|
|
301
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
self._cu.execute(
|
|
305
|
+
sql,
|
|
306
|
+
(
|
|
307
|
+
msg.dtm,
|
|
308
|
+
str(msg.verb),
|
|
309
|
+
msg.src.id,
|
|
310
|
+
msg.dst.id,
|
|
311
|
+
str(msg.code),
|
|
312
|
+
msg_pkt_ctx,
|
|
313
|
+
msg._pkt._hdr,
|
|
314
|
+
payload_keys(msg.payload),
|
|
315
|
+
),
|
|
316
|
+
)
|
|
317
|
+
_LOGGER.info(f"Added {msg} to gwy.msg_db")
|
|
318
|
+
|
|
319
|
+
return _old_msgs[0] if _old_msgs else None
|
|
320
|
+
|
|
321
|
+
def rem(
|
|
322
|
+
self, msg: Message | None = None, **kwargs: str | dt
|
|
323
|
+
) -> tuple[Message, ...] | None:
|
|
324
|
+
"""Remove a set of message(s) from the index.
|
|
325
|
+
|
|
326
|
+
:returns: any messages that were removed.
|
|
327
|
+
"""
|
|
328
|
+
# _LOGGER.debug(f"SQL REM msg={msg} bool{bool(msg)} kwargs={kwargs} bool(kwargs)")
|
|
329
|
+
# SQL REM
|
|
330
|
+
# msg=|| 02:044328 | | I | heat_demand | FC || {'domain_id': 'FC', 'heat_demand': 0.74}
|
|
331
|
+
# boolTrue
|
|
332
|
+
# kwargs={}
|
|
333
|
+
# bool(kwargs)
|
|
334
|
+
|
|
335
|
+
if not bool(msg) ^ bool(kwargs):
|
|
336
|
+
raise ValueError("Either a Message or kwargs should be provided, not both")
|
|
337
|
+
if msg:
|
|
338
|
+
kwargs["dtm"] = msg.dtm # .isoformat(timespec="microseconds")
|
|
339
|
+
|
|
340
|
+
msgs = None
|
|
341
|
+
try: # make this operation atomic, i.e. update self._msgs only on success
|
|
342
|
+
# await self._lock.acquire()
|
|
343
|
+
msgs = self._delete_from(**kwargs)
|
|
344
|
+
|
|
345
|
+
except sqlite3.Error: # need to tighten?
|
|
346
|
+
self._cx.rollback()
|
|
347
|
+
|
|
348
|
+
else:
|
|
349
|
+
for msg in msgs:
|
|
350
|
+
dtm: DtmStrT = msg.dtm.isoformat(timespec="microseconds") # type: ignore[assignment]
|
|
351
|
+
self._msgs.pop(dtm)
|
|
352
|
+
|
|
353
|
+
finally:
|
|
354
|
+
pass # self._lock.release()
|
|
355
|
+
|
|
356
|
+
return msgs
|
|
357
|
+
|
|
358
|
+
def _delete_from(self, **kwargs: bool | dt | str) -> tuple[Message, ...]:
|
|
359
|
+
"""Remove message(s) from the index.
|
|
360
|
+
:returns: any messages that were removed"""
|
|
361
|
+
|
|
362
|
+
msgs = self._select_from(**kwargs)
|
|
363
|
+
|
|
364
|
+
sql = "DELETE FROM messages WHERE "
|
|
365
|
+
sql += " AND ".join(f"{k} = ?" for k in kwargs)
|
|
366
|
+
|
|
367
|
+
self._cu.execute(sql, tuple(kwargs.values()))
|
|
368
|
+
|
|
369
|
+
return msgs
|
|
370
|
+
|
|
371
|
+
def get(
|
|
372
|
+
self, msg: Message | None = None, **kwargs: bool | dt | str
|
|
373
|
+
) -> tuple[Message, ...]:
|
|
374
|
+
"""Get a set of message(s) from the index."""
|
|
375
|
+
|
|
376
|
+
if not (bool(msg) ^ bool(kwargs)):
|
|
377
|
+
raise ValueError("Either a Message or kwargs should be provided, not both")
|
|
378
|
+
|
|
379
|
+
if msg:
|
|
380
|
+
kwargs["dtm"] = msg.dtm # .isoformat(timespec="microseconds")
|
|
381
|
+
|
|
382
|
+
return self._select_from(**kwargs)
|
|
383
|
+
|
|
384
|
+
def qry_dtms(self, **kwargs: bool | dt | str) -> list[Any]:
|
|
385
|
+
# tweak kwargs as stored in SQLite, inverse from _insert_into():
|
|
386
|
+
kw = {key: value for key, value in kwargs.items() if key != "ctx"}
|
|
387
|
+
if "ctx" in kwargs:
|
|
388
|
+
if isinstance(kwargs["ctx"], str):
|
|
389
|
+
kw["ctx"] = kwargs["ctx"]
|
|
390
|
+
elif kwargs["ctx"]:
|
|
391
|
+
kw["ctx"] = "True"
|
|
392
|
+
else:
|
|
393
|
+
kw["ctx"] = "False"
|
|
394
|
+
|
|
395
|
+
sql = "SELECT dtm FROM messages WHERE "
|
|
396
|
+
sql += " AND ".join(f"{k} = ?" for k in kw)
|
|
397
|
+
|
|
398
|
+
self._cu.execute(sql, tuple(kw.values()))
|
|
399
|
+
return self._cu.fetchall()
|
|
400
|
+
|
|
401
|
+
def contains(self, **kwargs: bool | dt | str) -> bool:
|
|
402
|
+
"""
|
|
403
|
+
Check if the MessageIndex contains at least 1 record that matches the provided fields.
|
|
404
|
+
:param kwargs: (exact) SQLite table field_name: required_value pairs
|
|
405
|
+
:return: True if at least one message fitting the given conditions is present, False when qry returned empty
|
|
406
|
+
"""
|
|
407
|
+
# adapted from _select_from()
|
|
408
|
+
|
|
409
|
+
return len(self.qry_dtms(**kwargs)) > 0
|
|
410
|
+
|
|
411
|
+
def _select_from(self, **kwargs: bool | dt | str) -> tuple[Message, ...]:
|
|
412
|
+
"""Select message(s) using the MessageIndex.
|
|
413
|
+
:param kwargs: (exact) SQLite table field_name: required_value pairs
|
|
414
|
+
:returns: a tuple of qualifying messages"""
|
|
415
|
+
|
|
416
|
+
return tuple(
|
|
417
|
+
self._msgs[row[0].isoformat(timespec="microseconds")]
|
|
418
|
+
for row in self.qry_dtms(**kwargs)
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
def qry(self, sql: str, parameters: tuple[str, ...]) -> tuple[Message, ...]:
|
|
422
|
+
"""Get a tuple of messages from the index, given sql and parameters."""
|
|
423
|
+
|
|
424
|
+
if "SELECT" not in sql:
|
|
425
|
+
raise ValueError(f"{self}: Only SELECT queries are allowed")
|
|
426
|
+
|
|
427
|
+
self._cu.execute(sql, parameters)
|
|
428
|
+
|
|
429
|
+
lst: list[Message] = []
|
|
430
|
+
# stamp = list(self._msgs)[0] if len(self._msgs) > 0 else "N/A" # for debug
|
|
431
|
+
for row in self._cu.fetchall():
|
|
432
|
+
ts: DtmStrT = row[0].isoformat(timespec="microseconds")
|
|
433
|
+
# _LOGGER.debug(
|
|
434
|
+
# f"QRY Msg key raw: {row[0]} Reformatted: {ts} _msgs stamp format: {stamp}"
|
|
435
|
+
# )
|
|
436
|
+
# QRY Msg key raw: 2022-09-08 13:43:31.536862 Reformatted: 2022-09-08T13:43:31.536862
|
|
437
|
+
# _msgs stamp format: 2022-09-08T13:40:52.447364
|
|
438
|
+
if ts in self._msgs:
|
|
439
|
+
lst.append(self._msgs[ts])
|
|
440
|
+
else: # happens in tests with artificial msg from heat
|
|
441
|
+
_LOGGER.warning("MessageIndex ts %s not in device messages", ts)
|
|
442
|
+
return tuple(lst)
|
|
443
|
+
|
|
444
|
+
def qry_field(
|
|
445
|
+
self, sql: str, parameters: tuple[str, ...]
|
|
446
|
+
) -> list[tuple[dt | str, str]]:
|
|
447
|
+
"""
|
|
448
|
+
Get a list of message field values from the index, given sql and parameters.
|
|
449
|
+
"""
|
|
450
|
+
|
|
451
|
+
if "SELECT" not in sql:
|
|
452
|
+
raise ValueError(f"{self}: Only SELECT queries are allowed")
|
|
453
|
+
|
|
454
|
+
self._cu.execute(sql, parameters)
|
|
455
|
+
|
|
456
|
+
return self._cu.fetchall()
|
|
457
|
+
|
|
458
|
+
def all(self, include_expired: bool = False) -> tuple[Message, ...]:
|
|
459
|
+
"""Get all messages from the index."""
|
|
460
|
+
|
|
461
|
+
self._cu.execute("SELECT * FROM messages")
|
|
462
|
+
|
|
463
|
+
lst: list[Message] = []
|
|
464
|
+
# stamp = list(self._msgs)[0] if len(self._msgs) > 0 else "N/A"
|
|
465
|
+
for row in self._cu.fetchall():
|
|
466
|
+
ts: DtmStrT = row[0].isoformat(timespec="microseconds")
|
|
467
|
+
# _LOGGER.debug(
|
|
468
|
+
# f"ALL Msg key raw: {row[0]} Reformatted: {ts} _msgs stamp format: {stamp}"
|
|
469
|
+
# )
|
|
470
|
+
# ALL Msg key raw: 2022-05-02 10:02:02.744905
|
|
471
|
+
# Reformatted: 2022-05-02T10:02:02.744905
|
|
472
|
+
# _msgs stamp format: 2022-05-02T10:02:02.744905
|
|
473
|
+
if ts in self._msgs:
|
|
474
|
+
# if include_expired or not self._msgs[ts].HAS_EXPIRED: # not working
|
|
475
|
+
lst.append(self._msgs[ts])
|
|
476
|
+
else: # happens in tests with dummy msg from heat init
|
|
477
|
+
_LOGGER.warning("MessageIndex ts %s not in device messages", ts)
|
|
478
|
+
return tuple(lst)
|
|
479
|
+
|
|
480
|
+
def clr(self) -> None:
|
|
481
|
+
"""Clear the message index (remove indexes of all messages)."""
|
|
482
|
+
|
|
483
|
+
self._cu.execute("DELETE FROM messages")
|
|
484
|
+
self._cx.commit()
|
|
485
|
+
|
|
486
|
+
self._msgs.clear()
|
|
487
|
+
|
|
488
|
+
# def _msgs(self, device_id: DeviceIdT) -> tuple[Message, ...]:
|
|
489
|
+
# msgs = [msg for msg in self._msgs.values() if msg.src.id == device_id]
|
|
490
|
+
# return msgs
|