conson-xp 2.0.2__tar.gz → 2.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. {conson_xp-2.0.2 → conson_xp-2.0.4}/PKG-INFO +1 -1
  2. {conson_xp-2.0.2 → conson_xp-2.0.4}/pyproject.toml +1 -1
  3. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/__init__.py +1 -1
  4. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_raw_commands.py +9 -10
  5. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_raw_service.py +13 -10
  6. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/term/homekit_accessory_driver.py +67 -11
  7. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/term/homekit_service.py +63 -4
  8. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_conbus_raw_integration.py +27 -20
  9. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_raw_service.py +8 -8
  10. {conson_xp-2.0.2 → conson_xp-2.0.4}/LICENSE +0 -0
  11. {conson_xp-2.0.2 → conson_xp-2.0.4}/README.md +0 -0
  12. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/__init__.py +0 -0
  13. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/__main__.py +0 -0
  14. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/__init__.py +0 -0
  15. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/__init__.py +0 -0
  16. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus.py +0 -0
  17. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  18. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  19. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  20. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  21. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  22. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  23. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
  24. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_event_commands.py +0 -0
  25. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_export_commands.py +0 -0
  26. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  27. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  28. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_modulenumber_commands.py +0 -0
  29. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +0 -0
  30. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  31. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
  32. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  33. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/file_commands.py +0 -0
  34. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/module_commands.py +0 -0
  35. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  36. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/server/__init__.py +0 -0
  37. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/server/server_commands.py +0 -0
  38. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/__init__.py +0 -0
  39. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/telegram.py +0 -0
  40. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  41. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  42. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  43. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  44. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  45. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  46. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/term/__init__.py +0 -0
  47. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/term/term.py +0 -0
  48. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/commands/term/term_commands.py +0 -0
  49. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/main.py +0 -0
  50. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/__init__.py +0 -0
  51. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/click_tree.py +0 -0
  52. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  53. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/decorators.py +0 -0
  54. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/error_handlers.py +0 -0
  55. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/formatters.py +0 -0
  56. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/module_type_choice.py +0 -0
  57. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/serial_number_type.py +0 -0
  58. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/cli/utils/system_function_choice.py +0 -0
  59. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/__init__.py +0 -0
  60. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/actiontable/__init__.py +0 -0
  61. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/actiontable/actiontable.py +0 -0
  62. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/actiontable/actiontable_type.py +0 -0
  63. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  64. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  65. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  66. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/__init__.py +0 -0
  67. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus.py +0 -0
  68. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  69. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_blink.py +0 -0
  70. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_client_config.py +0 -0
  71. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  72. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_custom.py +0 -0
  73. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  74. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_discover.py +0 -0
  75. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_event_list.py +0 -0
  76. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_event_raw.py +0 -0
  77. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_export.py +0 -0
  78. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  79. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  80. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_logger_config.py +0 -0
  81. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_output.py +0 -0
  82. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_raw.py +0 -0
  83. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_receive.py +0 -0
  84. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  85. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/config/__init__.py +0 -0
  86. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/config/conson_module_config.py +0 -0
  87. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/homekit/__init__.py +0 -0
  88. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/homekit/homekit_accessory.py +0 -0
  89. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/homekit/homekit_config.py +0 -0
  90. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/log_entry.py +0 -0
  91. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/protocol/__init__.py +0 -0
  92. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/protocol/conbus_protocol.py +0 -0
  93. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/response.py +0 -0
  94. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/__init__.py +0 -0
  95. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/action_type.py +0 -0
  96. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/datapoint_type.py +0 -0
  97. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/event_telegram.py +0 -0
  98. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/event_type.py +0 -0
  99. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/input_action_type.py +0 -0
  100. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/input_type.py +0 -0
  101. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/module_type.py +0 -0
  102. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/module_type_code.py +0 -0
  103. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/output_telegram.py +0 -0
  104. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/reply_telegram.py +0 -0
  105. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/system_function.py +0 -0
  106. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/system_telegram.py +0 -0
  107. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/telegram.py +0 -0
  108. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/telegram_type.py +0 -0
  109. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/telegram/timeparam_type.py +0 -0
  110. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/term/__init__.py +0 -0
  111. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/term/accessory_state.py +0 -0
  112. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/term/connection_state.py +0 -0
  113. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/term/module_state.py +0 -0
  114. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/term/protocol_keys_config.py +0 -0
  115. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/term/status_message.py +0 -0
  116. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/term/telegram_display.py +0 -0
  117. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/models/write_config_type.py +0 -0
  118. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/__init__.py +0 -0
  119. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/__init__.py +0 -0
  120. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/actiontable_serializer.py +0 -0
  121. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/download_state_machine.py +0 -0
  122. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
  123. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +0 -0
  124. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +0 -0
  125. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +0 -0
  126. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/actiontable/serializer_protocol.py +0 -0
  127. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/__init__.py +0 -0
  128. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  129. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/actiontable/actiontable_download_service.py +0 -0
  130. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/actiontable/actiontable_list_service.py +0 -0
  131. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/actiontable/actiontable_show_service.py +0 -0
  132. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/actiontable/actiontable_upload_service.py +0 -0
  133. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  134. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  135. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  136. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  137. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  138. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_discover_service.py +0 -0
  139. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_event_list_service.py +0 -0
  140. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_event_raw_service.py +0 -0
  141. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_export_actiontable_service.py +0 -0
  142. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_export_service.py +0 -0
  143. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_output_service.py +0 -0
  144. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_receive_service.py +0 -0
  145. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  146. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/conbus/write_config_service.py +0 -0
  147. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/log_file_service.py +0 -0
  148. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/module_type_service.py +0 -0
  149. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/protocol/__init__.py +0 -0
  150. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/protocol/conbus_event_protocol.py +0 -0
  151. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/reverse_proxy_service.py +0 -0
  152. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/__init__.py +0 -0
  153. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/base_server_service.py +0 -0
  154. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/client_buffer_manager.py +0 -0
  155. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/cp20_server_service.py +0 -0
  156. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/device_service_factory.py +0 -0
  157. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/server_service.py +0 -0
  158. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/xp130_server_service.py +0 -0
  159. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/xp20_server_service.py +0 -0
  160. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/xp230_server_service.py +0 -0
  161. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/xp24_server_service.py +0 -0
  162. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/server/xp33_server_service.py +0 -0
  163. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/__init__.py +0 -0
  164. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  165. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  166. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  167. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  168. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  169. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_output_service.py +0 -0
  170. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_service.py +0 -0
  171. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/telegram/telegram_version_service.py +0 -0
  172. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/term/__init__.py +0 -0
  173. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/term/protocol_monitor_service.py +0 -0
  174. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/services/term/state_monitor_service.py +0 -0
  175. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/__init__.py +0 -0
  176. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/homekit.py +0 -0
  177. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/homekit.tcss +0 -0
  178. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/protocol.py +0 -0
  179. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/protocol.tcss +0 -0
  180. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/state.py +0 -0
  181. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/state.tcss +0 -0
  182. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/widgets/__init__.py +0 -0
  183. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/widgets/help_menu.py +0 -0
  184. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/widgets/modules_list.py +0 -0
  185. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/widgets/protocol_log.py +0 -0
  186. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/widgets/room_list.py +0 -0
  187. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/term/widgets/status_footer.py +0 -0
  188. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/__init__.py +0 -0
  189. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/checksum.py +0 -0
  190. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/dependencies.py +0 -0
  191. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/event_helper.py +0 -0
  192. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/logging.py +0 -0
  193. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/serialization.py +0 -0
  194. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/state_machine.py +0 -0
  195. {conson_xp-2.0.2 → conson_xp-2.0.4}/src/xp/utils/time_utils.py +0 -0
  196. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/.coverage +0 -0
  197. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/__init__.py +0 -0
  198. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/conftest.py +0 -0
  199. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/.coverage +0 -0
  200. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/__init__.py +0 -0
  201. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/telegram_test_data.py +0 -0
  202. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_actiontable_integration.py +0 -0
  203. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_api/.coverage +0 -0
  204. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_api/__init__.py +0 -0
  205. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_blink_integration.py +0 -0
  206. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_checksum_integration.py +0 -0
  207. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_conbus_blink_integration.py +0 -0
  208. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  209. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_conbus_receive_integration.py +0 -0
  210. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_discovery_integration.py +0 -0
  211. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_event_telegram_integration.py +0 -0
  212. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_link_number_integration.py +0 -0
  213. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_module_integration.py +0 -0
  214. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_output_integration.py +0 -0
  215. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_reverse_proxy_integration.py +0 -0
  216. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  217. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_term_logging_integration.py +0 -0
  218. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_version_integration.py +0 -0
  219. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_xp20_action_table_integration.py +0 -0
  220. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/integration/test_xp24_action_table_integration.py +0 -0
  221. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/__init__.py +0 -0
  222. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_api/__init__.py +0 -0
  223. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/__init__.py +0 -0
  224. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_click_tree.py +0 -0
  225. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  226. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  227. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_conbus_msactiontable_upload_commands.py +0 -0
  228. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  229. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_decorators.py +0 -0
  230. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_error_handlers.py +0 -0
  231. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_formatters.py +0 -0
  232. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  233. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  234. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_cli/test_term_commands.py +0 -0
  235. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_encoding/__init__.py +0 -0
  236. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  237. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/__init__.py +0 -0
  238. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_conbus.py +0 -0
  239. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  240. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_conbus_discover.py +0 -0
  241. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  242. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_event_telegram.py +0 -0
  243. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_log_entry.py +0 -0
  244. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_logger_config.py +0 -0
  245. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_module_type.py +0 -0
  246. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_reply_telegram.py +0 -0
  247. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_system_telegram.py +0 -0
  248. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  249. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_term/__init__.py +0 -0
  250. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_term/test_accessory_state.py +0 -0
  251. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_version_telegram.py +0 -0
  252. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_write_config_type.py +0 -0
  253. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  254. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  255. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_xp24_action_table_short_format.py +0 -0
  256. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  257. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/__init__.py +0 -0
  258. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_actiontable_download_service.py +0 -0
  259. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_actiontable_serializer.py +0 -0
  260. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_actiontable_service.py +0 -0
  261. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_actiontable_upload_service.py +0 -0
  262. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_base_server_service.py +0 -0
  263. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_blink_service.py +0 -0
  264. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_checksum_service.py +0 -0
  265. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_client_buffer_manager.py +0 -0
  266. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  267. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_event_list_service.py +0 -0
  268. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_event_protocol.py +0 -0
  269. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_event_raw_service.py +0 -0
  270. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_output_service.py +0 -0
  271. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_receive_service.py +0 -0
  272. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  273. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_conbus_scan_service.py +0 -0
  274. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_device_service_factory.py +0 -0
  275. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_discovery_service.py +0 -0
  276. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_homekit_service.py +0 -0
  277. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_log_file_service.py +0 -0
  278. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_module_type_service.py +0 -0
  279. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_protocol_monitor_service.py +0 -0
  280. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_server_service.py +0 -0
  281. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_state_monitor_service.py +0 -0
  282. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  283. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_telegram_output_service.py +0 -0
  284. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_telegram_service.py +0 -0
  285. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_version_service.py +0 -0
  286. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_xp20_action_table_serializer.py +0 -0
  287. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  288. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_xp24_action_table_serializer.py +0 -0
  289. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_xp24_action_table_service.py +0 -0
  290. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_xp33_action_table_serializer.py +0 -0
  291. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_xp33_short_format.py +0 -0
  292. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_services/test_xp_server_services.py +0 -0
  293. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_tui/__init__.py +0 -0
  294. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_tui/test_homekit_app.py +0 -0
  295. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_tui/test_protocol_log.py +0 -0
  296. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_tui/test_room_list.py +0 -0
  297. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_utils/__init__.py +0 -0
  298. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_utils/test_checksum.py +0 -0
  299. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_utils/test_event_helper.py +0 -0
  300. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_utils/test_logging.py +0 -0
  301. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_utils/test_serialization.py +0 -0
  302. {conson_xp-2.0.2 → conson_xp-2.0.4}/tests/unit/test_utils/test_time_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: conson-xp
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: XP Protocol Communication Tools
5
5
  Author-Email: ldvchosal <ldvchosal@github.com>
6
6
  License: MIT License
@@ -22,7 +22,7 @@ dependencies = [
22
22
  ]
23
23
  requires-python = ">=3.11"
24
24
  readme = "README.md"
25
- version = "2.0.2"
25
+ version = "2.0.4"
26
26
 
27
27
  [project.license]
28
28
  file = "LICENSE"
@@ -4,7 +4,7 @@ XP CLI tool for remote console bus operations.
4
4
  conson-xp package.
5
5
  """
6
6
 
7
- __version__ = "2.0.2"
7
+ __version__ = "2.0.4"
8
8
  __manufacturer__ = "salchichon"
9
9
  __model__ = "xp.cli"
10
10
  __serial__ = "2025.09.23.000"
@@ -14,25 +14,24 @@ from xp.services.conbus.conbus_raw_service import ConbusRawService
14
14
 
15
15
 
16
16
  @conbus.command("raw")
17
- @click.argument("raw_telegrams")
17
+ @click.argument("telegrams", nargs=-1, required=True)
18
18
  @click.pass_context
19
19
  @connection_command()
20
- def send_raw_telegrams(ctx: Context, raw_telegrams: str) -> None:
20
+ def send_raw_telegrams(ctx: Context, telegrams: tuple[str, ...]) -> None:
21
21
  r"""
22
22
  Send raw telegram sequence to Conbus server.
23
23
 
24
- Accepts a string containing one or more telegrams in format <...>.
25
- Multiple telegrams should be concatenated without separators.
24
+ Accepts one or more telegrams in format S2113010000F02D (without <> nor CHECKSUM) as separate arguments.
26
25
 
27
26
  Args:
28
27
  ctx: Click context object.
29
- raw_telegrams: Raw telegram string(s).
28
+ telegrams: Raw telegram string(s).
30
29
 
31
30
  Examples:
32
31
  \b
33
- xp conbus raw '<S2113010000F02D12>'
34
- xp conbus raw '<S2113010000F02D12><S2113010001F02D12><S2113010002F02D12>'
35
- xp conbus raw '<S0012345003F02D12FM>...<S0012345009F02D12FF>'
32
+ xp conbus raw 'S2113010000F02D'
33
+ xp conbus raw 'S2113010000F02D' 'S2113010001F02D'
34
+ xp conbus raw 'S0012345003F02D12F' 'S0012345009F02D12'
36
35
  """
37
36
  service: ConbusRawService = (
38
37
  ctx.obj.get("container").get_container().resolve(ConbusRawService)
@@ -62,8 +61,8 @@ def send_raw_telegrams(ctx: Context, raw_telegrams: str) -> None:
62
61
  service.on_progress.connect(on_progress)
63
62
  service.on_finish.connect(on_finish)
64
63
  # Setup
65
- service.send_raw_telegram(
66
- raw_input=raw_telegrams,
64
+ service.send_raw_telegrams(
65
+ telegrams=list(telegrams),
67
66
  timeout_seconds=5.0,
68
67
  )
69
68
  # Start (blocks until completion)
@@ -51,7 +51,7 @@ class ConbusRawService:
51
51
  self.conbus_protocol.on_timeout.connect(self.timeout)
52
52
  self.conbus_protocol.on_failed.connect(self.failed)
53
53
 
54
- self.raw_input: str = ""
54
+ self.telegrams: list[str] = []
55
55
  self.service_response: ConbusRawResponse = ConbusRawResponse(
56
56
  success=False,
57
57
  )
@@ -60,8 +60,11 @@ class ConbusRawService:
60
60
 
61
61
  def connection_made(self) -> None:
62
62
  """Handle connection established event."""
63
- self.logger.debug(f"Connection established, sending {self.raw_input}")
64
- self.conbus_protocol.send_raw_telegram(self.raw_input)
63
+ self.logger.debug(
64
+ f"Connection established, sending {len(self.telegrams)} telegrams"
65
+ )
66
+ for telegram in self.telegrams:
67
+ self.conbus_protocol.send_raw_telegram(telegram)
65
68
 
66
69
  def telegram_sent(self, telegram_sent: str) -> None:
67
70
  """
@@ -108,22 +111,22 @@ class ConbusRawService:
108
111
  self.service_response.error = message
109
112
  self.on_finish.emit(self.service_response)
110
113
 
111
- def send_raw_telegram(
114
+ def send_raw_telegrams(
112
115
  self,
113
- raw_input: str,
116
+ telegrams: list[str],
114
117
  timeout_seconds: Optional[float] = None,
115
118
  ) -> None:
116
119
  """
117
- Send a raw telegram string to the Conbus server.
120
+ Send raw telegrams to the Conbus server.
118
121
 
119
122
  Args:
120
- raw_input: Raw telegram string to send.
123
+ telegrams: List of raw telegram strings to send.
121
124
  timeout_seconds: Timeout in seconds.
122
125
  """
123
- self.logger.info("Starting send_raw_telegram")
126
+ self.logger.info(f"Starting send_raw_telegrams with {len(telegrams)} telegrams")
124
127
  if timeout_seconds:
125
128
  self.conbus_protocol.timeout_seconds = timeout_seconds
126
- self.raw_input = raw_input
129
+ self.telegrams = telegrams
127
130
 
128
131
  def set_timeout(self, timeout_seconds: float) -> None:
129
132
  """
@@ -151,7 +154,7 @@ class ConbusRawService:
151
154
  """
152
155
  # Reset state for singleton reuse
153
156
  self.service_response = ConbusRawResponse(success=False)
154
- self.raw_input = ""
157
+ self.telegrams = []
155
158
  return self
156
159
 
157
160
  def __exit__(
@@ -10,9 +10,18 @@ from pyhap.const import CATEGORY_LIGHTBULB, CATEGORY_OUTLET
10
10
 
11
11
  from xp.models.homekit.homekit_config import HomekitConfig
12
12
 
13
+ # Callback type: (accessory_name, is_on, brightness_or_none)
14
+ OnSetCallback = Callable[[str, bool, Optional[int]], None]
15
+
13
16
 
14
17
  class XPAccessory(Accessory):
15
- """Single accessory wrapping a Conbus output."""
18
+ """
19
+ Single accessory wrapping a Conbus output.
20
+
21
+ Attributes:
22
+ logger: Logger instance for this accessory.
23
+ current_brightness: Current brightness value 0-100.
24
+ """
16
25
 
17
26
  def __init__(
18
27
  self,
@@ -35,12 +44,19 @@ class XPAccessory(Accessory):
35
44
  super().__init__(driver._driver, display_name, aid=aid)
36
45
  self._hk_driver = driver
37
46
  self._accessory_id = name
47
+ self._is_dimmable = service_type == "dimminglight"
48
+ self._char_brightness: Optional[object] = None
49
+ self._current_brightness: int = 100
38
50
  self.logger = logging.getLogger(__name__)
39
51
 
40
- if service_type == "dimminglight":
52
+ if self._is_dimmable:
41
53
  self.category = CATEGORY_LIGHTBULB
42
54
  serv = self.add_preload_service("Lightbulb", chars=["On", "Brightness"])
43
- # Note: Brightness setter_callback deferred to future update
55
+ self._char_brightness = serv.configure_char(
56
+ "Brightness",
57
+ setter_callback=self._set_brightness,
58
+ value=self._current_brightness,
59
+ )
44
60
  elif service_type == "outlet":
45
61
  self.category = CATEGORY_OUTLET
46
62
  serv = self.add_preload_service("Outlet")
@@ -58,16 +74,36 @@ class XPAccessory(Accessory):
58
74
  value: True for on, False for off.
59
75
  """
60
76
  if self._hk_driver._on_set:
61
- self._hk_driver._on_set(self._accessory_id, value)
77
+ self._hk_driver._on_set(self._accessory_id, value, None)
78
+
79
+ def _set_brightness(self, value: int) -> None:
80
+ """
81
+ Handle HomeKit set brightness request.
82
+
83
+ Args:
84
+ value: Brightness value 0-100.
85
+ """
86
+ if self._hk_driver._on_set:
87
+ self._hk_driver._on_set(self._accessory_id, True, value)
88
+ self._current_brightness = value
62
89
 
63
- def update_state(self, is_on: bool) -> None:
90
+ def update_state(self, is_on: bool, brightness: Optional[int] = None) -> None:
64
91
  """
65
92
  Update accessory state from Conbus event.
66
93
 
67
94
  Args:
68
95
  is_on: True if accessory is on, False otherwise.
96
+ brightness: Optional brightness value 0-100.
69
97
  """
70
98
  self._char_on.set_value(is_on)
99
+ if brightness is not None and self._char_brightness:
100
+ self._char_brightness.set_value(brightness) # type: ignore[attr-defined]
101
+ self._current_brightness = brightness
102
+
103
+ @property
104
+ def current_brightness(self) -> int:
105
+ """Get current brightness value."""
106
+ return self._current_brightness
71
107
 
72
108
 
73
109
  class HomekitAccessoryDriver:
@@ -84,14 +120,15 @@ class HomekitAccessoryDriver:
84
120
  self._homekit_config = homekit_config
85
121
  self._driver: Optional[AccessoryDriver] = None
86
122
  self._accessories: Dict[str, XPAccessory] = {}
87
- self._on_set: Optional[Callable[[str, bool], None]] = None
123
+ self._on_set: Optional[OnSetCallback] = None
88
124
 
89
- def set_callback(self, on_set: Callable[[str, bool], None]) -> None:
125
+ def set_callback(self, on_set: OnSetCallback) -> None:
90
126
  """
91
127
  Set callback for HomeKit set events.
92
128
 
93
129
  Args:
94
- on_set: Callback(accessory_name, is_on) called when HomeKit app toggles.
130
+ on_set: Callback(accessory_name, is_on, brightness) called when HomeKit app changes state.
131
+ brightness is None for on/off only, or 0-100 for dimming.
95
132
  """
96
133
  self._on_set = on_set
97
134
 
@@ -157,15 +194,34 @@ class HomekitAccessoryDriver:
157
194
  except Exception as e:
158
195
  self.logger.error(f"Error stopping AccessoryDriver: {e}", exc_info=True)
159
196
 
160
- def update_state(self, accessory_name: str, is_on: bool) -> None:
197
+ def update_state(
198
+ self, accessory_name: str, is_on: bool, brightness: Optional[int] = None
199
+ ) -> None:
161
200
  """
162
201
  Update accessory state from Conbus event.
163
202
 
164
203
  Args:
165
204
  accessory_name: Accessory name to update.
166
205
  is_on: True if accessory is on, False otherwise.
206
+ brightness: Optional brightness value 0-100.
167
207
  """
168
- if acc := self._accessories.get(accessory_name):
169
- acc.update_state(is_on)
208
+ acc = self._accessories.get(accessory_name)
209
+ if acc:
210
+ acc.update_state(is_on, brightness)
170
211
  else:
171
212
  self.logger.warning(f"Unknown accessory name: {accessory_name}")
213
+
214
+ def get_brightness(self, accessory_name: str) -> int:
215
+ """
216
+ Get current brightness for an accessory.
217
+
218
+ Args:
219
+ accessory_name: Accessory name.
220
+
221
+ Returns:
222
+ Current brightness 0-100, defaults to 100 if not found.
223
+ """
224
+ acc = self._accessories.get(accessory_name)
225
+ if acc:
226
+ return acc.current_brightness
227
+ return 100
@@ -300,23 +300,82 @@ class HomekitService:
300
300
  await self._accessory_driver.stop()
301
301
  self.cleanup()
302
302
 
303
- def _on_homekit_set(self, accessory_name: str, is_on: bool) -> None:
303
+ def _on_homekit_set(
304
+ self, accessory_name: str, is_on: bool, brightness: Optional[int]
305
+ ) -> None:
304
306
  """
305
- Handle HomeKit app toggle request.
307
+ Handle HomeKit app set request (on/off or brightness).
306
308
 
307
309
  Args:
308
310
  accessory_name: Accessory name from HomeKit.
309
311
  is_on: True for on, False for off.
312
+ brightness: Brightness value 0-100, or None for on/off only.
310
313
  """
311
314
  config = self._find_accessory_config(accessory_name)
312
- if config:
315
+ if not config:
316
+ self.logger.warning(f"No config found for accessory: {accessory_name}")
317
+ return
318
+
319
+ if brightness is not None:
320
+ # Handle brightness change
321
+ self._handle_brightness_change(accessory_name, config, brightness)
322
+ else:
323
+ # Handle on/off toggle
313
324
  action = config.on_action if is_on else config.off_action
314
325
  self.send_action(action)
315
326
  self.on_status_message.emit(
316
327
  f"HomeKit: {accessory_name} {'ON' if is_on else 'OFF'}"
317
328
  )
329
+
330
+ def _handle_brightness_change(
331
+ self,
332
+ accessory_name: str,
333
+ config: "HomekitAccessoryConfig",
334
+ target_brightness: int,
335
+ ) -> None:
336
+ """
337
+ Handle brightness change by sending dimup/dimdown actions.
338
+
339
+ Calculates delta from current brightness and sends appropriate
340
+ number of LEVELINC or LEVELDEC commands (step = 10%).
341
+
342
+ Args:
343
+ accessory_name: Accessory name.
344
+ config: Accessory configuration.
345
+ target_brightness: Target brightness 0-100.
346
+ """
347
+ current = self._accessory_driver.get_brightness(accessory_name)
348
+ delta = target_brightness - current
349
+
350
+ if delta == 0:
351
+ return
352
+
353
+ # Determine action and steps (10% per step)
354
+ step_size = 10
355
+ steps = abs(delta) // step_size
356
+
357
+ if delta > 0:
358
+ # Increase brightness
359
+ if not config.dimup_action:
360
+ self.logger.warning(f"No dimup_action for {accessory_name}")
361
+ return
362
+ action = config.dimup_action
363
+ direction = "+"
318
364
  else:
319
- self.logger.warning(f"No config found for accessory: {accessory_name}")
365
+ # Decrease brightness
366
+ if not config.dimdown_action:
367
+ self.logger.warning(f"No dimdown_action for {accessory_name}")
368
+ return
369
+ action = config.dimdown_action
370
+ direction = "-"
371
+
372
+ # Send action for each step
373
+ for _ in range(steps):
374
+ self.send_action(action)
375
+
376
+ self.on_status_message.emit(
377
+ f"HomeKit: {accessory_name} {current}% → {target_brightness}% ({direction}{steps * step_size}%)"
378
+ )
320
379
 
321
380
  def send_action(self, action: str) -> None:
322
381
  """
@@ -59,12 +59,12 @@ class TestConbusRawIntegration:
59
59
  mock_service.on_progress.connect.side_effect = mock_on_progress_connect
60
60
 
61
61
  # Make the mock service call the callback immediately
62
- def mock_send_raw_telegram(raw_input, timeout_seconds=None):
62
+ def mock_send_raw_telegrams(telegrams, timeout_seconds=None):
63
63
  """
64
64
  Test helper function.
65
65
 
66
66
  Args:
67
- raw_input: Raw telegram input.
67
+ telegrams: List of raw telegram inputs.
68
68
  timeout_seconds: Timeout in seconds.
69
69
  """
70
70
  # Call the on_finish callback that was connected
@@ -76,7 +76,7 @@ class TestConbusRawIntegration:
76
76
  # Do nothing in test
77
77
  pass
78
78
 
79
- mock_service.send_raw_telegram.side_effect = mock_send_raw_telegram
79
+ mock_service.send_raw_telegrams.side_effect = mock_send_raw_telegrams
80
80
  mock_service.start_reactor.side_effect = mock_start_reactor
81
81
 
82
82
  # Mock the container
@@ -92,7 +92,7 @@ class TestConbusRawIntegration:
92
92
  assert result.exit_code == 0
93
93
  assert '"success": true' in result.output
94
94
  assert '"received_telegrams": [' in result.output
95
- mock_service.send_raw_telegram.assert_called_once()
95
+ mock_service.send_raw_telegrams.assert_called_once()
96
96
 
97
97
  def test_conbus_raw_multiple_telegrams(self):
98
98
  """Test conbus raw command with multiple telegrams."""
@@ -137,12 +137,12 @@ class TestConbusRawIntegration:
137
137
  mock_service.on_progress.connect.side_effect = mock_on_progress_connect
138
138
 
139
139
  # Make the mock service call the callback immediately
140
- def mock_send_raw_telegram(raw_input, timeout_seconds=None):
140
+ def mock_send_raw_telegrams(telegrams, timeout_seconds=None):
141
141
  """
142
142
  Test helper function.
143
143
 
144
144
  Args:
145
- raw_input: Raw telegram input.
145
+ telegrams: List of raw telegram inputs.
146
146
  timeout_seconds: Timeout in seconds.
147
147
  """
148
148
  # Simulate progress callbacks for each received telegram
@@ -159,23 +159,30 @@ class TestConbusRawIntegration:
159
159
  # Do nothing in test
160
160
  pass
161
161
 
162
- mock_service.send_raw_telegram.side_effect = mock_send_raw_telegram
162
+ mock_service.send_raw_telegrams.side_effect = mock_send_raw_telegrams
163
163
  mock_service.start_reactor.side_effect = mock_start_reactor
164
164
 
165
165
  # Mock the container
166
166
  mock_container = MagicMock()
167
167
  mock_container.get_container().resolve.return_value = mock_service
168
168
 
169
- raw_input = "<S2113010000F02D12><S2113010001F02D12><S2113010002F02D12>"
170
169
  result = self.runner.invoke(
171
- cli, ["conbus", "raw", raw_input], obj={"container": mock_container}
170
+ cli,
171
+ [
172
+ "conbus",
173
+ "raw",
174
+ "<S2113010000F02D12>",
175
+ "<S2113010001F02D12>",
176
+ "<S2113010002F02D12>",
177
+ ],
178
+ obj={"container": mock_container},
172
179
  )
173
180
 
174
181
  assert result.exit_code == 0
175
182
  assert "<R2113010000F02D12>" in result.output
176
183
  assert "<R2113010001F02D12>" in result.output
177
184
  assert "<S2113010002F02D12>" in result.output
178
- mock_service.send_raw_telegram.assert_called_once()
185
+ mock_service.send_raw_telegrams.assert_called_once()
179
186
 
180
187
  def test_conbus_raw_connection_error(self):
181
188
  """Test conbus raw command with connection error."""
@@ -212,12 +219,12 @@ class TestConbusRawIntegration:
212
219
  mock_service.on_progress.connect.side_effect = mock_on_progress_connect
213
220
 
214
221
  # Make the mock service call the callback immediately
215
- def mock_send_raw_telegram(raw_input, timeout_seconds=None):
222
+ def mock_send_raw_telegrams(telegrams, timeout_seconds=None):
216
223
  """
217
224
  Test helper function.
218
225
 
219
226
  Args:
220
- raw_input: Raw telegram input.
227
+ telegrams: List of raw telegram inputs.
221
228
  timeout_seconds: Timeout in seconds.
222
229
  """
223
230
  # Call the on_finish callback that was connected
@@ -229,7 +236,7 @@ class TestConbusRawIntegration:
229
236
  # Do nothing in test
230
237
  pass
231
238
 
232
- mock_service.send_raw_telegram.side_effect = mock_send_raw_telegram
239
+ mock_service.send_raw_telegrams.side_effect = mock_send_raw_telegrams
233
240
  mock_service.start_reactor.side_effect = mock_start_reactor
234
241
 
235
242
  # Mock the container
@@ -285,12 +292,12 @@ class TestConbusRawIntegration:
285
292
  mock_service.on_progress.connect.side_effect = mock_on_progress_connect
286
293
 
287
294
  # Make the mock service call the callback immediately
288
- def mock_send_raw_telegram(raw_input, timeout_seconds=None):
295
+ def mock_send_raw_telegrams(telegrams, timeout_seconds=None):
289
296
  """
290
297
  Test helper function.
291
298
 
292
299
  Args:
293
- raw_input: Raw telegram input.
300
+ telegrams: List of raw telegram inputs.
294
301
  timeout_seconds: Timeout in seconds.
295
302
  """
296
303
  # Call the on_finish callback that was connected
@@ -302,7 +309,7 @@ class TestConbusRawIntegration:
302
309
  # Do nothing in test
303
310
  pass
304
311
 
305
- mock_service.send_raw_telegram.side_effect = mock_send_raw_telegram
312
+ mock_service.send_raw_telegrams.side_effect = mock_send_raw_telegrams
306
313
  mock_service.start_reactor.side_effect = mock_start_reactor
307
314
 
308
315
  # Mock the container
@@ -331,14 +338,14 @@ class TestConbusRawIntegration:
331
338
  output = result.output
332
339
 
333
340
  assert "Send raw telegram sequence to Conbus server" in output
334
- assert "RAW_TELEGRAMS" in output
341
+ assert "TELEGRAMS" in output
335
342
 
336
343
  def test_conbus_raw_missing_arguments(self):
337
344
  """Test conbus raw command with missing arguments."""
338
345
  result = self.runner.invoke(cli, ["conbus", "raw"])
339
346
 
340
347
  assert result.exit_code != 0
341
- assert "Usage: cli conbus raw [OPTIONS] RAW_TELEGRAMS" in result.output
348
+ assert "Usage: cli conbus raw [OPTIONS] TELEGRAMS" in result.output
342
349
 
343
350
  def test_conbus_raw_service_exception(self):
344
351
  """Test conbus raw command when service raises exception."""
@@ -347,8 +354,8 @@ class TestConbusRawIntegration:
347
354
  mock_service.__enter__.return_value = mock_service
348
355
  mock_service.__exit__.return_value = None
349
356
 
350
- # Make the service raise an exception when send_raw_telegram is called
351
- mock_service.send_raw_telegram.side_effect = Exception("Service error")
357
+ # Make the service raise an exception when send_raw_telegrams is called
358
+ mock_service.send_raw_telegrams.side_effect = Exception("Service error")
352
359
 
353
360
  # Mock the container
354
361
  mock_container = MagicMock()
@@ -37,7 +37,7 @@ class TestConbusRawService:
37
37
 
38
38
  def test_service_initialization(self, service, mock_conbus_protocol):
39
39
  """Test service can be initialized with required dependencies."""
40
- assert service.raw_input == ""
40
+ assert service.telegrams == []
41
41
  assert service.service_response.success is False
42
42
  # Verify signals were connected
43
43
  assert mock_conbus_protocol.on_connection_made.connect.called
@@ -172,7 +172,7 @@ class TestConbusRawService:
172
172
  def test_context_manager_enter_resets_state(self, service):
173
173
  """Test __enter__ resets state for singleton reuse."""
174
174
  # Set some state
175
- service.raw_input = "test"
175
+ service.telegrams = ["test"]
176
176
  service.service_response.success = True
177
177
 
178
178
  # Enter context
@@ -180,7 +180,7 @@ class TestConbusRawService:
180
180
 
181
181
  # Verify state is reset
182
182
  assert result is service
183
- assert service.raw_input == ""
183
+ assert service.telegrams == []
184
184
  assert service.service_response.success is False
185
185
 
186
186
  def test_context_manager_exit_disconnects_signals(
@@ -208,9 +208,9 @@ class TestConbusRawService:
208
208
  mock_conbus_protocol.stop_reactor.assert_called_once()
209
209
 
210
210
  def test_connection_made(self, service, mock_conbus_protocol):
211
- """Test connection_made sends raw telegram."""
212
- service.raw_input = "<S2113010000F02D12>"
211
+ """Test connection_made sends raw telegrams."""
212
+ service.telegrams = ["S2113010000F02D12", "S2113010001F02D12"]
213
213
  service.connection_made()
214
- mock_conbus_protocol.send_raw_telegram.assert_called_once_with(
215
- "<S2113010000F02D12>"
216
- )
214
+ assert mock_conbus_protocol.send_raw_telegram.call_count == 2
215
+ mock_conbus_protocol.send_raw_telegram.assert_any_call("S2113010000F02D12")
216
+ mock_conbus_protocol.send_raw_telegram.assert_any_call("S2113010001F02D12")
File without changes
File without changes