conson-xp 2.0.0__tar.gz → 2.0.2__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-2.0.0 → conson_xp-2.0.2}/PKG-INFO +1 -1
- {conson_xp-2.0.0 → conson_xp-2.0.2}/pyproject.toml +1 -1
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/__init__.py +1 -1
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/main.py +23 -4
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_client_config.py +2 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/homekit/homekit_config.py +8 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/actiontable_serializer.py +4 -4
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/actiontable/actiontable_upload_service.py +8 -1
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/protocol/conbus_event_protocol.py +1 -1
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/term/homekit_service.py +105 -8
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/homekit.py +23 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_actiontable_serializer.py +111 -1
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_actiontable_upload_service.py +6 -2
- {conson_xp-2.0.0 → conson_xp-2.0.2}/LICENSE +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/README.md +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/__main__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_event_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_export_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_modulenumber_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/file_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/module_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/server/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/server/server_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/term/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/term/term.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/term/term_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/click_tree.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/decorators.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/error_handlers.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/formatters.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/module_type_choice.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/serial_number_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/utils/system_function_choice.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/actiontable/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/actiontable/actiontable.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/actiontable/actiontable_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_autoreport.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_blink.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_connection_status.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_custom.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_datapoint.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_discover.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_event_list.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_event_raw.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_export.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_linknumber.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_logger_config.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_output.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_raw.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_receive.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/config/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/config/conson_module_config.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/homekit/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/homekit/homekit_accessory.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/log_entry.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/protocol/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/protocol/conbus_protocol.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/response.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/action_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/datapoint_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/event_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/event_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/input_action_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/input_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/module_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/module_type_code.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/output_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/reply_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/system_function.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/system_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/telegram_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/telegram/timeparam_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/term/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/term/accessory_state.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/term/connection_state.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/term/module_state.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/term/protocol_keys_config.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/term/status_message.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/term/telegram_display.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/models/write_config_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/download_state_machine.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/actiontable/serializer_protocol.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/actiontable/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/actiontable/actiontable_download_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/actiontable/actiontable_list_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/actiontable/actiontable_show_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_blink_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_custom_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_discover_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_event_list_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_event_raw_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_export_actiontable_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_export_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_output_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_raw_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_receive_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/conbus_scan_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/write_config_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/log_file_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/module_type_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/protocol/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/reverse_proxy_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/base_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/client_buffer_manager.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/cp20_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/device_service_factory.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/xp130_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/xp20_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/xp230_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/xp24_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/server/xp33_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_blink_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_discover_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_output_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/telegram/telegram_version_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/term/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/term/homekit_accessory_driver.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/term/protocol_monitor_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/term/state_monitor_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/homekit.tcss +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/protocol.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/protocol.tcss +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/state.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/state.tcss +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/widgets/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/widgets/help_menu.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/widgets/modules_list.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/widgets/protocol_log.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/widgets/room_list.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/term/widgets/status_footer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/checksum.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/dependencies.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/event_helper.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/logging.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/serialization.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/state_machine.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/utils/time_utils.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/.coverage +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/conftest.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/.coverage +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/telegram_test_data.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_actiontable_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_api/.coverage +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_api/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_blink_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_checksum_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_conbus_blink_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_conbus_datapoint_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_conbus_raw_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_conbus_receive_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_discovery_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_event_telegram_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_link_number_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_module_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_output_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_reverse_proxy_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_system_reply_telegram_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_term_logging_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_version_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_xp20_action_table_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/integration/test_xp24_action_table_integration.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_api/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_click_tree.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_conbus_msactiontable_upload_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_decorators.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_error_handlers.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_formatters.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_serial_number_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_system_function_choice.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_cli/test_term_commands.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_encoding/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_conbus.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_conbus_client_send.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_conbus_discover.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_event_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_log_entry.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_logger_config.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_module_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_reply_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_system_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_term/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_term/test_accessory_state.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_version_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_write_config_type.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_xp20_action_table.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_xp24_action_table.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_xp24_action_table_short_format.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_actiontable_download_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_actiontable_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_base_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_blink_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_checksum_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_client_buffer_manager.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_event_list_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_event_protocol.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_event_raw_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_output_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_receive_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_conbus_scan_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_device_service_factory.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_discovery_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_homekit_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_log_file_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_module_type_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_protocol_monitor_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_server_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_state_monitor_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_telegram_input_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_telegram_output_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_telegram_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_version_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_xp20_action_table_serializer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_xp24_action_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_xp24_action_table_serializer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_xp24_action_table_service.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_xp33_action_table_serializer.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_xp33_short_format.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_xp_server_services.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_tui/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_tui/test_homekit_app.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_tui/test_protocol_log.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_tui/test_room_list.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_utils/__init__.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_utils/test_checksum.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_utils/test_event_helper.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_utils/test_logging.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_utils/test_serialization.py +0 -0
- {conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_utils/test_time_utils.py +0 -0
|
@@ -24,17 +24,36 @@ from xp.utils.logging import LoggerService
|
|
|
24
24
|
cls=HelpColorsGroup, help_headers_color="yellow", help_options_color="green"
|
|
25
25
|
)
|
|
26
26
|
@click.version_option()
|
|
27
|
+
@click.option(
|
|
28
|
+
"--cli-config",
|
|
29
|
+
"-c",
|
|
30
|
+
default="cli.yml",
|
|
31
|
+
help="Path to the CLI configuration file (default: cli.yml)",
|
|
32
|
+
type=click.Path(exists=False),
|
|
33
|
+
)
|
|
34
|
+
@click.option(
|
|
35
|
+
"--log-config",
|
|
36
|
+
"-l",
|
|
37
|
+
default="logger.yml",
|
|
38
|
+
help="Path to the logger configuration file (default: logger.yml)",
|
|
39
|
+
type=click.Path(exists=False),
|
|
40
|
+
)
|
|
27
41
|
@click.pass_context
|
|
28
|
-
def cli(ctx: click.Context) -> None:
|
|
42
|
+
def cli(ctx: click.Context, cli_config: str, log_config: str) -> None:
|
|
29
43
|
"""
|
|
30
44
|
XP CLI tool for remote console bus operations.
|
|
31
45
|
|
|
32
46
|
Args:
|
|
33
47
|
ctx: Click context object for passing state between commands.
|
|
48
|
+
cli_config: Path to the CLI configuration file.
|
|
49
|
+
log_config: Path to the logger configuration file.
|
|
34
50
|
"""
|
|
35
|
-
container = ServiceContainer(
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
container = ServiceContainer(
|
|
52
|
+
client_config_path=cli_config,
|
|
53
|
+
logger_config_path=log_config,
|
|
54
|
+
)
|
|
55
|
+
logger_service = container.get_container().resolve(LoggerService)
|
|
56
|
+
logger_service.setup()
|
|
38
57
|
|
|
39
58
|
# Initialize the service container and store it in the context
|
|
40
59
|
ctx.ensure_object(dict)
|
|
@@ -15,11 +15,13 @@ class ClientConfig(BaseModel):
|
|
|
15
15
|
ip: IP address of the Conbus server.
|
|
16
16
|
port: Port number for the connection.
|
|
17
17
|
timeout: Connection timeout in seconds.
|
|
18
|
+
queue_delay_max: Max delay between queued telegrams in centiseconds (default 40 = 0.40s).
|
|
18
19
|
"""
|
|
19
20
|
|
|
20
21
|
ip: str = "192.168.1.100"
|
|
21
22
|
port: int = 10001
|
|
22
23
|
timeout: float = 0.1
|
|
24
|
+
queue_delay_max: int = 40
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
class ConbusClientConfig(BaseModel):
|
|
@@ -66,6 +66,10 @@ class HomekitAccessoryConfig(BaseModel):
|
|
|
66
66
|
on_action: on code for the accessory.
|
|
67
67
|
off_action: off code for the accessory.
|
|
68
68
|
toggle_action: Optional toggle action code for the accessory.
|
|
69
|
+
dimup_action: Optional dim up action code for the dimmable accessory.
|
|
70
|
+
dimdown_action: Optional dim down action code for the dimmable accessory.
|
|
71
|
+
levelup_action: Optional level up action code for the dimmable accessory.
|
|
72
|
+
leveldown_action: Optional level down action code for the dimmable accessory.
|
|
69
73
|
hap_accessory: Optional HAP accessory identifier.
|
|
70
74
|
"""
|
|
71
75
|
|
|
@@ -78,6 +82,10 @@ class HomekitAccessoryConfig(BaseModel):
|
|
|
78
82
|
on_action: str
|
|
79
83
|
off_action: str
|
|
80
84
|
toggle_action: Optional[str] = None
|
|
85
|
+
dimup_action: Optional[str] = None
|
|
86
|
+
dimdown_action: Optional[str] = None
|
|
87
|
+
levelup_action: Optional[str] = None
|
|
88
|
+
leveldown_action: Optional[str] = None
|
|
81
89
|
hap_accessory: Optional[int] = None
|
|
82
90
|
|
|
83
91
|
|
|
@@ -65,8 +65,8 @@ class ActionTableSerializer(ActionTableSerializerProtocol):
|
|
|
65
65
|
link_number = de_bcd(data[i + 1])
|
|
66
66
|
module_input = de_bcd(data[i + 2])
|
|
67
67
|
|
|
68
|
-
# Extract output
|
|
69
|
-
module_output = lower3(data[i + 3])
|
|
68
|
+
# Extract output (0-indexed in wire format, convert to 1-indexed) and command
|
|
69
|
+
module_output = lower3(data[i + 3]) + 1
|
|
70
70
|
command_raw = upper5(data[i + 3])
|
|
71
71
|
|
|
72
72
|
parameter_raw = byte_to_unsigned(data[i + 4])
|
|
@@ -125,8 +125,8 @@ class ActionTableSerializer(ActionTableSerializerProtocol):
|
|
|
125
125
|
link_byte = to_bcd(entry.link_number)
|
|
126
126
|
input_byte = to_bcd(entry.module_input)
|
|
127
127
|
|
|
128
|
-
# Combine output (lower 3 bits) and command (upper 5 bits)
|
|
129
|
-
output_command_byte = (entry.module_output & 0x07) | (
|
|
128
|
+
# Combine output (lower 3 bits, 0-indexed) and command (upper 5 bits)
|
|
129
|
+
output_command_byte = ((entry.module_output - 1) & 0x07) | (
|
|
130
130
|
(entry.command.value & 0x1F) << 3
|
|
131
131
|
)
|
|
132
132
|
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/services/conbus/actiontable/actiontable_upload_service.py
RENAMED
|
@@ -81,6 +81,7 @@ class ActionTableUploadService:
|
|
|
81
81
|
# Upload state
|
|
82
82
|
self.upload_data_chunks: list[str] = []
|
|
83
83
|
self.current_chunk_index: int = 0
|
|
84
|
+
self._eof_sent: bool = False
|
|
84
85
|
|
|
85
86
|
# Set up logging
|
|
86
87
|
self.logger = logging.getLogger(__name__)
|
|
@@ -173,7 +174,7 @@ class ActionTableUploadService:
|
|
|
173
174
|
)
|
|
174
175
|
self.current_chunk_index += 1
|
|
175
176
|
self.on_progress.emit(".")
|
|
176
|
-
|
|
177
|
+
elif not self._eof_sent:
|
|
177
178
|
# All chunks sent, send EOF
|
|
178
179
|
self.logger.debug("All chunks sent, sending EOF")
|
|
179
180
|
self.conbus_protocol.send_telegram(
|
|
@@ -182,7 +183,13 @@ class ActionTableUploadService:
|
|
|
182
183
|
system_function=SystemFunction.EOF,
|
|
183
184
|
data_value="00",
|
|
184
185
|
)
|
|
186
|
+
self.on_progress.emit("END")
|
|
187
|
+
self.logger.debug("EOF sent, waiting for last ACK")
|
|
188
|
+
self._eof_sent = True
|
|
189
|
+
else:
|
|
190
|
+
self.logger.debug("Last ACK received, closing connection")
|
|
185
191
|
self.on_finish.emit(True)
|
|
192
|
+
|
|
186
193
|
elif reply_telegram.system_function == SystemFunction.NAK:
|
|
187
194
|
self.logger.debug("Received NAK during upload")
|
|
188
195
|
self.failed("Upload failed: NAK received")
|
|
@@ -513,7 +513,7 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
|
|
|
513
513
|
self.logger.debug("Queue manager: event loop")
|
|
514
514
|
telegram = self.telegram_queue.get_nowait()
|
|
515
515
|
self.sendFrame(telegram)
|
|
516
|
-
later = randint(
|
|
516
|
+
later = randint(5, self.cli_config.queue_delay_max) / 100
|
|
517
517
|
self.call_later(later, self.process_telegram_queue)
|
|
518
518
|
|
|
519
519
|
def set_event_loop(self, event_loop: asyncio.AbstractEventLoop) -> None:
|
|
@@ -81,6 +81,9 @@ class HomekitService:
|
|
|
81
81
|
# Set up HomeKit callback
|
|
82
82
|
self._accessory_driver.set_callback(self._on_homekit_set)
|
|
83
83
|
|
|
84
|
+
# Track active level action: (accessory_id, action_type) or None
|
|
85
|
+
self._active_level_action: Optional[tuple[str, str]] = None
|
|
86
|
+
|
|
84
87
|
# Connect to protocol signals
|
|
85
88
|
self._connect_signals()
|
|
86
89
|
|
|
@@ -421,12 +424,15 @@ class HomekitService:
|
|
|
421
424
|
Returns:
|
|
422
425
|
True if command was sent, False otherwise.
|
|
423
426
|
"""
|
|
427
|
+
config = self._find_accessory_config_by_id(accessory_id)
|
|
424
428
|
state = self._accessory_states.get(accessory_id)
|
|
425
|
-
if not state:
|
|
429
|
+
if not config or not state or not config.dimup_action:
|
|
430
|
+
self.logger.warning(f"No config for accessory {accessory_id}")
|
|
426
431
|
return False
|
|
427
|
-
|
|
428
|
-
self.
|
|
429
|
-
|
|
432
|
+
|
|
433
|
+
self.send_action(config.dimup_action)
|
|
434
|
+
self.on_status_message.emit(f"Dim+ {state.accessory_name}")
|
|
435
|
+
return True
|
|
430
436
|
|
|
431
437
|
def decrease_dimmer(self, accessory_id: str) -> bool:
|
|
432
438
|
"""
|
|
@@ -438,12 +444,103 @@ class HomekitService:
|
|
|
438
444
|
Returns:
|
|
439
445
|
True if command was sent, False otherwise.
|
|
440
446
|
"""
|
|
447
|
+
config = self._find_accessory_config_by_id(accessory_id)
|
|
441
448
|
state = self._accessory_states.get(accessory_id)
|
|
442
|
-
if not state:
|
|
449
|
+
if not config or not state or not config.dimdown_action:
|
|
450
|
+
self.logger.warning(f"No config for accessory {accessory_id}")
|
|
443
451
|
return False
|
|
444
|
-
|
|
445
|
-
self.
|
|
446
|
-
|
|
452
|
+
|
|
453
|
+
self.send_action(config.dimdown_action)
|
|
454
|
+
self.on_status_message.emit(f"Dim- {state.accessory_name}")
|
|
455
|
+
return True
|
|
456
|
+
|
|
457
|
+
def levelup_selected(self, accessory_id: str) -> bool:
|
|
458
|
+
"""
|
|
459
|
+
Increase level for accessory (toggle Make/Break).
|
|
460
|
+
|
|
461
|
+
First press sends Make (M), second press sends Break (B).
|
|
462
|
+
|
|
463
|
+
Args:
|
|
464
|
+
accessory_id: Accessory ID (e.g., "A12_1").
|
|
465
|
+
|
|
466
|
+
Returns:
|
|
467
|
+
True if command was sent, False otherwise.
|
|
468
|
+
"""
|
|
469
|
+
config = self._find_accessory_config_by_id(accessory_id)
|
|
470
|
+
state = self._accessory_states.get(accessory_id)
|
|
471
|
+
if not config or not state or not config.levelup_action:
|
|
472
|
+
self.logger.warning(f"No config for accessory {accessory_id}")
|
|
473
|
+
return False
|
|
474
|
+
|
|
475
|
+
return self._send_level_action(
|
|
476
|
+
accessory_id, "levelup", config.levelup_action, state.accessory_name
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
def leveldown_selected(self, accessory_id: str) -> bool:
|
|
480
|
+
"""
|
|
481
|
+
Decrease level for accessory (toggle Make/Break).
|
|
482
|
+
|
|
483
|
+
First press sends Make (M), second press sends Break (B).
|
|
484
|
+
|
|
485
|
+
Args:
|
|
486
|
+
accessory_id: Accessory ID (e.g., "A12_1").
|
|
487
|
+
|
|
488
|
+
Returns:
|
|
489
|
+
True if command was sent, False otherwise.
|
|
490
|
+
"""
|
|
491
|
+
config = self._find_accessory_config_by_id(accessory_id)
|
|
492
|
+
state = self._accessory_states.get(accessory_id)
|
|
493
|
+
if not config or not state or not config.leveldown_action:
|
|
494
|
+
self.logger.warning(f"No config for accessory {accessory_id}")
|
|
495
|
+
return False
|
|
496
|
+
|
|
497
|
+
return self._send_level_action(
|
|
498
|
+
accessory_id, "leveldown", config.leveldown_action, state.accessory_name
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
def _send_level_action(
|
|
502
|
+
self, accessory_id: str, action_type: str, action: str, name: str
|
|
503
|
+
) -> bool:
|
|
504
|
+
"""
|
|
505
|
+
Send level action with Make/Break toggle.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
accessory_id: Accessory ID.
|
|
509
|
+
action_type: "levelup" or "leveldown".
|
|
510
|
+
action: Action code (e.g., "E02L13I15").
|
|
511
|
+
name: Accessory name for status message.
|
|
512
|
+
|
|
513
|
+
Returns:
|
|
514
|
+
True if command was sent.
|
|
515
|
+
"""
|
|
516
|
+
current = self._active_level_action
|
|
517
|
+
|
|
518
|
+
# If same action is active, send Break and clear
|
|
519
|
+
if current and current[0] == accessory_id and current[1] == action_type:
|
|
520
|
+
self._conbus_protocol.send_raw_telegram(f"{action}B")
|
|
521
|
+
self._active_level_action = None
|
|
522
|
+
direction = "+" if action_type == "levelup" else "-"
|
|
523
|
+
self.on_status_message.emit(f"Level{direction} {name} [B]")
|
|
524
|
+
return True
|
|
525
|
+
|
|
526
|
+
# If different action is active, send Break for it first
|
|
527
|
+
if current:
|
|
528
|
+
old_config = self._find_accessory_config_by_id(current[0])
|
|
529
|
+
if old_config:
|
|
530
|
+
old_action = (
|
|
531
|
+
old_config.levelup_action
|
|
532
|
+
if current[1] == "levelup"
|
|
533
|
+
else old_config.leveldown_action
|
|
534
|
+
)
|
|
535
|
+
if old_action:
|
|
536
|
+
self._conbus_protocol.send_raw_telegram(f"{old_action}B")
|
|
537
|
+
|
|
538
|
+
# Send Make for new action
|
|
539
|
+
self._conbus_protocol.send_raw_telegram(f"{action}M")
|
|
540
|
+
self._active_level_action = (accessory_id, action_type)
|
|
541
|
+
direction = "+" if action_type == "levelup" else "-"
|
|
542
|
+
self.on_status_message.emit(f"Level{direction} {name} [M]")
|
|
543
|
+
return True
|
|
447
544
|
|
|
448
545
|
def refresh_all(self) -> None:
|
|
449
546
|
"""
|
|
@@ -41,6 +41,8 @@ class HomekitApp(App[None]):
|
|
|
41
41
|
("minus", "turn_off_selected", "Off"),
|
|
42
42
|
("plus", "dim_up", "Dim+"),
|
|
43
43
|
("quotation_mark", "dim_down", "Dim-"),
|
|
44
|
+
("asterisk", "level_up", "Level+"),
|
|
45
|
+
("ç", "level_down", "Level-"),
|
|
44
46
|
]
|
|
45
47
|
|
|
46
48
|
def __init__(self, homekit_service: HomekitService) -> None:
|
|
@@ -106,12 +108,17 @@ class HomekitApp(App[None]):
|
|
|
106
108
|
- - : Turn OFF
|
|
107
109
|
- + : Dim up
|
|
108
110
|
- " : Dim down
|
|
111
|
+
- * : Level up
|
|
112
|
+
- ç : Level down
|
|
109
113
|
|
|
110
114
|
Args:
|
|
111
115
|
event: Key press event.
|
|
112
116
|
"""
|
|
113
117
|
key = event.key
|
|
114
118
|
|
|
119
|
+
# Debug: show received key
|
|
120
|
+
self.homekit_service.on_status_message.emit(f"Key: {key}")
|
|
121
|
+
|
|
115
122
|
# Selection keys (a-z0-9)
|
|
116
123
|
if len(key) == 1 and (("a" <= key <= "z") or ("0" <= key <= "9")):
|
|
117
124
|
accessory_id = self.homekit_service.select_accessory(key)
|
|
@@ -140,6 +147,12 @@ class HomekitApp(App[None]):
|
|
|
140
147
|
elif key in ("quotation_mark", '"'):
|
|
141
148
|
self.homekit_service.decrease_dimmer(self.selected_accessory_id)
|
|
142
149
|
event.prevent_default()
|
|
150
|
+
elif key in ("asterisk", "star", "*"):
|
|
151
|
+
self.homekit_service.levelup_selected(self.selected_accessory_id)
|
|
152
|
+
event.prevent_default()
|
|
153
|
+
elif key in ("cedille", "ç"):
|
|
154
|
+
self.homekit_service.leveldown_selected(self.selected_accessory_id)
|
|
155
|
+
event.prevent_default()
|
|
143
156
|
|
|
144
157
|
def _select_row(self, action_key: str) -> None:
|
|
145
158
|
"""
|
|
@@ -243,6 +256,16 @@ class HomekitApp(App[None]):
|
|
|
243
256
|
if self.selected_accessory_id:
|
|
244
257
|
self.homekit_service.decrease_dimmer(self.selected_accessory_id)
|
|
245
258
|
|
|
259
|
+
def action_level_up(self) -> None:
|
|
260
|
+
"""Increase level on selected accessory."""
|
|
261
|
+
if self.selected_accessory_id:
|
|
262
|
+
self.homekit_service.levelup_selected(self.selected_accessory_id)
|
|
263
|
+
|
|
264
|
+
def action_level_down(self) -> None:
|
|
265
|
+
"""Decrease level on selected accessory."""
|
|
266
|
+
if self.selected_accessory_id:
|
|
267
|
+
self.homekit_service.leveldown_selected(self.selected_accessory_id)
|
|
268
|
+
|
|
246
269
|
async def on_unmount(self) -> None:
|
|
247
270
|
"""Stop AccessoryDriver and clean up service when app unmounts."""
|
|
248
271
|
await self.homekit_service.stop()
|
|
@@ -398,7 +398,7 @@ class TestActionTableSerializerPadding:
|
|
|
398
398
|
assert result[0] == 0x02 # CP20 (value=2) in BCD
|
|
399
399
|
assert result[1] == 0x01 # link_number
|
|
400
400
|
assert result[2] == 0x02 # module_input
|
|
401
|
-
assert result[3] ==
|
|
401
|
+
assert result[3] == 0x0A # output 0-indexed: (3-1) | (ON << 3) = 2 | 8 = 10
|
|
402
402
|
assert result[4] == 0x04 # parameter
|
|
403
403
|
|
|
404
404
|
# Rest should be padding
|
|
@@ -414,3 +414,113 @@ class TestActionTableSerializerPadding:
|
|
|
414
414
|
# Should still be 480 bytes, all zeros
|
|
415
415
|
assert len(result) == 480
|
|
416
416
|
assert result == b"\x00" * 480
|
|
417
|
+
|
|
418
|
+
def test_to_encoded_string_cp20_link4_input0_output1_on(self):
|
|
419
|
+
"""
|
|
420
|
+
Test encoding CP20 4 0 > 1 ON produces expected BCD string.
|
|
421
|
+
|
|
422
|
+
ActionTable: CP20 4 0 > 1 ON;
|
|
423
|
+
Serialized BCD (first 8 chars): ACAEAAAI
|
|
424
|
+
"""
|
|
425
|
+
action_table = ActionTable(
|
|
426
|
+
entries=[
|
|
427
|
+
ActionTableEntry(
|
|
428
|
+
module_type=ModuleTypeCode.CP20,
|
|
429
|
+
link_number=4,
|
|
430
|
+
module_input=0,
|
|
431
|
+
module_output=1,
|
|
432
|
+
command=InputActionType.ON,
|
|
433
|
+
parameter=TimeParam.NONE,
|
|
434
|
+
inverted=False,
|
|
435
|
+
)
|
|
436
|
+
]
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
encoded_string = ActionTableSerializer.to_encoded_string(action_table)
|
|
440
|
+
|
|
441
|
+
# First 8 characters (4 bytes in BCD, high-nibble first):
|
|
442
|
+
# AC = 0x02 (CP20, value=2)
|
|
443
|
+
# AE = 0x04 (link_number=4)
|
|
444
|
+
# AA = 0x00 (module_input=0)
|
|
445
|
+
# AI = 0x08 (output 0-indexed: (1-1) | (ON<<3) = 0 | 8 = 8)
|
|
446
|
+
assert encoded_string[:8] == "ACAEAAAI"
|
|
447
|
+
|
|
448
|
+
def test_from_encoded_string_cp20_link4_input0_output1_on(self):
|
|
449
|
+
"""
|
|
450
|
+
Test decoding BCD string ACAEAAAI produces expected ActionTable.
|
|
451
|
+
|
|
452
|
+
Serialized BCD: ACAEAAAI (+ padding)
|
|
453
|
+
ActionTable: CP20 4 0 > 1 ON;
|
|
454
|
+
"""
|
|
455
|
+
# Build full 960-char encoded string (96 entries × 5 bytes × 2 nibbles)
|
|
456
|
+
# First entry: ACAEAAAI, rest is padding (AA = 0x00)
|
|
457
|
+
encoded_string = "ACAEAAAI" + "AA" * 476
|
|
458
|
+
|
|
459
|
+
action_table = ActionTableSerializer.from_encoded_string(encoded_string)
|
|
460
|
+
|
|
461
|
+
# Should have exactly 1 entry (padding entries with NOMOD are filtered out)
|
|
462
|
+
assert len(action_table.entries) == 1
|
|
463
|
+
|
|
464
|
+
entry = action_table.entries[0]
|
|
465
|
+
assert entry.module_type == ModuleTypeCode.CP20
|
|
466
|
+
assert entry.link_number == 4
|
|
467
|
+
assert entry.module_input == 0
|
|
468
|
+
assert entry.module_output == 1 # 0-indexed in wire format, converted to 1
|
|
469
|
+
assert entry.command == InputActionType.ON
|
|
470
|
+
assert entry.parameter == TimeParam.NONE
|
|
471
|
+
assert entry.inverted is False
|
|
472
|
+
|
|
473
|
+
def test_to_encoded_string_cp20_link13_input9_output1_levelinc(self):
|
|
474
|
+
"""
|
|
475
|
+
Test encoding CP20 13 9 > 1 LEVELINC produces expected BCD string.
|
|
476
|
+
|
|
477
|
+
ActionTable: CP20 13 9 > 1 LEVELINC;
|
|
478
|
+
Serialized BCD (first 8 chars): ACBDAJEI
|
|
479
|
+
"""
|
|
480
|
+
action_table = ActionTable(
|
|
481
|
+
entries=[
|
|
482
|
+
ActionTableEntry(
|
|
483
|
+
module_type=ModuleTypeCode.CP20,
|
|
484
|
+
link_number=13,
|
|
485
|
+
module_input=9,
|
|
486
|
+
module_output=1,
|
|
487
|
+
command=InputActionType.LEVELINC,
|
|
488
|
+
parameter=TimeParam.NONE,
|
|
489
|
+
inverted=False,
|
|
490
|
+
)
|
|
491
|
+
]
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
encoded_string = ActionTableSerializer.to_encoded_string(action_table)
|
|
495
|
+
|
|
496
|
+
# First 8 characters (4 bytes in BCD, high-nibble first):
|
|
497
|
+
# AC = 0x02 (CP20, value=2)
|
|
498
|
+
# BD = 0x13 (link_number=13 in BCD)
|
|
499
|
+
# AJ = 0x09 (module_input=9)
|
|
500
|
+
# EI = 0x48 (output 0-indexed: (1-1) | (LEVELINC<<3) = 0 | 72 = 0x48)
|
|
501
|
+
assert encoded_string[:8] == "ACBDAJEI"
|
|
502
|
+
|
|
503
|
+
def test_from_encoded_string_cp20_link13_input9_output1_levelinc(self):
|
|
504
|
+
"""
|
|
505
|
+
Test decoding BCD string ACBDAJEIAA produces expected ActionTable.
|
|
506
|
+
|
|
507
|
+
Serialized BCD: ACBDAJEIAA (+ padding)
|
|
508
|
+
ActionTable: CP20 13 9 > 1 LEVELINC;
|
|
509
|
+
"""
|
|
510
|
+
# Build full 960-char encoded string (96 entries × 5 bytes × 2 nibbles)
|
|
511
|
+
# First entry: ACBDAJEIAA, rest is padding (AA = 0x00)
|
|
512
|
+
encoded_string = "ACBDAJEIAA" + "AA" * 475
|
|
513
|
+
|
|
514
|
+
action_table = ActionTableSerializer.from_encoded_string(encoded_string)
|
|
515
|
+
|
|
516
|
+
# Should have exactly 1 entry (padding entries with NOMOD are filtered out)
|
|
517
|
+
assert len(action_table.entries) == 1
|
|
518
|
+
|
|
519
|
+
entry = action_table.entries[0]
|
|
520
|
+
assert entry.module_type == ModuleTypeCode.CP20
|
|
521
|
+
assert entry.link_number == 13
|
|
522
|
+
assert entry.module_input == 9
|
|
523
|
+
assert entry.module_output == 1 # 0-indexed in wire format, converted to 1
|
|
524
|
+
assert entry.command == InputActionType.LEVELINC
|
|
525
|
+
assert entry.parameter == TimeParam.NONE
|
|
526
|
+
assert entry.inverted is False
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/tests/unit/test_services/test_actiontable_upload_service.py
RENAMED
|
@@ -408,6 +408,7 @@ class TestActionTableUploadChunkPrefix:
|
|
|
408
408
|
mock_reply = Mock()
|
|
409
409
|
mock_reply.system_function = SystemFunction.ACK
|
|
410
410
|
|
|
411
|
+
# First ACK after all chunks sent triggers EOF
|
|
411
412
|
service._handle_upload_response(mock_reply)
|
|
412
413
|
|
|
413
414
|
# Should send EOF
|
|
@@ -418,6 +419,9 @@ class TestActionTableUploadChunkPrefix:
|
|
|
418
419
|
data_value="00",
|
|
419
420
|
)
|
|
420
421
|
|
|
422
|
+
# Second ACK (after EOF) triggers finish signal
|
|
423
|
+
service._handle_upload_response(mock_reply)
|
|
424
|
+
|
|
421
425
|
# Should call finish signal with True
|
|
422
426
|
mock_finish.assert_called_once_with(True)
|
|
423
427
|
|
|
@@ -580,11 +584,11 @@ class TestActionTableUploadFullSequence:
|
|
|
580
584
|
# Simulate connection made
|
|
581
585
|
service.connection_made()
|
|
582
586
|
|
|
583
|
-
# Simulate ACK responses for each chunk +
|
|
587
|
+
# Simulate ACK responses for each chunk + ACK to trigger EOF + ACK after EOF
|
|
584
588
|
mock_ack = Mock()
|
|
585
589
|
mock_ack.system_function = SystemFunction.ACK
|
|
586
590
|
|
|
587
|
-
for _ in range(
|
|
591
|
+
for _ in range(17): # 15 chunks + 1 ACK to trigger EOF + 1 ACK after EOF
|
|
588
592
|
service._handle_upload_response(mock_ack)
|
|
589
593
|
|
|
590
594
|
# Verify: Exactly 17 telegrams sent (1 UPLOAD_ACTIONTABLE + 15 ACTIONTABLE + 1 EOF)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py
RENAMED
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py
RENAMED
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py
RENAMED
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_modulenumber_commands.py
RENAMED
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_checksum_commands.py
RENAMED
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_discover_commands.py
RENAMED
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py
RENAMED
|
File without changes
|
|
File without changes
|
{conson_xp-2.0.0 → conson_xp-2.0.2}/src/xp/cli/commands/telegram/telegram_version_commands.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|