ramses-rf 0.53.2__tar.gz → 0.53.4__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.53.2 → ramses_rf-0.53.4}/.github/workflows/check-cov.yml +1 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.pre-commit-config.yaml +5 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/PKG-INFO +1 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/pyproject.toml +1 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_cli/client.py +15 -11
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/database.py +113 -61
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/gateway.py +14 -10
- ramses_rf-0.53.4/ramses_rf/storage.py +168 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/version.py +1 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/gateway.py +20 -16
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/parsers.py +3 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/ramses.py +1 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/transport.py +41 -27
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/version.py +1 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/requirements/requirements_dev.txt +4 -2
- ramses_rf-0.53.4/requirements/requirements_docs.txt +15 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_31da.log +7 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_eavesdrop_schema.py +1 -1
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_schemas.py +7 -13
- ramses_rf-0.53.4/tests/tests/test_storage.py +115 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_systems.py +69 -90
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_cli/test_client.py +5 -4
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_database.py +5 -4
- ramses_rf-0.53.2/requirements/requirements_docs.txt +0 -17
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.github/dependabot.yml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.github/workflows/check-lint.yml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.github/workflows/check-test.yml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.github/workflows/check-type.yml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.github/workflows/publish-hatch.yml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/.gitignore +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/LICENSE +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/README-developers.md +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/README.md +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/client.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/Makefile +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/make.bat +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/_static/CC-BY-NC-SA-4.0.txt +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/_static/ramses_rf_logo.png +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/binding_process.md +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/conf.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/glossary.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/index.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/modules.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/ramses_cli.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/ramses_rf.device.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/ramses_rf.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/ramses_rf.system.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/ramses_tx.rst +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/docs/source/usage.md +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/misc/2411_parser.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/misc/fingerprints.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/misc/ser2net.yaml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/misc/ti_3410/notes.sh +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/misc/ti_3410/ti_3410.fw +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_cli/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_cli/debug.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_cli/discovery.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_cli/py.typed +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_cli/utils/cat_slow.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_cli/utils/convert.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/binding_fsm.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/const.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/device/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/device/base.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/device/heat.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/device/hvac.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/dispatcher.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/entity_base.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/exceptions.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/helpers.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/py.typed +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/schemas.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/system/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/system/faultlog.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/system/heat.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/system/schedule.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_rf/system/zones.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/address.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/command.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/const.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/exceptions.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/fingerprints.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/frame.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/helpers.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/logger.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/message.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/opentherm.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/packet.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/protocol.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/protocol_fsm.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/py.typed +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/schemas.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/typed_dicts.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/ramses_tx/typing.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/requirements/requirements.txt +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/_test_apis_mock.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/_test_mock_faultlog.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/_test_mock_schedule.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/_test_packets_bad.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/_test_performance_WIP.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/_test_state_mgt.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/common.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/mocked_devices/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/mocked_devices/command.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/mocked_devices/const.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/mocked_devices/device_heat.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/mocked_devices/device_hvac.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/deprecated/mocked_devices/transport.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/test_HA_MQTT/test_transport_callback.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/heat/ctl_bdr_91t.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/heat/dts_ctl_sensor.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/heat/hcw_ctl_sensor.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/heat/rnd_ctl_sensor.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/heat/rnd_ctl_sensor.yaml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/heat/trv_ctl.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/co2_fan_itho.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/co2_fan_itho.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/co2_fan_itho.yaml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/dis_fan_orcon.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/dis_fan_orcon.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/rem_fan_climarad.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/rem_fan_nuaire.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/rem_fan_nuaire.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/rem_fan_nuaire.yaml +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/rem_fan_vasco.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/bindings/hvac/rem_fan_ventura.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/devices/device_02.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/devices/device_04.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/devices/device_10.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/devices/device_13.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/devices/device_22.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_dev_class/hvac/known_list_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_dev_class/hvac/known_list_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_dev_class/hvac/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_trv_actuator_long/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_trv_actuator_long/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_trv_actuator_long/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_trv_actuator_mixed/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_trv_actuator_mixed/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_trv_actuator_mixed/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_ufh_circuits/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_ufh_circuits/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/_ufh_circuits/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/app_cntrl/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/app_cntrl/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/app_cntrl/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/trv_actuators/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/trv_actuators/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/trv_actuators/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_000/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_000/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_000/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_001/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_001/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_001/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_002/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_002/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_002/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_003/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_003/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_003/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_004/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_004/schema_eavesdrop_off.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/eavesdrop_schema/zone_sensors_004/schema_eavesdrop_on.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/10e0_xxxx.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/_gather.sh +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/01_EvoTouch_Colour.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/01_Evo_Color.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/01_IONA_RAI_Prototype.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/02_HCE80_V3.10_061117..log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/04_HR92 Radiator Ctrl_.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/08_Jasper_EIM.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/10_R8810A_Bridge.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/10_R8820.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/30_Internet_Gateway.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/31_Jasper_Stat_TXXX.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/heat/34_T87RF2025.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/18_BRDG-02A55.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/18_HRA82.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/20.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/21_CCU-12T20.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMC-07RP01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMC-15RP01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMC-17RP01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMN-07LM01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMN-15LF01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMN-17LMP01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMS-15C16.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/29_VMS-17HB01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/30_BRDG-02EM23.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/30_BRDG-02JAS01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMC-15RPS34.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMD-15RMS64.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMD-15RMS86.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMD-17RPS01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMN-23LM33.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMN-23LMH23.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMS-15CM17.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMS-23C33.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMS-23HB33.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/32_VMZ-15V13.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/37_VMD-07RPS13.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/37_VMI-15MC01log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/37_VMI-15WSJ53.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/37_VMS-02J52.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/37_VMS-12C39.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/99_CVE-RF.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/fingerprints/hvac/99_VMS-17C01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/helpers.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/logger/packet_in.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/logger/packet_out.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/logs/pkts_bad_000.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/logs/pkts_tba_000.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/logs/system_cache.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parser_helpers/pkt_addr_set.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parser_helpers/pkt_dev_class.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0001_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0002.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0004_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0005.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0006.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0008.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0009.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_000a.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_000c.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_000e.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_01ff_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_0418.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_042f.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1030.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1060.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_10d0.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_10e0.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1260.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1298.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_12a0.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_12c0.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1300.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1f09.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1fc9.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_1fd4.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_2210.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22c9.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22d0.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22d9.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22e0.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22e5.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22e9.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22f1.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22f2.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22f3.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22f4.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_22f7.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_2309.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_2349.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_2411_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_2e04.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_2e10_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_30c9.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3110_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3120.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_313e_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3150.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_31d9.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3200.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3210.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3220.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3222.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3ef0_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_3ef1_wip.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_4e01.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_4e02.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_4e04.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/parsers/code_4e15.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schedules/_sched_002/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schedules/_sched_002/schedule.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schedules/sched_001/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schedules/sched_001/schedule.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schedules/sched_dhw/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schedules/sched_dhw/schedule.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/jsn_files/schema_100.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/jsn_files/schema_101.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/jsn_files/schema_102.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/jsn_files/schema_103.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/jsn_files/schema_104.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/jsn_files/schema_105.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/jsn_files/schema_108.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_000.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_000.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_001.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_001.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_002.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_002.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_010.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_010.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_011.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_011.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_012.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_012.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_013.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_013.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_014.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_014.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_300.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_300.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_301.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_301.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_302.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_302.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_303.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_303.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_304.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_304.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_310.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/schemas/log_files/schema_310.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_heat_trv_00/config.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_heat_trv_00/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_heat_trv_00/schema.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_hvac_nuaire/config.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_hvac_nuaire/known_list.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_hvac_nuaire/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_hvac_nuaire/schema.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/_hvac_nuaire/status.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_otb_00/config.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_otb_00/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_otb_00/schema.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_simple/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_simple/schema.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_ufc_00/config.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_ufc_00/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_ufc_01/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_zxdavb/config.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_zxdavb/known_list.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_zxdavb/packet.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/systems/heat_zxdavb/schema.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_api_faultlog.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_api_schedule.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_apis_binding.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_apis_common.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_apis_heat.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_apis_hvac.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_cli_transport_factory.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_devices.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_eavesdrop_dev_class.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_helpers.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_parser_helpers.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_parsers.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_ramses_schema.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_schema_bits.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests/test_vol_schemas.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_cli/test_cli_utility.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_cli/test_debug.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_cli/test_discovery.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/configs/config_heat.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/configs/config_hvac.json +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/conftest.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/device/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/device/test_hvac_ventilator.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/logs/test_api_faultlog.log +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_api_faultlog.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_api_schedule.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_binding_fsm.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_create_stack.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_dispatcher.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_entity_base.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_hgi_behaviors.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_protocol_fsm.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_use_regex.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_virt_network.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/test_virtual_rf.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/virtual_rf/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/virtual_rf/const.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/virtual_rf/helpers.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_rf/virtual_rf/virtual_rf.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_tx/__init__.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_tx/test_command.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/tests_tx/test_const.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/wip/_test_eavesdrop_dhw_sensor.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/wip/_test_eavesdrop_htg_control.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/wip/_test_eavesdrop_ufc_circuits.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/wip/_test_eavesdrop_zone_sensors.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/wip/_test_eavesdrop_zone_type.py +0 -0
- {ramses_rf-0.53.2 → ramses_rf-0.53.4}/tests/wip/test_wip_cli.sh +0 -0
|
@@ -14,7 +14,7 @@ repos:
|
|
|
14
14
|
# Run `python-typing-update` hook manually from time to time
|
|
15
15
|
# to update python typing syntax.
|
|
16
16
|
# Will require manual work, before submitting changes!
|
|
17
|
-
#
|
|
17
|
+
# prek run --hook-stage manual python-typing-update --all-files
|
|
18
18
|
- id: python-typing-update
|
|
19
19
|
stages: [manual]
|
|
20
20
|
args:
|
|
@@ -39,6 +39,10 @@ repos:
|
|
|
39
39
|
hooks:
|
|
40
40
|
- id: check-executables-have-shebangs
|
|
41
41
|
# id: check-json # don't enable this one
|
|
42
|
+
# - id: no-commit-to-branch
|
|
43
|
+
# args:
|
|
44
|
+
# - --branch=master
|
|
45
|
+
# - --branch=stable
|
|
42
46
|
- id: check-toml
|
|
43
47
|
- id: check-yaml
|
|
44
48
|
- id: debug-statements
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ramses_rf
|
|
3
|
-
Version: 0.53.
|
|
3
|
+
Version: 0.53.4
|
|
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
|
|
@@ -471,13 +471,8 @@ def print_results(gwy: Gateway, **kwargs: Any) -> None:
|
|
|
471
471
|
system_id, _ = kwargs[GET_SCHED]
|
|
472
472
|
|
|
473
473
|
|
|
474
|
-
def
|
|
475
|
-
"""
|
|
476
|
-
|
|
477
|
-
:param gwy: The gateway instance.
|
|
478
|
-
"""
|
|
479
|
-
schema, msgs = gwy.get_state()
|
|
480
|
-
|
|
474
|
+
def _write_state(schema: dict[str, Any], msgs: dict[str, str]) -> None:
|
|
475
|
+
"""Write the state to the file system (blocking)."""
|
|
481
476
|
with open("state_msgs.log", "w") as f:
|
|
482
477
|
[f.write(f"{dtm} {pkt}\r\n") for dtm, pkt in msgs.items()] # if not m._expired
|
|
483
478
|
|
|
@@ -485,13 +480,22 @@ def _save_state(gwy: Gateway) -> None:
|
|
|
485
480
|
f.write(json.dumps(schema, indent=4))
|
|
486
481
|
|
|
487
482
|
|
|
488
|
-
def
|
|
483
|
+
async def _save_state(gwy: Gateway) -> None:
|
|
484
|
+
"""Save the gateway state to files.
|
|
485
|
+
|
|
486
|
+
:param gwy: The gateway instance.
|
|
487
|
+
"""
|
|
488
|
+
schema, msgs = await gwy.get_state()
|
|
489
|
+
await asyncio.to_thread(_write_state, schema, msgs)
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
async def _print_engine_state(gwy: Gateway, **kwargs: Any) -> None:
|
|
489
493
|
"""Print the current engine state (schema and packets).
|
|
490
494
|
|
|
491
495
|
:param gwy: The gateway instance.
|
|
492
496
|
:param kwargs: Command arguments to determine verbosity.
|
|
493
497
|
"""
|
|
494
|
-
(schema, packets) = gwy.get_state(include_expired=True)
|
|
498
|
+
(schema, packets) = await gwy.get_state(include_expired=True)
|
|
495
499
|
|
|
496
500
|
if kwargs["print_state"] > 0:
|
|
497
501
|
print(f"schema: {json.dumps(schema, indent=4)}\r\n")
|
|
@@ -671,10 +675,10 @@ async def async_main(command: str, lib_kwargs: dict[str, Any], **kwargs: Any) ->
|
|
|
671
675
|
print(f"\r\nclient.py: Engine stopped: {msg}")
|
|
672
676
|
|
|
673
677
|
# if kwargs["save_state"]:
|
|
674
|
-
# _save_state(gwy)
|
|
678
|
+
# await _save_state(gwy)
|
|
675
679
|
|
|
676
680
|
if kwargs["print_state"]:
|
|
677
|
-
_print_engine_state(gwy, **kwargs)
|
|
681
|
+
await _print_engine_state(gwy, **kwargs)
|
|
678
682
|
|
|
679
683
|
elif command == EXECUTE:
|
|
680
684
|
print_results(gwy, **kwargs)
|
|
@@ -24,14 +24,19 @@ RAMSES RF - Message database and index.
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
26
|
import asyncio
|
|
27
|
+
import contextlib
|
|
27
28
|
import logging
|
|
29
|
+
import os
|
|
28
30
|
import sqlite3
|
|
31
|
+
import uuid
|
|
29
32
|
from collections import OrderedDict
|
|
30
33
|
from datetime import datetime as dt, timedelta as td
|
|
31
34
|
from typing import TYPE_CHECKING, Any, NewType
|
|
32
35
|
|
|
33
36
|
from ramses_tx import CODES_SCHEMA, RQ, Code, Message, Packet
|
|
34
37
|
|
|
38
|
+
from .storage import StorageWorker
|
|
39
|
+
|
|
35
40
|
if TYPE_CHECKING:
|
|
36
41
|
DtmStrT = NewType("DtmStrT", str)
|
|
37
42
|
MsgDdT = OrderedDict[DtmStrT, Message]
|
|
@@ -89,22 +94,55 @@ class MessageIndex:
|
|
|
89
94
|
|
|
90
95
|
_housekeeping_task: asyncio.Task[None]
|
|
91
96
|
|
|
92
|
-
def __init__(self, maintain: bool = True) -> None:
|
|
97
|
+
def __init__(self, maintain: bool = True, db_path: str = ":memory:") -> None:
|
|
93
98
|
"""Instantiate a message database/index."""
|
|
94
99
|
|
|
95
100
|
self.maintain = maintain
|
|
96
101
|
self._msgs: MsgDdT = OrderedDict() # stores all messages for retrieval.
|
|
97
102
|
# Filled & cleaned up in housekeeping_loop.
|
|
98
103
|
|
|
99
|
-
#
|
|
104
|
+
# For :memory: databases with multiple connections (Reader vs Worker)
|
|
105
|
+
# We must use a Shared Cache URI so both threads see the same data.
|
|
106
|
+
if db_path == ":memory:":
|
|
107
|
+
# Unique ID ensures parallel tests don't share the same in-memory DB
|
|
108
|
+
db_path = f"file:ramses_rf_{uuid.uuid4()}?mode=memory&cache=shared"
|
|
109
|
+
|
|
110
|
+
# Start the Storage Worker (Write Connection)
|
|
111
|
+
# This thread handles all blocking INSERT/UPDATE operations
|
|
112
|
+
self._worker = StorageWorker(db_path)
|
|
113
|
+
|
|
114
|
+
# Wait for the worker to create the tables.
|
|
115
|
+
# This prevents "no such table" errors on immediate reads.
|
|
116
|
+
if not self._worker.wait_for_ready(timeout=10.0):
|
|
117
|
+
_LOGGER.error("MessageIndex: StorageWorker timed out initializing database")
|
|
118
|
+
|
|
119
|
+
# Connect to a SQLite DB (Read Connection)
|
|
100
120
|
self._cx = sqlite3.connect(
|
|
101
|
-
|
|
121
|
+
db_path,
|
|
122
|
+
detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES,
|
|
123
|
+
check_same_thread=False,
|
|
124
|
+
uri=True, # Enable URI parsing for shared memory support
|
|
125
|
+
timeout=10.0, # Increased timeout to reduce 'database locked' errors
|
|
126
|
+
isolation_level=None, # Autocommit mode prevents stale snapshots
|
|
102
127
|
)
|
|
128
|
+
|
|
129
|
+
# Enable Write-Ahead Logging for Reader as well
|
|
130
|
+
if db_path != ":memory:" and "mode=memory" not in db_path:
|
|
131
|
+
with contextlib.suppress(sqlite3.Error):
|
|
132
|
+
self._cx.execute("PRAGMA journal_mode=WAL")
|
|
133
|
+
elif "cache=shared" in db_path:
|
|
134
|
+
# Shared cache (used in tests) requires read_uncommitted to prevent
|
|
135
|
+
# readers from blocking writers (Table Locking).
|
|
136
|
+
with contextlib.suppress(sqlite3.Error):
|
|
137
|
+
self._cx.execute("PRAGMA read_uncommitted = true")
|
|
138
|
+
|
|
103
139
|
# detect_types should retain dt type on store/retrieve
|
|
104
140
|
self._cu = self._cx.cursor() # Create a cursor
|
|
105
141
|
|
|
106
142
|
_setup_db_adapters() # DTM adapter/converter
|
|
107
|
-
|
|
143
|
+
|
|
144
|
+
# Schema creation is now handled safely by the StorageWorker to avoid races.
|
|
145
|
+
# self._setup_db_schema()
|
|
108
146
|
|
|
109
147
|
if self.maintain:
|
|
110
148
|
self._lock = asyncio.Lock()
|
|
@@ -137,6 +175,7 @@ class MessageIndex:
|
|
|
137
175
|
):
|
|
138
176
|
self._housekeeping_task.cancel() # stop the housekeeper
|
|
139
177
|
|
|
178
|
+
self._worker.stop() # Stop the background thread
|
|
140
179
|
self._cx.commit() # just in case
|
|
141
180
|
self._cx.close() # may still need to do queries after engine has stopped?
|
|
142
181
|
|
|
@@ -145,6 +184,13 @@ class MessageIndex:
|
|
|
145
184
|
"""Return the messages in the index in a threadsafe way."""
|
|
146
185
|
return self._msgs
|
|
147
186
|
|
|
187
|
+
def flush(self) -> None:
|
|
188
|
+
"""Flush the storage worker queue.
|
|
189
|
+
|
|
190
|
+
This is primarily for testing to ensure data persistence before querying.
|
|
191
|
+
"""
|
|
192
|
+
self._worker.flush()
|
|
193
|
+
|
|
148
194
|
def _setup_db_schema(self) -> None:
|
|
149
195
|
"""Set up the message database schema.
|
|
150
196
|
|
|
@@ -236,23 +282,30 @@ class MessageIndex:
|
|
|
236
282
|
dup: tuple[Message, ...] = tuple() # avoid UnboundLocalError
|
|
237
283
|
old: Message | None = None # avoid UnboundLocalError
|
|
238
284
|
|
|
285
|
+
# Check in-memory cache for collision instead of blocking SQL
|
|
286
|
+
dtm_str: DtmStrT = msg.dtm.isoformat(timespec="microseconds") # type: ignore[assignment]
|
|
287
|
+
if dtm_str in self._msgs:
|
|
288
|
+
dup = (self._msgs[dtm_str],)
|
|
289
|
+
|
|
239
290
|
try: # TODO: remove this, or apply only when source is a real packet log?
|
|
240
291
|
# await self._lock.acquire()
|
|
241
|
-
dup = self._delete_from( # HACK: because of contrived pkt logs
|
|
242
|
-
|
|
243
|
-
)
|
|
244
|
-
|
|
292
|
+
# dup = self._delete_from( # HACK: because of contrived pkt logs
|
|
293
|
+
# dtm=msg.dtm # stored as such with DTM formatter
|
|
294
|
+
# )
|
|
295
|
+
# We defer the write to the worker; return value (old) is not available synchronously
|
|
296
|
+
self._insert_into(msg) # will delete old msg by hdr (not dtm!)
|
|
245
297
|
|
|
246
298
|
except (
|
|
247
299
|
sqlite3.Error
|
|
248
300
|
): # UNIQUE constraint failed: ? messages.dtm or .hdr (so: HACK)
|
|
249
|
-
self._cx.rollback()
|
|
301
|
+
# self._cx.rollback()
|
|
302
|
+
pass
|
|
250
303
|
|
|
251
304
|
else:
|
|
252
305
|
# _msgs dict requires a timestamp reformat
|
|
253
|
-
dtm: DtmStrT = msg.dtm.isoformat(timespec="microseconds")
|
|
306
|
+
# dtm: DtmStrT = msg.dtm.isoformat(timespec="microseconds")
|
|
254
307
|
# add msg to self._msgs dict
|
|
255
|
-
self._msgs[
|
|
308
|
+
self._msgs[dtm_str] = msg
|
|
256
309
|
|
|
257
310
|
finally:
|
|
258
311
|
pass # self._lock.release()
|
|
@@ -288,39 +341,36 @@ class MessageIndex:
|
|
|
288
341
|
dtm: DtmStrT = _now.isoformat(timespec="microseconds") # type: ignore[assignment]
|
|
289
342
|
hdr = f"{code}|{verb}|{src}|{payload}"
|
|
290
343
|
|
|
291
|
-
dup = self._delete_from(hdr=hdr)
|
|
344
|
+
# dup = self._delete_from(hdr=hdr)
|
|
345
|
+
# Avoid blocking read; worker handles REPLACE on unique constraint collision
|
|
346
|
+
|
|
347
|
+
# Prepare data tuple for worker
|
|
348
|
+
data = (
|
|
349
|
+
_now,
|
|
350
|
+
verb,
|
|
351
|
+
src,
|
|
352
|
+
src,
|
|
353
|
+
code,
|
|
354
|
+
None,
|
|
355
|
+
hdr,
|
|
356
|
+
"|",
|
|
357
|
+
)
|
|
292
358
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
self.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
code,
|
|
306
|
-
None,
|
|
307
|
-
hdr,
|
|
308
|
-
"|",
|
|
309
|
-
),
|
|
310
|
-
)
|
|
311
|
-
except sqlite3.Error:
|
|
312
|
-
self._cx.rollback()
|
|
313
|
-
else:
|
|
314
|
-
# also add dummy 3220 msg to self._msgs dict to allow maintenance loop
|
|
315
|
-
msg: Message = Message._from_pkt(
|
|
316
|
-
Packet(
|
|
317
|
-
_now, f"... {verb} --- {src} --:------ {src} {code} 005 0000000000"
|
|
318
|
-
)
|
|
319
|
-
)
|
|
320
|
-
self._msgs[dtm] = msg
|
|
359
|
+
self._worker.submit_packet(data)
|
|
360
|
+
|
|
361
|
+
# Backward compatibility for Tests:
|
|
362
|
+
# Check specific env var set by pytest, which is more reliable than sys.modules
|
|
363
|
+
if "PYTEST_CURRENT_TEST" in os.environ:
|
|
364
|
+
self.flush()
|
|
365
|
+
|
|
366
|
+
# also add dummy 3220 msg to self._msgs dict to allow maintenance loop
|
|
367
|
+
msg: Message = Message._from_pkt(
|
|
368
|
+
Packet(_now, f"... {verb} --- {src} --:------ {src} {code} 005 0000000000")
|
|
369
|
+
)
|
|
370
|
+
self._msgs[dtm] = msg
|
|
321
371
|
|
|
322
|
-
if dup: # expected when more than one heat system in schema
|
|
323
|
-
|
|
372
|
+
# if dup: # expected when more than one heat system in schema
|
|
373
|
+
# _LOGGER.debug("Replaced record with same hdr: %s", hdr)
|
|
324
374
|
|
|
325
375
|
def _insert_into(self, msg: Message) -> Message | None:
|
|
326
376
|
"""
|
|
@@ -337,29 +387,31 @@ class MessageIndex:
|
|
|
337
387
|
else:
|
|
338
388
|
msg_pkt_ctx = msg._pkt._ctx # can be None
|
|
339
389
|
|
|
340
|
-
_old_msgs = self._delete_from(hdr=msg._pkt._hdr)
|
|
390
|
+
# _old_msgs = self._delete_from(hdr=msg._pkt._hdr)
|
|
391
|
+
# Refactor: Worker uses INSERT OR REPLACE to handle collision
|
|
392
|
+
|
|
393
|
+
data = (
|
|
394
|
+
msg.dtm,
|
|
395
|
+
str(msg.verb),
|
|
396
|
+
msg.src.id,
|
|
397
|
+
msg.dst.id,
|
|
398
|
+
str(msg.code),
|
|
399
|
+
msg_pkt_ctx,
|
|
400
|
+
msg._pkt._hdr,
|
|
401
|
+
payload_keys(msg.payload),
|
|
402
|
+
)
|
|
341
403
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
404
|
+
self._worker.submit_packet(data)
|
|
405
|
+
|
|
406
|
+
# Backward compatibility for Tests:
|
|
407
|
+
# Tests assume the DB update is instant. If running in pytest, flush immediately.
|
|
408
|
+
# This effectively makes the operation synchronous during tests to avoid rewriting tests.
|
|
409
|
+
if "PYTEST_CURRENT_TEST" in os.environ:
|
|
410
|
+
self.flush()
|
|
346
411
|
|
|
347
|
-
self._cu.execute(
|
|
348
|
-
sql,
|
|
349
|
-
(
|
|
350
|
-
msg.dtm,
|
|
351
|
-
str(msg.verb),
|
|
352
|
-
msg.src.id,
|
|
353
|
-
msg.dst.id,
|
|
354
|
-
str(msg.code),
|
|
355
|
-
msg_pkt_ctx,
|
|
356
|
-
msg._pkt._hdr,
|
|
357
|
-
payload_keys(msg.payload),
|
|
358
|
-
),
|
|
359
|
-
)
|
|
360
412
|
# _LOGGER.debug(f"Added {msg} to gwy.msg_db")
|
|
361
413
|
|
|
362
|
-
return
|
|
414
|
+
return None
|
|
363
415
|
|
|
364
416
|
def rem(
|
|
365
417
|
self, msg: Message | None = None, **kwargs: str | dt
|
|
@@ -267,12 +267,14 @@ class Gateway(Engine):
|
|
|
267
267
|
:returns: None
|
|
268
268
|
:rtype: None
|
|
269
269
|
"""
|
|
270
|
+
# Stop the Engine first to ensure no tasks/callbacks try to write
|
|
271
|
+
# to the DB while we are closing it.
|
|
272
|
+
await super().stop()
|
|
270
273
|
|
|
271
274
|
if self.msg_db:
|
|
272
275
|
self.msg_db.stop()
|
|
273
|
-
await super().stop()
|
|
274
276
|
|
|
275
|
-
def _pause(self, *args: Any) -> None:
|
|
277
|
+
async def _pause(self, *args: Any) -> None:
|
|
276
278
|
"""Pause the (unpaused) gateway (disables sending/discovery).
|
|
277
279
|
|
|
278
280
|
There is the option to save other objects, as `args`.
|
|
@@ -288,12 +290,12 @@ class Gateway(Engine):
|
|
|
288
290
|
self.config.disable_discovery, disc_flag = True, self.config.disable_discovery
|
|
289
291
|
|
|
290
292
|
try:
|
|
291
|
-
super()._pause(disc_flag, *args)
|
|
293
|
+
await super()._pause(disc_flag, *args)
|
|
292
294
|
except RuntimeError:
|
|
293
295
|
self.config.disable_discovery = disc_flag
|
|
294
296
|
raise
|
|
295
297
|
|
|
296
|
-
def _resume(self) -> tuple[Any]:
|
|
298
|
+
async def _resume(self) -> tuple[Any]:
|
|
297
299
|
"""Resume the (paused) gateway (enables sending/discovery, if applicable).
|
|
298
300
|
|
|
299
301
|
Will restore other objects, as `args`.
|
|
@@ -305,11 +307,13 @@ class Gateway(Engine):
|
|
|
305
307
|
|
|
306
308
|
_LOGGER.debug("Gateway: Resuming engine...")
|
|
307
309
|
|
|
308
|
-
|
|
310
|
+
# args_tuple = await super()._resume()
|
|
311
|
+
# self.config.disable_discovery, *args = args_tuple # type: ignore[assignment]
|
|
312
|
+
self.config.disable_discovery, *args = await super()._resume() # type: ignore[assignment]
|
|
309
313
|
|
|
310
314
|
return args
|
|
311
315
|
|
|
312
|
-
def get_state(
|
|
316
|
+
async def get_state(
|
|
313
317
|
self, include_expired: bool = False
|
|
314
318
|
) -> tuple[dict[str, Any], dict[str, str]]:
|
|
315
319
|
"""Return the current schema & state (may include expired packets).
|
|
@@ -320,7 +324,7 @@ class Gateway(Engine):
|
|
|
320
324
|
:rtype: tuple[dict[str, Any], dict[str, str]]
|
|
321
325
|
"""
|
|
322
326
|
|
|
323
|
-
self._pause()
|
|
327
|
+
await self._pause()
|
|
324
328
|
|
|
325
329
|
def wanted_msg(msg: Message, include_expired: bool = False) -> bool:
|
|
326
330
|
if msg.code == Code._313F:
|
|
@@ -357,7 +361,7 @@ class Gateway(Engine):
|
|
|
357
361
|
}
|
|
358
362
|
# _LOGGER.warning("Missing MessageIndex")
|
|
359
363
|
|
|
360
|
-
self._resume()
|
|
364
|
+
await self._resume()
|
|
361
365
|
|
|
362
366
|
return self.schema, dict(sorted(pkts.items()))
|
|
363
367
|
|
|
@@ -392,7 +396,7 @@ class Gateway(Engine):
|
|
|
392
396
|
tmp_transport: RamsesTransportT # mypy hint
|
|
393
397
|
|
|
394
398
|
_LOGGER.debug("Gateway: Restoring a cached packet log...")
|
|
395
|
-
self._pause()
|
|
399
|
+
await self._pause()
|
|
396
400
|
|
|
397
401
|
if _clear_state: # only intended for test suite use
|
|
398
402
|
clear_state()
|
|
@@ -428,7 +432,7 @@ class Gateway(Engine):
|
|
|
428
432
|
await tmp_transport.get_extra_info(SZ_READER_TASK)
|
|
429
433
|
|
|
430
434
|
_LOGGER.debug("Gateway: Restored, resuming")
|
|
431
|
-
self._resume()
|
|
435
|
+
await self._resume()
|
|
432
436
|
|
|
433
437
|
def _add_device(self, dev: Device) -> None: # TODO: also: _add_system()
|
|
434
438
|
"""Add a device to the gateway (called by devices during instantiation).
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""RAMSES RF - Background storage worker for async I/O."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
import logging
|
|
7
|
+
import queue
|
|
8
|
+
import sqlite3
|
|
9
|
+
import threading
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
_LOGGER = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class StorageWorker:
|
|
16
|
+
"""A background worker thread to handle blocking storage I/O asynchronously."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, db_path: str = ":memory:"):
|
|
19
|
+
"""Initialize the storage worker thread."""
|
|
20
|
+
self._db_path = db_path
|
|
21
|
+
self._queue: queue.SimpleQueue[tuple[str, Any] | None] = queue.SimpleQueue()
|
|
22
|
+
self._ready_event = threading.Event()
|
|
23
|
+
|
|
24
|
+
self._thread = threading.Thread(
|
|
25
|
+
target=self._run,
|
|
26
|
+
name="RamsesStorage",
|
|
27
|
+
daemon=True, # FIX: Set to True so the process can exit even if stop() is missed
|
|
28
|
+
)
|
|
29
|
+
self._thread.start()
|
|
30
|
+
|
|
31
|
+
def wait_for_ready(self, timeout: float | None = None) -> bool:
|
|
32
|
+
"""Wait until the database is initialized and ready."""
|
|
33
|
+
return self._ready_event.wait(timeout)
|
|
34
|
+
|
|
35
|
+
def submit_packet(self, packet_data: tuple[Any, ...]) -> None:
|
|
36
|
+
"""Submit a packet tuple for SQL insertion (Non-blocking)."""
|
|
37
|
+
self._queue.put(("SQL", packet_data))
|
|
38
|
+
|
|
39
|
+
def flush(self, timeout: float = 10.0) -> None:
|
|
40
|
+
"""Block until all currently pending tasks are processed."""
|
|
41
|
+
# REMOVED: if self._queue.empty(): return
|
|
42
|
+
# This check caused a race condition where flush() returned before
|
|
43
|
+
# the worker finished committing the last item it just popped.
|
|
44
|
+
|
|
45
|
+
# We inject a special marker into the queue
|
|
46
|
+
sentinel = threading.Event()
|
|
47
|
+
self._queue.put(("MARKER", sentinel))
|
|
48
|
+
|
|
49
|
+
# Wait for the worker to set the sentinel
|
|
50
|
+
if not sentinel.wait(timeout):
|
|
51
|
+
_LOGGER.warning("StorageWorker flush timed out")
|
|
52
|
+
|
|
53
|
+
def stop(self) -> None:
|
|
54
|
+
"""Signal the worker to stop processing and close resources."""
|
|
55
|
+
self._queue.put(None) # Poison pill
|
|
56
|
+
self._thread.join()
|
|
57
|
+
|
|
58
|
+
def _init_db(self, conn: sqlite3.Connection) -> None:
|
|
59
|
+
"""Initialize the database schema."""
|
|
60
|
+
cursor = conn.cursor()
|
|
61
|
+
cursor.execute(
|
|
62
|
+
"""
|
|
63
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
64
|
+
dtm DTM NOT NULL PRIMARY KEY,
|
|
65
|
+
verb TEXT(2) NOT NULL,
|
|
66
|
+
src TEXT(12) NOT NULL,
|
|
67
|
+
dst TEXT(12) NOT NULL,
|
|
68
|
+
code TEXT(4) NOT NULL,
|
|
69
|
+
ctx TEXT,
|
|
70
|
+
hdr TEXT NOT NULL UNIQUE,
|
|
71
|
+
plk TEXT NOT NULL
|
|
72
|
+
)
|
|
73
|
+
"""
|
|
74
|
+
)
|
|
75
|
+
# Create indexes to speed up future reads
|
|
76
|
+
for col in ("verb", "src", "dst", "code", "ctx", "hdr"):
|
|
77
|
+
cursor.execute(f"CREATE INDEX IF NOT EXISTS idx_{col} ON messages ({col})")
|
|
78
|
+
conn.commit()
|
|
79
|
+
|
|
80
|
+
def _run(self) -> None:
|
|
81
|
+
"""The main loop running in the background thread."""
|
|
82
|
+
_LOGGER.debug("StorageWorker thread started.")
|
|
83
|
+
|
|
84
|
+
# Setup SQLite connection in this thread
|
|
85
|
+
try:
|
|
86
|
+
# uri=True allows opening "file::memory:?cache=shared"
|
|
87
|
+
conn = sqlite3.connect(
|
|
88
|
+
self._db_path,
|
|
89
|
+
detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES,
|
|
90
|
+
check_same_thread=False,
|
|
91
|
+
uri=True,
|
|
92
|
+
timeout=10.0, # Increased timeout for locking
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Enable Write-Ahead Logging for concurrency
|
|
96
|
+
if self._db_path != ":memory:" and "mode=memory" not in self._db_path:
|
|
97
|
+
with contextlib.suppress(sqlite3.Error):
|
|
98
|
+
conn.execute("PRAGMA journal_mode=WAL")
|
|
99
|
+
conn.execute("PRAGMA synchronous=NORMAL")
|
|
100
|
+
elif "cache=shared" in self._db_path:
|
|
101
|
+
with contextlib.suppress(sqlite3.Error):
|
|
102
|
+
conn.execute("PRAGMA read_uncommitted = true")
|
|
103
|
+
|
|
104
|
+
self._init_db(conn)
|
|
105
|
+
self._ready_event.set() # Signal that tables exist
|
|
106
|
+
except sqlite3.Error as exc:
|
|
107
|
+
_LOGGER.error("Failed to initialize storage database: %s", exc)
|
|
108
|
+
self._ready_event.set() # Avoid blocking waiters forever
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
while True:
|
|
112
|
+
try:
|
|
113
|
+
# Block here waiting for work
|
|
114
|
+
item = self._queue.get()
|
|
115
|
+
|
|
116
|
+
if item is None: # Shutdown signal
|
|
117
|
+
break
|
|
118
|
+
|
|
119
|
+
task_type, data = item
|
|
120
|
+
|
|
121
|
+
if task_type == "MARKER":
|
|
122
|
+
# Flush requested
|
|
123
|
+
data.set()
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
if task_type == "SQL":
|
|
127
|
+
# Optimization: Batch processing
|
|
128
|
+
batch = [data]
|
|
129
|
+
# Drain queue of pending SQL tasks to bulk insert
|
|
130
|
+
while not self._queue.empty():
|
|
131
|
+
try:
|
|
132
|
+
# Peek/get next item without blocking
|
|
133
|
+
next_item = self._queue.get_nowait()
|
|
134
|
+
if next_item is None:
|
|
135
|
+
self._queue.put(None) # Re-queue poison pill
|
|
136
|
+
break
|
|
137
|
+
|
|
138
|
+
next_type, next_data = next_item
|
|
139
|
+
if next_type == "SQL":
|
|
140
|
+
batch.append(next_data)
|
|
141
|
+
elif next_type == "MARKER":
|
|
142
|
+
# Handle marker after this batch
|
|
143
|
+
self._queue.put(next_item) # Re-queue marker
|
|
144
|
+
break
|
|
145
|
+
else:
|
|
146
|
+
pass
|
|
147
|
+
except queue.Empty:
|
|
148
|
+
break
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
conn.executemany(
|
|
152
|
+
"""
|
|
153
|
+
INSERT OR REPLACE INTO messages
|
|
154
|
+
(dtm, verb, src, dst, code, ctx, hdr, plk)
|
|
155
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
156
|
+
""",
|
|
157
|
+
batch,
|
|
158
|
+
)
|
|
159
|
+
conn.commit()
|
|
160
|
+
except sqlite3.Error as err:
|
|
161
|
+
_LOGGER.error("SQL Write Failed: %s", err)
|
|
162
|
+
|
|
163
|
+
except Exception as err:
|
|
164
|
+
_LOGGER.exception("StorageWorker encountered an error: %s", err)
|
|
165
|
+
|
|
166
|
+
# Cleanup
|
|
167
|
+
conn.close()
|
|
168
|
+
_LOGGER.debug("StorageWorker thread stopped.")
|