conson-xp 1.6.0__tar.gz → 1.8.0__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.
- {conson_xp-1.6.0 → conson_xp-1.8.0}/PKG-INFO +1 -1
- {conson_xp-1.6.0 → conson_xp-1.8.0}/pyproject.toml +1 -1
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/__init__.py +1 -1
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +11 -2
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/input_action_type.py +2 -2
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +13 -25
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +25 -39
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +4 -21
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/actiontable_service.py +6 -2
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +44 -9
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/conbus_protocol.py +0 -2
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/base_server_service.py +19 -30
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/server_service.py +1 -8
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_service.py +4 -1
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/dependencies.py +6 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_xp20_action_table_integration.py +4 -12
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_xp24_action_table_integration.py +2 -2
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +82 -19
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +12 -14
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp24_action_table_service.py +4 -3
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +12 -14
- {conson_xp-1.6.0 → conson_xp-1.8.0}/LICENSE +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/README.md +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/__main__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/file_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/module_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/server/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/server/server_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/main.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/click_tree.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/decorators.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/error_handlers.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/formatters.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/serial_number_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/system_function_choice.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/xp_module_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/connection/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/connection/exceptions.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/actiontable.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_blink.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_custom.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_discover.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_output.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_raw.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_receive.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/homekit_config.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/log_entry.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/protocol/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/response.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/action_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/datapoint_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/event_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/event_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/input_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/module_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/module_type_code.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/output_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/reply_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/system_function.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/system_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/telegram_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/timeparam_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/write_config_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/actiontable_serializer.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_discover_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_receive_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/write_config_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/log_file_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/module_type_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/protocol_factory.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/reverse_proxy_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/cp20_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/device_service_factory.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp130_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp20_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp230_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp24_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp33_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/checksum.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/event_helper.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/serialization.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/time_utils.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/.coverage +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/conftest.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/.coverage +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/telegram_test_data.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_actiontable_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_api/.coverage +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_api/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_blink_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_checksum_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_blink_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_raw_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_receive_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_discovery_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_event_telegram_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_homekit_config_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_link_number_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_module_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_output_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_version_integration.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_api/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_click_tree.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_decorators.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_formatters.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_connection/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_connection/test_connection_init.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_connection/test_exceptions.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_encoding/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_event_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_log_entry.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_module_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_system_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_version_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_write_config_type.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_base_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_blink_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_checksum_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_device_service_factory.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_discovery_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_services.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_log_file_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_module_type_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_protocol.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_server_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_telegram_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_version_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/__init__.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/test_checksum.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/test_event_helper.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/test_serialization.py +0 -0
- {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/test_time_utils.py +0 -0
{conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py
RENAMED
|
@@ -49,13 +49,22 @@ def conbus_download_msactiontable(
|
|
|
49
49
|
click.echo(progress, nl=False)
|
|
50
50
|
|
|
51
51
|
def on_finish(
|
|
52
|
-
action_table: Union[
|
|
52
|
+
action_table: Union[
|
|
53
|
+
Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None
|
|
54
|
+
],
|
|
53
55
|
) -> None:
|
|
54
56
|
"""Handle successful completion of MS action table download.
|
|
55
57
|
|
|
56
58
|
Args:
|
|
57
|
-
action_table: Downloaded MS action table object.
|
|
59
|
+
action_table: Downloaded MS action table object or None if failed.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
Abort: If action table download failed.
|
|
58
63
|
"""
|
|
64
|
+
if action_table is None:
|
|
65
|
+
click.echo("Error: Failed to download MS action table")
|
|
66
|
+
raise click.Abort()
|
|
67
|
+
|
|
59
68
|
output = {
|
|
60
69
|
"serial_number": serial_number,
|
|
61
70
|
"xpmoduletype": xpmoduletype,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Input action types for XP24 module based on Feature-Action-Table.md."""
|
|
2
2
|
|
|
3
|
-
from enum import
|
|
3
|
+
from enum import Enum
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class InputActionType(
|
|
6
|
+
class InputActionType(Enum):
|
|
7
7
|
"""Input action types for XP24 module (based on Feature-Action-Table.md).
|
|
8
8
|
|
|
9
9
|
Attributes:
|
{conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp20_serializer.py
RENAMED
|
@@ -46,8 +46,9 @@ class Xp20MsActionTableSerializer:
|
|
|
46
46
|
input_channel, input_index, raw_bytes
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
+
encoded_data = nibbles(raw_bytes)
|
|
49
50
|
# Convert raw bytes to hex string with A-P encoding
|
|
50
|
-
return
|
|
51
|
+
return "AAAA" + encoded_data
|
|
51
52
|
|
|
52
53
|
@staticmethod
|
|
53
54
|
def from_data(msactiontable_rawdata: str) -> Xp20MsActionTable:
|
|
@@ -62,13 +63,20 @@ class Xp20MsActionTableSerializer:
|
|
|
62
63
|
Raises:
|
|
63
64
|
ValueError: If input length is not 64 characters
|
|
64
65
|
"""
|
|
65
|
-
|
|
66
|
+
raw_length = len(msactiontable_rawdata)
|
|
67
|
+
if raw_length < 68: # Minimum: 4 char prefix + 64 chars data
|
|
66
68
|
raise ValueError(
|
|
67
|
-
f"XP20 action table data must be
|
|
69
|
+
f"XP20 action table data must be 68 characters long, got {len(msactiontable_rawdata)}"
|
|
68
70
|
)
|
|
69
71
|
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
+
# Remove action table count prefix (first 4 characters: AAAA, AAAB, etc.)
|
|
73
|
+
data = msactiontable_rawdata[4:]
|
|
74
|
+
|
|
75
|
+
# Take first 64 chars (32 bytes) as per pseudocode
|
|
76
|
+
hex_data = data[:64]
|
|
77
|
+
|
|
78
|
+
# Convert hex string to bytes using deNibble (A-P encoding)
|
|
79
|
+
raw_bytes = de_nibbles(hex_data)
|
|
72
80
|
|
|
73
81
|
# Decode input channels
|
|
74
82
|
input_channels = []
|
|
@@ -159,23 +167,3 @@ class Xp20MsActionTableSerializer:
|
|
|
159
167
|
and_functions_byte |= 1 << bit_index
|
|
160
168
|
|
|
161
169
|
raw_bytes[AND_FUNCTIONS_INDEX + input_index] = and_functions_byte
|
|
162
|
-
|
|
163
|
-
@staticmethod
|
|
164
|
-
def from_telegrams(ms_telegrams: str) -> Xp20MsActionTable:
|
|
165
|
-
"""Legacy method for backward compatibility. Use from_data() instead.
|
|
166
|
-
|
|
167
|
-
Args:
|
|
168
|
-
ms_telegrams: Full telegram string
|
|
169
|
-
|
|
170
|
-
Returns:
|
|
171
|
-
Decoded XP20 action table
|
|
172
|
-
"""
|
|
173
|
-
# Extract data portion from telegram (skip header, take action table data)
|
|
174
|
-
# Based on XP24 pattern: telegram[16:84] gives us the 68-char data portion
|
|
175
|
-
# For XP20, we need 64 chars, so we take the first 64 chars after removing count
|
|
176
|
-
data_parts = ms_telegrams[16:84]
|
|
177
|
-
|
|
178
|
-
# Remove action table count (first 4 chars: AAAA, AAAB, etc.)
|
|
179
|
-
hex_data = data_parts[4:68] # Take 64 chars after count
|
|
180
|
-
|
|
181
|
-
return Xp20MsActionTableSerializer.from_data(hex_data)
|
{conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp24_serializer.py
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from xp.models.actiontable.msactiontable_xp24 import InputAction, Xp24MsActionTable
|
|
4
4
|
from xp.models.telegram.input_action_type import InputActionType
|
|
5
5
|
from xp.models.telegram.timeparam_type import TimeParam
|
|
6
|
-
from xp.utils.serialization import de_nibbles
|
|
6
|
+
from xp.utils.serialization import de_nibbles, nibbles
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Xp24MsActionTableSerializer:
|
|
@@ -17,11 +17,12 @@ class Xp24MsActionTableSerializer:
|
|
|
17
17
|
action_table: XP24 MS action table to serialize.
|
|
18
18
|
|
|
19
19
|
Returns:
|
|
20
|
-
Serialized action table data string.
|
|
20
|
+
Serialized action table data string (68 characters).
|
|
21
21
|
"""
|
|
22
|
-
|
|
22
|
+
# Build byte array for the action table (32 bytes total)
|
|
23
|
+
raw_bytes = bytearray()
|
|
23
24
|
|
|
24
|
-
# Encode all 4 input actions
|
|
25
|
+
# Encode all 4 input actions (2 bytes each = 8 bytes total)
|
|
25
26
|
input_actions = [
|
|
26
27
|
action_table.input1_action,
|
|
27
28
|
action_table.input2_action,
|
|
@@ -30,26 +31,24 @@ class Xp24MsActionTableSerializer:
|
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
for action in input_actions:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
]
|
|
49
|
-
)
|
|
34
|
+
raw_bytes.append(action.type.value)
|
|
35
|
+
raw_bytes.append(action.param.value)
|
|
36
|
+
|
|
37
|
+
# Add settings (5 bytes)
|
|
38
|
+
raw_bytes.append(0x01 if action_table.mutex12 else 0x00)
|
|
39
|
+
raw_bytes.append(0x01 if action_table.mutex34 else 0x00)
|
|
40
|
+
raw_bytes.append(action_table.mutual_deadtime)
|
|
41
|
+
raw_bytes.append(0x01 if action_table.curtain12 else 0x00)
|
|
42
|
+
raw_bytes.append(0x01 if action_table.curtain34 else 0x00)
|
|
43
|
+
|
|
44
|
+
# Add padding to reach 32 bytes (19 more bytes needed)
|
|
45
|
+
raw_bytes.extend([0x00] * 19)
|
|
46
|
+
|
|
47
|
+
# Encode to A-P nibbles (32 bytes -> 64 chars)
|
|
48
|
+
encoded_data = nibbles(bytes(raw_bytes))
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
return
|
|
50
|
+
# Prepend action table count "AAAA" (4 chars) -> total 68 chars
|
|
51
|
+
return "AAAA" + encoded_data
|
|
53
52
|
|
|
54
53
|
@staticmethod
|
|
55
54
|
def from_data(msactiontable_rawdata: str) -> Xp24MsActionTable:
|
|
@@ -66,7 +65,9 @@ class Xp24MsActionTableSerializer:
|
|
|
66
65
|
"""
|
|
67
66
|
raw_length = len(msactiontable_rawdata)
|
|
68
67
|
if raw_length != 68:
|
|
69
|
-
raise ValueError(
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"Msactiontable is not 68 bytes long ({raw_length}): {msactiontable_rawdata}"
|
|
70
|
+
)
|
|
70
71
|
|
|
71
72
|
# Remove action table count AAAA, AAAB .
|
|
72
73
|
data = msactiontable_rawdata[4:]
|
|
@@ -117,18 +118,3 @@ class Xp24MsActionTableSerializer:
|
|
|
117
118
|
param_type = TimeParam(param_id)
|
|
118
119
|
|
|
119
120
|
return InputAction(action_type, param_type)
|
|
120
|
-
|
|
121
|
-
@staticmethod
|
|
122
|
-
def from_telegrams(ms_telegrams: str) -> Xp24MsActionTable:
|
|
123
|
-
"""Legacy method for backward compatibility. Use from_data() instead.
|
|
124
|
-
|
|
125
|
-
Args:
|
|
126
|
-
ms_telegrams: Telegram data string.
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
Deserialized XP24 MS action table.
|
|
130
|
-
"""
|
|
131
|
-
# For backward compatibility, assume full telegrams and extract data
|
|
132
|
-
data_parts = ms_telegrams[16:84]
|
|
133
|
-
|
|
134
|
-
return Xp24MsActionTableSerializer.from_data(data_parts)
|
{conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp33_serializer.py
RENAMED
|
@@ -6,7 +6,7 @@ from xp.models.actiontable.msactiontable_xp33 import (
|
|
|
6
6
|
Xp33Scene,
|
|
7
7
|
)
|
|
8
8
|
from xp.models.telegram.timeparam_type import TimeParam
|
|
9
|
-
from xp.utils.serialization import bits_to_byte, byte_to_bits, de_nibbles,
|
|
9
|
+
from xp.utils.serialization import bits_to_byte, byte_to_bits, de_nibbles, nibbles
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class Xp33MsActionTableSerializer:
|
|
@@ -96,13 +96,11 @@ class Xp33MsActionTableSerializer:
|
|
|
96
96
|
raw_bytes[24] = bits_to_byte(leading_edge_bits)
|
|
97
97
|
|
|
98
98
|
# Bytes 25-31 are padding (already 0)
|
|
99
|
-
|
|
100
99
|
# Convert to hex string using nibble encoding
|
|
101
|
-
|
|
102
|
-
for byte_val in raw_bytes:
|
|
103
|
-
hex_data += nibble(byte_val)
|
|
100
|
+
encoded_data = nibbles(raw_bytes)
|
|
104
101
|
|
|
105
|
-
|
|
102
|
+
# Convert raw bytes to hex string with A-P encoding
|
|
103
|
+
return "AAAA" + encoded_data
|
|
106
104
|
|
|
107
105
|
@staticmethod
|
|
108
106
|
def from_data(msactiontable_rawdata: str) -> Xp33MsActionTable:
|
|
@@ -239,18 +237,3 @@ class Xp33MsActionTableSerializer:
|
|
|
239
237
|
output3_level=output3_level,
|
|
240
238
|
time=time_param,
|
|
241
239
|
)
|
|
242
|
-
|
|
243
|
-
@staticmethod
|
|
244
|
-
def from_telegrams(ms_telegrams: str) -> Xp33MsActionTable:
|
|
245
|
-
"""Legacy method for backward compatibility. Use from_data() instead.
|
|
246
|
-
|
|
247
|
-
Args:
|
|
248
|
-
ms_telegrams: Telegram data string.
|
|
249
|
-
|
|
250
|
-
Returns:
|
|
251
|
-
Deserialized XP33 MS action table.
|
|
252
|
-
"""
|
|
253
|
-
# For backward compatibility, assume full telegrams and extract data
|
|
254
|
-
data_parts = ms_telegrams[16:152] # Adjusted for XP33 length
|
|
255
|
-
|
|
256
|
-
return Xp33MsActionTableSerializer.from_data(data_parts)
|
{conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/actiontable_service.py
RENAMED
|
@@ -51,7 +51,9 @@ class ActionTableService(ConbusProtocol):
|
|
|
51
51
|
|
|
52
52
|
def connection_established(self) -> None:
|
|
53
53
|
"""Handle connection established event."""
|
|
54
|
-
self.logger.debug(
|
|
54
|
+
self.logger.debug(
|
|
55
|
+
"Connection established, sending download actiontable telegram"
|
|
56
|
+
)
|
|
55
57
|
self.send_telegram(
|
|
56
58
|
telegram_type=TelegramType.SYSTEM,
|
|
57
59
|
serial_number=self.serial_number,
|
|
@@ -82,7 +84,9 @@ class ActionTableService(ConbusProtocol):
|
|
|
82
84
|
self.logger.debug("Not a reply response")
|
|
83
85
|
return
|
|
84
86
|
|
|
85
|
-
reply_telegram = self.telegram_service.parse_reply_telegram(
|
|
87
|
+
reply_telegram = self.telegram_service.parse_reply_telegram(
|
|
88
|
+
telegram_received.frame
|
|
89
|
+
)
|
|
86
90
|
if reply_telegram.system_function not in (
|
|
87
91
|
SystemFunction.ACTIONTABLE,
|
|
88
92
|
SystemFunction.EOF,
|
{conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/msactiontable_service.py
RENAMED
|
@@ -74,7 +74,8 @@ class MsActionTableService(ConbusProtocol):
|
|
|
74
74
|
self.error_callback: Optional[Callable[[str], None]] = None
|
|
75
75
|
self.finish_callback: Optional[
|
|
76
76
|
Callable[
|
|
77
|
-
[Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable]],
|
|
77
|
+
[Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None]],
|
|
78
|
+
None,
|
|
78
79
|
]
|
|
79
80
|
] = None
|
|
80
81
|
self.msactiontable_data: list[str] = []
|
|
@@ -83,7 +84,9 @@ class MsActionTableService(ConbusProtocol):
|
|
|
83
84
|
|
|
84
85
|
def connection_established(self) -> None:
|
|
85
86
|
"""Handle connection established event."""
|
|
86
|
-
self.logger.debug(
|
|
87
|
+
self.logger.debug(
|
|
88
|
+
"Connection established, sending download msactiontable telegram"
|
|
89
|
+
)
|
|
87
90
|
self.send_telegram(
|
|
88
91
|
telegram_type=TelegramType.SYSTEM,
|
|
89
92
|
serial_number=self.serial_number,
|
|
@@ -114,17 +117,32 @@ class MsActionTableService(ConbusProtocol):
|
|
|
114
117
|
self.logger.debug("Not a reply response")
|
|
115
118
|
return
|
|
116
119
|
|
|
117
|
-
reply_telegram = self.telegram_service.parse_reply_telegram(
|
|
120
|
+
reply_telegram = self.telegram_service.parse_reply_telegram(
|
|
121
|
+
telegram_received.frame
|
|
122
|
+
)
|
|
118
123
|
if reply_telegram.system_function not in (
|
|
119
124
|
SystemFunction.MSACTIONTABLE,
|
|
125
|
+
SystemFunction.ACK,
|
|
126
|
+
SystemFunction.NAK,
|
|
120
127
|
SystemFunction.EOF,
|
|
121
128
|
):
|
|
122
129
|
self.logger.debug("Not a msactiontable response")
|
|
123
130
|
return
|
|
124
131
|
|
|
125
|
-
if reply_telegram.system_function == SystemFunction.
|
|
126
|
-
self.logger.debug("
|
|
127
|
-
|
|
132
|
+
if reply_telegram.system_function == SystemFunction.ACK:
|
|
133
|
+
self.logger.debug("Received ACK")
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
if reply_telegram.system_function == SystemFunction.NAK:
|
|
137
|
+
self.logger.debug("Received NAK")
|
|
138
|
+
self.failed("Received NAK")
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
if reply_telegram.system_function == SystemFunction.MSACTIONTABLE:
|
|
142
|
+
self.logger.debug("Received MSACTIONTABLE")
|
|
143
|
+
self.msactiontable_data.extend(
|
|
144
|
+
(reply_telegram.data, reply_telegram.data_value)
|
|
145
|
+
)
|
|
128
146
|
if self.progress_callback:
|
|
129
147
|
self.progress_callback(".")
|
|
130
148
|
|
|
@@ -137,11 +155,14 @@ class MsActionTableService(ConbusProtocol):
|
|
|
137
155
|
return
|
|
138
156
|
|
|
139
157
|
if reply_telegram.system_function == SystemFunction.EOF:
|
|
158
|
+
self.logger.debug("Received EOF")
|
|
140
159
|
all_data = "".join(self.msactiontable_data)
|
|
141
160
|
# Deserialize from received data
|
|
142
161
|
msactiontable = self.serializer.from_data(all_data)
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
self.succeed(msactiontable)
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
self.logger.debug("Invalid msactiontable response")
|
|
145
166
|
|
|
146
167
|
def failed(self, message: str) -> None:
|
|
147
168
|
"""Handle failed connection event.
|
|
@@ -152,6 +173,20 @@ class MsActionTableService(ConbusProtocol):
|
|
|
152
173
|
self.logger.debug(f"Failed: {message}")
|
|
153
174
|
if self.error_callback:
|
|
154
175
|
self.error_callback(message)
|
|
176
|
+
self._stop_reactor()
|
|
177
|
+
|
|
178
|
+
def succeed(
|
|
179
|
+
self,
|
|
180
|
+
msactiontable: Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable],
|
|
181
|
+
) -> None:
|
|
182
|
+
"""Handle succeed connection event.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
msactiontable: result.
|
|
186
|
+
"""
|
|
187
|
+
if self.finish_callback:
|
|
188
|
+
self.finish_callback(msactiontable)
|
|
189
|
+
self._stop_reactor()
|
|
155
190
|
|
|
156
191
|
def start(
|
|
157
192
|
self,
|
|
@@ -160,7 +195,7 @@ class MsActionTableService(ConbusProtocol):
|
|
|
160
195
|
progress_callback: Callable[[str], None],
|
|
161
196
|
error_callback: Callable[[str], None],
|
|
162
197
|
finish_callback: Callable[
|
|
163
|
-
[Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable]], None
|
|
198
|
+
[Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None]], None
|
|
164
199
|
],
|
|
165
200
|
timeout_seconds: Optional[float] = None,
|
|
166
201
|
) -> None:
|
|
@@ -230,13 +230,11 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
|
|
|
230
230
|
self.timeout_call = self.reactor.callLater(
|
|
231
231
|
self.timeout_seconds, self._on_timeout
|
|
232
232
|
)
|
|
233
|
-
self.logger.debug(f"Timeout set for {self.timeout_seconds} seconds")
|
|
234
233
|
|
|
235
234
|
def _cancel_timeout(self) -> None:
|
|
236
235
|
"""Cancel the inactivity timeout."""
|
|
237
236
|
if self.timeout_call and self.timeout_call.active():
|
|
238
237
|
self.timeout_call.cancel()
|
|
239
|
-
self.logger.debug("Timeout cancelled")
|
|
240
238
|
|
|
241
239
|
def _on_timeout(self) -> None:
|
|
242
240
|
"""Handle inactivity timeout expiration."""
|
|
@@ -185,15 +185,25 @@ class BaseServerService(ABC):
|
|
|
185
185
|
Returns:
|
|
186
186
|
ACK telegram if request is valid, NAK otherwise.
|
|
187
187
|
"""
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
and self.msactiontable_download_state is None
|
|
191
|
-
):
|
|
192
|
-
self.msactiontable_download_state = "ack_sent"
|
|
193
|
-
# Send ACK and queue data telegram
|
|
194
|
-
return self._build_response_telegram(f"R{self.serial_number}F18D") # ACK
|
|
188
|
+
serializer = self._get_msactiontable_serializer()
|
|
189
|
+
msactiontable = self._get_msactiontable()
|
|
195
190
|
|
|
196
|
-
|
|
191
|
+
# Only handle if serializer and msactiontable are available
|
|
192
|
+
if not serializer or msactiontable is None:
|
|
193
|
+
return None
|
|
194
|
+
|
|
195
|
+
# Send ACK and queue data telegram
|
|
196
|
+
ack_data = self._build_response_telegram(f"R{self.serial_number}F18D") # ACK
|
|
197
|
+
|
|
198
|
+
# Send MsActionTable data
|
|
199
|
+
encoded_data = serializer.to_data(msactiontable)
|
|
200
|
+
data_telegram = self._build_response_telegram(
|
|
201
|
+
f"R{self.serial_number}F17D{encoded_data}"
|
|
202
|
+
)
|
|
203
|
+
self.msactiontable_download_state = "data_sent"
|
|
204
|
+
|
|
205
|
+
# Return ACK and TABLE
|
|
206
|
+
return ack_data + data_telegram
|
|
197
207
|
|
|
198
208
|
def _handle_download_msactiontable_ack_request(
|
|
199
209
|
self, _request: SystemTelegram
|
|
@@ -206,24 +216,7 @@ class BaseServerService(ABC):
|
|
|
206
216
|
Returns:
|
|
207
217
|
Data telegram, EOF telegram, or NAK if state is invalid.
|
|
208
218
|
"""
|
|
209
|
-
|
|
210
|
-
msactiontable = self._get_msactiontable()
|
|
211
|
-
|
|
212
|
-
# Only handle if serializer and msactiontable are available
|
|
213
|
-
if not serializer or msactiontable is None:
|
|
214
|
-
return None
|
|
215
|
-
|
|
216
|
-
# Handle F18D - CONTINUE (after ACK or data)
|
|
217
|
-
if self.msactiontable_download_state == "ack_sent":
|
|
218
|
-
# Send MsActionTable data
|
|
219
|
-
encoded_data = serializer.to_data(msactiontable)
|
|
220
|
-
data_telegram = self._build_response_telegram(
|
|
221
|
-
f"R{self.serial_number}F17D{encoded_data}"
|
|
222
|
-
)
|
|
223
|
-
self.msactiontable_download_state = "data_sent"
|
|
224
|
-
return data_telegram
|
|
225
|
-
|
|
226
|
-
elif self.msactiontable_download_state == "data_sent":
|
|
219
|
+
if self.msactiontable_download_state == "data_sent":
|
|
227
220
|
# Send EOF
|
|
228
221
|
eof_telegram = self._build_response_telegram(f"R{self.serial_number}F16D")
|
|
229
222
|
self.msactiontable_download_state = None
|
|
@@ -367,11 +360,7 @@ class BaseServerService(ABC):
|
|
|
367
360
|
Returns:
|
|
368
361
|
List of telegram strings from the buffer. The buffer is cleared after collection.
|
|
369
362
|
"""
|
|
370
|
-
self.logger.debug(
|
|
371
|
-
f"Collecting {self.serial_number} telegrams from buffer: {len(self.telegram_buffer)}"
|
|
372
|
-
)
|
|
373
363
|
with self.telegram_buffer_lock:
|
|
374
364
|
result = self.telegram_buffer.copy()
|
|
375
|
-
self.logger.debug(f"Resetting {self.serial_number} buffer")
|
|
376
365
|
self.telegram_buffer.clear()
|
|
377
366
|
return result
|
|
@@ -209,14 +209,11 @@ class ServerService:
|
|
|
209
209
|
self.logger.debug(f"Sent buffer to {client_address}")
|
|
210
210
|
|
|
211
211
|
# Receive data from client
|
|
212
|
-
self.logger.debug(f"Receiving data {client_address}")
|
|
213
212
|
data = None
|
|
214
213
|
try:
|
|
215
214
|
data = client_socket.recv(1024)
|
|
216
215
|
except socket.timeout:
|
|
217
|
-
|
|
218
|
-
f"Timeout receiving data {client_address} ({timeout})"
|
|
219
|
-
)
|
|
216
|
+
pass
|
|
220
217
|
finally:
|
|
221
218
|
timeout -= 1
|
|
222
219
|
|
|
@@ -421,9 +418,6 @@ class ServerService:
|
|
|
421
418
|
self.logger.info("Collector thread starting")
|
|
422
419
|
|
|
423
420
|
while True:
|
|
424
|
-
self.logger.debug(
|
|
425
|
-
f"Collector thread collecting ({len(self.collector_buffer)})"
|
|
426
|
-
)
|
|
427
421
|
collected = 0
|
|
428
422
|
for device_service in self.device_services.values():
|
|
429
423
|
telegram_buffer = device_service.collect_telegram_buffer()
|
|
@@ -431,5 +425,4 @@ class ServerService:
|
|
|
431
425
|
collected += len(telegram_buffer)
|
|
432
426
|
|
|
433
427
|
# Wait a bit before checking again
|
|
434
|
-
self.logger.debug(f"Collector thread collected ({collected})")
|
|
435
428
|
self.collector_stop_event.wait(timeout=1)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
This module provides telegram parsing functionality for event, system, and reply telegrams.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import logging
|
|
6
7
|
import re
|
|
7
8
|
from typing import Union
|
|
8
9
|
|
|
@@ -48,7 +49,8 @@ class TelegramService:
|
|
|
48
49
|
|
|
49
50
|
def __init__(self) -> None:
|
|
50
51
|
"""Initialize the telegram service."""
|
|
51
|
-
|
|
52
|
+
# Set up logging
|
|
53
|
+
self.logger = logging.getLogger(__name__)
|
|
52
54
|
|
|
53
55
|
def parse_event_telegram(self, raw_telegram: str) -> EventTelegram:
|
|
54
56
|
"""Parse a raw telegram string into an EventTelegram object.
|
|
@@ -242,6 +244,7 @@ class TelegramService:
|
|
|
242
244
|
raise TelegramParsingError("Empty telegram string")
|
|
243
245
|
|
|
244
246
|
# Validate and parse using regex
|
|
247
|
+
self.logger.debug(f"Parsing reply telegram {raw_telegram}")
|
|
245
248
|
match = self.REPLY_TELEGRAM_PATTERN.match(raw_telegram.strip())
|
|
246
249
|
if not match:
|
|
247
250
|
raise TelegramParsingError(f"Invalid reply telegram format: {raw_telegram}")
|
|
@@ -326,6 +326,12 @@ class ServiceContainer:
|
|
|
326
326
|
# Module type services layer
|
|
327
327
|
self.container.register(ModuleTypeService, scope=punq.Scope.singleton)
|
|
328
328
|
|
|
329
|
+
# MsActionTable serializers
|
|
330
|
+
self.container.register(MsActionTableSerializer, scope=punq.Scope.singleton)
|
|
331
|
+
self.container.register(Xp20MsActionTableSerializer, scope=punq.Scope.singleton)
|
|
332
|
+
self.container.register(Xp24MsActionTableSerializer, scope=punq.Scope.singleton)
|
|
333
|
+
self.container.register(Xp33MsActionTableSerializer, scope=punq.Scope.singleton)
|
|
334
|
+
|
|
329
335
|
# Device service factory
|
|
330
336
|
self.container.register(
|
|
331
337
|
DeviceServiceFactory,
|
|
@@ -33,16 +33,8 @@ class TestXp20ActionTableIntegration:
|
|
|
33
33
|
# Serialize it
|
|
34
34
|
serialized = Xp20MsActionTableSerializer.to_data(action_table)
|
|
35
35
|
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
"0123456789ABCDEF" # 16 chars header
|
|
39
|
-
"AAAA"
|
|
40
|
-
+ serialized # 4 chars count + 64 chars data
|
|
41
|
-
+ "PADDING" # Additional padding
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
# Test legacy from_telegrams method
|
|
45
|
-
result = Xp20MsActionTableSerializer.from_telegrams(mock_telegram)
|
|
36
|
+
# Deserialize from data
|
|
37
|
+
result = Xp20MsActionTableSerializer.from_data(serialized)
|
|
46
38
|
|
|
47
39
|
# Verify the round-trip worked
|
|
48
40
|
assert result.input1.invert == action_table.input1.invert
|
|
@@ -166,7 +158,7 @@ class TestXp20ActionTableIntegration:
|
|
|
166
158
|
def test_specification_compliance(self):
|
|
167
159
|
"""Test compliance with the specification example."""
|
|
168
160
|
spec_example = (
|
|
169
|
-
"
|
|
161
|
+
"AAAAAAAAAAAAAAABACAEAIBACAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
170
162
|
)
|
|
171
163
|
|
|
172
164
|
# Should decode without errors
|
|
@@ -177,7 +169,7 @@ class TestXp20ActionTableIntegration:
|
|
|
177
169
|
|
|
178
170
|
# Test that we can re-encode it
|
|
179
171
|
re_encoded = Xp20MsActionTableSerializer.to_data(result)
|
|
180
|
-
assert len(re_encoded) ==
|
|
172
|
+
assert len(re_encoded) == 68
|
|
181
173
|
|
|
182
174
|
# Round-trip should work
|
|
183
175
|
final_result = Xp20MsActionTableSerializer.from_data(re_encoded)
|
|
@@ -92,9 +92,9 @@ class TestXp24ActionTableIntegration:
|
|
|
92
92
|
|
|
93
93
|
# Verify action table structure
|
|
94
94
|
action_table = output["action_table"]
|
|
95
|
-
assert action_table["input1_action"]["type"] == InputActionType.TOGGLE
|
|
95
|
+
assert action_table["input1_action"]["type"] == str(InputActionType.TOGGLE)
|
|
96
96
|
assert action_table["input1_action"]["param"] == TimeParam.NONE.value
|
|
97
|
-
assert action_table["input2_action"]["type"] == InputActionType.TURNON
|
|
97
|
+
assert action_table["input2_action"]["type"] == str(InputActionType.TURNON)
|
|
98
98
|
assert action_table["input2_action"]["param"] == TimeParam.T5SEC.value
|
|
99
99
|
assert action_table["mutex34"] is True
|
|
100
100
|
assert action_table["curtain34"] is True
|