conson-xp 1.23.0__tar.gz → 1.24.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. {conson_xp-1.23.0 → conson_xp-1.24.0}/PKG-INFO +1 -1
  2. {conson_xp-1.23.0 → conson_xp-1.24.0}/pyproject.toml +1 -1
  3. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/__init__.py +1 -1
  4. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +7 -2
  5. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +5 -2
  6. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_discover_service.py +61 -53
  7. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_receive_service.py +30 -25
  8. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/protocol.yml +14 -14
  9. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/widgets/protocol_log.py +2 -39
  10. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_receive_service.py +22 -43
  11. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_tui/test_protocol_log.py +0 -1
  12. {conson_xp-1.23.0 → conson_xp-1.24.0}/LICENSE +0 -0
  13. {conson_xp-1.23.0 → conson_xp-1.24.0}/README.md +0 -0
  14. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/__init__.py +0 -0
  15. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/__main__.py +0 -0
  16. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/__init__.py +0 -0
  17. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
  18. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
  19. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  20. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  21. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  22. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  23. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  24. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  25. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_event_commands.py +0 -0
  26. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  27. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  28. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_modulenumber_commands.py +0 -0
  29. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +0 -0
  30. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  31. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
  32. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  33. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/file_commands.py +0 -0
  34. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
  35. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
  36. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
  37. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/module_commands.py +0 -0
  38. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  39. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/server/__init__.py +0 -0
  40. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/server/server_commands.py +0 -0
  41. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
  42. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
  43. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  44. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  45. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  46. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  47. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  48. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  49. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/term/__init__.py +0 -0
  50. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/term/term.py +0 -0
  51. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/commands/term/term_commands.py +0 -0
  52. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/main.py +0 -0
  53. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/__init__.py +0 -0
  54. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/click_tree.py +0 -0
  55. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  56. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/decorators.py +0 -0
  57. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/error_handlers.py +0 -0
  58. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/formatters.py +0 -0
  59. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/module_type_choice.py +0 -0
  60. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/serial_number_type.py +0 -0
  61. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/system_function_choice.py +0 -0
  62. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/cli/utils/xp_module_type.py +0 -0
  63. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/connection/__init__.py +0 -0
  64. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/connection/exceptions.py +0 -0
  65. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/__init__.py +0 -0
  66. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/actiontable/__init__.py +0 -0
  67. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/actiontable/actiontable.py +0 -0
  68. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  69. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  70. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  71. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/__init__.py +0 -0
  72. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus.py +0 -0
  73. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  74. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_blink.py +0 -0
  75. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
  76. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  77. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_custom.py +0 -0
  78. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  79. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_discover.py +0 -0
  80. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_event_list.py +0 -0
  81. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_event_raw.py +0 -0
  82. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  83. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  84. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_logger_config.py +0 -0
  85. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_output.py +0 -0
  86. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_raw.py +0 -0
  87. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_receive.py +0 -0
  88. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  89. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/homekit/__init__.py +0 -0
  90. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
  91. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/homekit/homekit_config.py +0 -0
  92. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
  93. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/log_entry.py +0 -0
  94. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/protocol/__init__.py +0 -0
  95. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
  96. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/response.py +0 -0
  97. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/__init__.py +0 -0
  98. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/action_type.py +0 -0
  99. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/datapoint_type.py +0 -0
  100. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/event_telegram.py +0 -0
  101. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/event_type.py +0 -0
  102. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/input_action_type.py +0 -0
  103. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/input_type.py +0 -0
  104. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/module_type.py +0 -0
  105. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/module_type_code.py +0 -0
  106. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/output_telegram.py +0 -0
  107. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/reply_telegram.py +0 -0
  108. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/system_function.py +0 -0
  109. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/system_telegram.py +0 -0
  110. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/telegram.py +0 -0
  111. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/telegram_type.py +0 -0
  112. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/telegram/timeparam_type.py +0 -0
  113. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/term/__init__.py +0 -0
  114. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/term/connection_state.py +0 -0
  115. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/term/protocol_keys_config.py +0 -0
  116. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/term/status_message.py +0 -0
  117. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/models/write_config_type.py +0 -0
  118. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/__init__.py +0 -0
  119. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/actiontable/__init__.py +0 -0
  120. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/actiontable/actiontable_serializer.py +0 -0
  121. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
  122. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +0 -0
  123. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +0 -0
  124. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +0 -0
  125. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/__init__.py +0 -0
  126. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  127. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_download_service.py +0 -0
  128. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_list_service.py +0 -0
  129. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_show_service.py +0 -0
  130. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_upload_service.py +0 -0
  131. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +0 -0
  132. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  133. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  134. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  135. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  136. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  137. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_event_list_service.py +0 -0
  138. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_event_raw_service.py +0 -0
  139. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
  140. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
  141. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  142. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/conbus/write_config_service.py +0 -0
  143. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/__init__.py +0 -0
  144. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
  145. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
  146. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
  147. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
  148. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
  149. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
  150. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
  151. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
  152. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
  153. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
  154. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
  155. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
  156. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_service.py +0 -0
  157. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/log_file_service.py +0 -0
  158. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/module_type_service.py +0 -0
  159. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/protocol/__init__.py +0 -0
  160. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/protocol/conbus_event_protocol.py +0 -0
  161. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/protocol/conbus_protocol.py +0 -0
  162. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/protocol/protocol_factory.py +0 -0
  163. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
  164. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/reverse_proxy_service.py +0 -0
  165. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/__init__.py +0 -0
  166. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/base_server_service.py +0 -0
  167. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/cp20_server_service.py +0 -0
  168. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/device_service_factory.py +0 -0
  169. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/server_service.py +0 -0
  170. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/xp130_server_service.py +0 -0
  171. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/xp20_server_service.py +0 -0
  172. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/xp230_server_service.py +0 -0
  173. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/xp24_server_service.py +0 -0
  174. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/server/xp33_server_service.py +0 -0
  175. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/__init__.py +0 -0
  176. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  177. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  178. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  179. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  180. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  181. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
  182. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_service.py +0 -0
  183. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
  184. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/__init__.py +0 -0
  185. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/protocol.py +0 -0
  186. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/protocol.tcss +0 -0
  187. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/widgets/__init__.py +0 -0
  188. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/widgets/help_menu.py +0 -0
  189. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/term/widgets/status_footer.py +0 -0
  190. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/__init__.py +0 -0
  191. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/checksum.py +0 -0
  192. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/dependencies.py +0 -0
  193. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/event_helper.py +0 -0
  194. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/logging.py +0 -0
  195. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/serialization.py +0 -0
  196. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/state_machine.py +0 -0
  197. {conson_xp-1.23.0 → conson_xp-1.24.0}/src/xp/utils/time_utils.py +0 -0
  198. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/.coverage +0 -0
  199. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/__init__.py +0 -0
  200. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/conftest.py +0 -0
  201. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/.coverage +0 -0
  202. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/__init__.py +0 -0
  203. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/telegram_test_data.py +0 -0
  204. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_actiontable_integration.py +0 -0
  205. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_api/.coverage +0 -0
  206. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_api/__init__.py +0 -0
  207. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_blink_integration.py +0 -0
  208. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_checksum_integration.py +0 -0
  209. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_conbus_blink_integration.py +0 -0
  210. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  211. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_conbus_raw_integration.py +0 -0
  212. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_conbus_receive_integration.py +0 -0
  213. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_discovery_integration.py +0 -0
  214. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_event_telegram_integration.py +0 -0
  215. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_homekit_config_integration.py +0 -0
  216. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_link_number_integration.py +0 -0
  217. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_module_integration.py +0 -0
  218. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_output_integration.py +0 -0
  219. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
  220. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  221. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_term_logging_integration.py +0 -0
  222. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_version_integration.py +0 -0
  223. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_xp20_action_table_integration.py +0 -0
  224. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/integration/test_xp24_action_table_integration.py +0 -0
  225. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/__init__.py +0 -0
  226. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_api/__init__.py +0 -0
  227. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/__init__.py +0 -0
  228. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_click_tree.py +0 -0
  229. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  230. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  231. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  232. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_decorators.py +0 -0
  233. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
  234. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_formatters.py +0 -0
  235. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  236. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  237. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_term_commands.py +0 -0
  238. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_connection/__init__.py +0 -0
  239. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_connection/test_connection_init.py +0 -0
  240. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_connection/test_exceptions.py +0 -0
  241. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_encoding/__init__.py +0 -0
  242. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  243. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/__init__.py +0 -0
  244. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus.py +0 -0
  245. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  246. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
  247. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  248. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_event_telegram.py +0 -0
  249. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_log_entry.py +0 -0
  250. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_logger_config.py +0 -0
  251. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_module_type.py +0 -0
  252. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
  253. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_system_telegram.py +0 -0
  254. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  255. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_version_telegram.py +0 -0
  256. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_write_config_type.py +0 -0
  257. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  258. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  259. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  260. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/__init__.py +0 -0
  261. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_actiontable_serializer.py +0 -0
  262. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
  263. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_actiontable_upload_service.py +0 -0
  264. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_base_server_service.py +0 -0
  265. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_blink_service.py +0 -0
  266. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_checksum_service.py +0 -0
  267. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  268. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_event_list_service.py +0 -0
  269. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_event_raw_service.py +0 -0
  270. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
  271. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  272. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_device_service_factory.py +0 -0
  273. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_discovery_service.py +0 -0
  274. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
  275. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
  276. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
  277. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_services.py +0 -0
  278. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_log_file_service.py +0 -0
  279. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_module_type_service.py +0 -0
  280. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_protocol.py +0 -0
  281. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_server_service.py +0 -0
  282. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  283. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
  284. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_telegram_service.py +0 -0
  285. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_version_service.py +0 -0
  286. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +0 -0
  287. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  288. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +0 -0
  289. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp24_action_table_service.py +0 -0
  290. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +0 -0
  291. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
  292. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_tui/__init__.py +0 -0
  293. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_utils/__init__.py +0 -0
  294. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_checksum.py +0 -0
  295. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_event_helper.py +0 -0
  296. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_logging.py +0 -0
  297. {conson_xp-1.23.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_serialization.py +0 -0
  298. {conson_xp-1.23.0 → conson_xp-1.24.0}/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: 1.23.0
3
+ Version: 1.24.0
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 = "1.23.0"
25
+ version = "1.24.0"
26
26
 
27
27
  [project.license]
28
28
  file = "LICENSE"
@@ -3,7 +3,7 @@
3
3
  conson-xp package.
4
4
  """
5
5
 
6
- __version__ = "1.23.0"
6
+ __version__ = "1.24.0"
7
7
  __manufacturer__ = "salchichon"
8
8
  __model__ = "xp.cli"
9
9
  __serial__ = "2025.09.23.000"
@@ -36,6 +36,7 @@ def send_discover_telegram(ctx: click.Context) -> None:
36
36
  discovered_devices: Discover response with all found devices.
37
37
  """
38
38
  click.echo(json.dumps(discovered_devices.to_dict(), indent=2))
39
+ service.stop_reactor()
39
40
 
40
41
  def on_device_discovered(discovered_device: DiscoveredDevice) -> None:
41
42
  """Handle discovery of sa single module.
@@ -57,5 +58,9 @@ def send_discover_telegram(ctx: click.Context) -> None:
57
58
  service: ConbusDiscoverService = (
58
59
  ctx.obj.get("container").get_container().resolve(ConbusDiscoverService)
59
60
  )
60
- service.run(progress, on_device_discovered, on_finish, 5)
61
- service.start_reactor()
61
+ with service:
62
+ service.on_progress.connect(progress)
63
+ service.on_device_discovered.connect(on_device_discovered)
64
+ service.on_finish.connect(on_finish)
65
+ service.set_timeout(5)
66
+ service.start_reactor()
@@ -43,8 +43,9 @@ def receive_telegrams(ctx: Context, timeout: float) -> None:
43
43
  response_received: Receive response object with telegrams.
44
44
  """
45
45
  click.echo(json.dumps(response_received.to_dict(), indent=2))
46
+ service.stop_reactor()
46
47
 
47
- def progress(telegram_received: str) -> None:
48
+ def on_progress(telegram_received: str) -> None:
48
49
  """Handle progress updates during telegram receive operation.
49
50
 
50
51
  Args:
@@ -56,5 +57,7 @@ def receive_telegrams(ctx: Context, timeout: float) -> None:
56
57
  ctx.obj.get("container").get_container().resolve(ConbusReceiveService)
57
58
  )
58
59
  with service:
59
- service.init(progress, on_finish, timeout)
60
+ service.on_progress.connect(on_progress)
61
+ service.on_finish.connect(on_finish)
62
+ service.set_timeout(timeout)
60
63
  service.start_reactor()
@@ -4,8 +4,11 @@ This service implements a TCP client that connects to Conbus servers and sends
4
4
  discover telegrams to find modules on the network.
5
5
  """
6
6
 
7
+ import asyncio
7
8
  import logging
8
- from typing import Callable, Optional
9
+ from typing import Any, Optional
10
+
11
+ from psygnal import Signal
9
12
 
10
13
  from xp.models import ConbusDiscoverResponse
11
14
  from xp.models.conbus.conbus_discover import DiscoveredDevice
@@ -26,9 +29,15 @@ class ConbusDiscoverService:
26
29
 
27
30
  Attributes:
28
31
  conbus_protocol: Protocol instance for Conbus communication.
32
+ on_progress: Signal emitted when discovery progress is made (with serial number).
33
+ on_finish: Signal emitted when discovery finishes (with result).
34
+ on_device_discovered: Signal emitted when a device is discovered (with device info).
29
35
  """
30
36
 
31
37
  conbus_protocol: ConbusEventProtocol
38
+ on_progress: Signal = Signal(str)
39
+ on_finish: Signal = Signal(DiscoveredDevice)
40
+ on_device_discovered: Signal = Signal(ConbusDiscoverResponse)
32
41
 
33
42
  def __init__(self, conbus_protocol: ConbusEventProtocol) -> None:
34
43
  """Initialize the Conbus discover service.
@@ -36,12 +45,6 @@ class ConbusDiscoverService:
36
45
  Args:
37
46
  conbus_protocol: ConbusProtocol.
38
47
  """
39
- self.progress_callback: Optional[Callable[[str], None]] = None
40
- self.device_discover_callback: Optional[Callable[[DiscoveredDevice], None]] = (
41
- None
42
- )
43
- self.finish_callback: Optional[Callable[[ConbusDiscoverResponse], None]] = None
44
-
45
48
  self.conbus_protocol: ConbusEventProtocol = conbus_protocol
46
49
  self.conbus_protocol.on_connection_made.connect(self.connection_made)
47
50
  self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
@@ -135,9 +138,7 @@ class ConbusDiscoverService:
135
138
  "module_type_name": None,
136
139
  }
137
140
  self.discovered_device_result.discovered_devices.append(device)
138
-
139
- if self.device_discover_callback:
140
- self.device_discover_callback(device)
141
+ self.on_device_discovered.emit(device)
141
142
 
142
143
  # Send READ_DATAPOINT telegram to query module type
143
144
  self.logger.debug(f"Sending module type query for {serial_number}")
@@ -147,8 +148,7 @@ class ConbusDiscoverService:
147
148
  system_function=SystemFunction.READ_DATAPOINT,
148
149
  data_value=DataPointType.MODULE_TYPE.value,
149
150
  )
150
- if self.progress_callback:
151
- self.progress_callback(serial_number)
151
+ self.on_progress.emit(serial_number)
152
152
 
153
153
  def handle_module_type_code_response(
154
154
  self, serial_number: str, module_type_code: str
@@ -194,8 +194,7 @@ class ConbusDiscoverService:
194
194
  device["module_type_code"] = code
195
195
  device["module_type_name"] = module_type_name
196
196
 
197
- if self.device_discover_callback:
198
- self.device_discover_callback(device)
197
+ self.on_device_discovered.emit(device)
199
198
 
200
199
  self.logger.debug(
201
200
  f"Updated device {serial_number} with module_type {module_type_name}"
@@ -231,9 +230,7 @@ class ConbusDiscoverService:
231
230
  self.logger.debug(
232
231
  f"Updated device {serial_number} with module_type {module_type}"
233
232
  )
234
- if self.device_discover_callback:
235
- self.device_discover_callback(device)
236
-
233
+ self.on_device_discovered.emit(device)
237
234
  break
238
235
 
239
236
  self.conbus_protocol.send_telegram(
@@ -249,10 +246,7 @@ class ConbusDiscoverService:
249
246
  self.logger.info("Discovery stopped after: %ss", timeout)
250
247
  self.discovered_device_result.success = False
251
248
  self.discovered_device_result.error = "Discovered device timeout"
252
- if self.finish_callback:
253
- self.finish_callback(self.discovered_device_result)
254
-
255
- self.stop_reactor()
249
+ self.on_finish.emit(self.discovered_device_result)
256
250
 
257
251
  def failed(self, message: str) -> None:
258
252
  """Handle failed connection event.
@@ -263,50 +257,64 @@ class ConbusDiscoverService:
263
257
  self.logger.debug(f"Failed: {message}")
264
258
  self.discovered_device_result.success = False
265
259
  self.discovered_device_result.error = message
266
- if self.finish_callback:
267
- self.finish_callback(self.discovered_device_result)
268
-
269
- self.stop_reactor()
260
+ self.on_finish.emit(self.discovered_device_result)
270
261
 
271
262
  def succeed(self) -> None:
272
263
  """Handle discovered device success event."""
273
264
  self.logger.debug("Succeed")
274
265
  self.discovered_device_result.success = True
275
266
  self.discovered_device_result.error = None
276
- if self.finish_callback:
277
- self.finish_callback(self.discovered_device_result)
267
+ self.on_finish.emit(self.discovered_device_result)
278
268
 
279
- self.stop_reactor()
269
+ def set_timeout(self, timeout_seconds: float) -> None:
270
+ """Setup callbacks and timeout for receiving telegrams.
280
271
 
281
- def stop_reactor(self) -> None:
282
- """Stop reactor."""
283
- self.logger.info("Stopping reactor")
284
- self.conbus_protocol.stop_reactor()
285
-
286
- def start_reactor(self) -> None:
287
- """Start reactor."""
288
- self.logger.info("Starting reactor")
289
- self.conbus_protocol.start_reactor()
272
+ Args:
273
+ timeout_seconds: Optional timeout in seconds.
274
+ """
275
+ self.logger.debug("Set timeout")
276
+ self.conbus_protocol.timeout_seconds = timeout_seconds
290
277
 
291
- def run(
278
+ def set_event_loop(
292
279
  self,
293
- progress_callback: Callable[[str], None],
294
- device_discover_callback: Callable[[DiscoveredDevice], None],
295
- finish_callback: Callable[[ConbusDiscoverResponse], None],
296
- timeout_seconds: Optional[float] = None,
280
+ event_loop: asyncio.AbstractEventLoop,
297
281
  ) -> None:
298
- """Run reactor in dedicated thread with its own event loop.
282
+ """Setup callbacks and timeout for receiving telegrams.
299
283
 
300
284
  Args:
301
- progress_callback: Callback for each discovered device.
302
- device_discover_callback: Callback for each discovered device.
303
- finish_callback: Callback when discovery completes.
304
- timeout_seconds: Optional timeout in seconds.
285
+ event_loop: Optional event loop to use for async operations.
305
286
  """
306
- self.logger.info("Starting discovery")
287
+ self.logger.debug("Set eventloop")
288
+ self.conbus_protocol.set_event_loop(event_loop)
307
289
 
308
- if timeout_seconds:
309
- self.conbus_protocol.timeout_seconds = timeout_seconds
310
- self.progress_callback = progress_callback
311
- self.device_discover_callback = device_discover_callback
312
- self.finish_callback = finish_callback
290
+ def start_reactor(self) -> None:
291
+ """Start the reactor."""
292
+ self.conbus_protocol.start_reactor()
293
+
294
+ def stop_reactor(self) -> None:
295
+ """Start the reactor."""
296
+ self.conbus_protocol.stop_reactor()
297
+
298
+ def __enter__(self) -> "ConbusDiscoverService":
299
+ """Enter context manager.
300
+
301
+ Returns:
302
+ Self for context manager protocol.
303
+ """
304
+ # Reset state for singleton reuse
305
+ self.receive_response = ConbusDiscoverResponse(success=True)
306
+ return self
307
+
308
+ def __exit__(
309
+ self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
310
+ ) -> None:
311
+ """Exit context manager and disconnect signals."""
312
+ self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
313
+ self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
314
+ self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
315
+ self.conbus_protocol.on_timeout.disconnect(self.timeout)
316
+ self.conbus_protocol.on_failed.disconnect(self.failed)
317
+ self.on_device_discovered.disconnect()
318
+ self.on_progress.disconnect()
319
+ self.on_finish.disconnect()
320
+ self.stop_reactor()
@@ -6,7 +6,9 @@ allowing clients to receive waiting event telegrams using empty telegram sends.
6
6
 
7
7
  import asyncio
8
8
  import logging
9
- from typing import Any, Callable, Optional
9
+ from typing import Any, Optional
10
+
11
+ from psygnal import Signal
10
12
 
11
13
  from xp.models.conbus.conbus_receive import ConbusReceiveResponse
12
14
  from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
@@ -22,9 +24,13 @@ class ConbusReceiveService:
22
24
 
23
25
  Attributes:
24
26
  conbus_protocol: Protocol instance for Conbus communication.
27
+ on_progress: Signal emitted when a telegram is received (with telegram frame).
28
+ on_finish: Signal emitted when receiving finishes (with result).
25
29
  """
26
30
 
27
31
  conbus_protocol: ConbusEventProtocol
32
+ on_progress: Signal = Signal(str)
33
+ on_finish: Signal = Signal(ConbusReceiveResponse)
28
34
 
29
35
  def __init__(self, conbus_protocol: ConbusEventProtocol) -> None:
30
36
  """Initialize the Conbus receive service.
@@ -32,8 +38,6 @@ class ConbusReceiveService:
32
38
  Args:
33
39
  conbus_protocol: ConbusEventProtocol instance.
34
40
  """
35
- self.progress_callback: Optional[Callable[[str], None]] = None
36
- self.finish_callback: Optional[Callable[[ConbusReceiveResponse], None]] = None
37
41
  self.receive_response: ConbusReceiveResponse = ConbusReceiveResponse(
38
42
  success=True
39
43
  )
@@ -67,8 +71,7 @@ class ConbusReceiveService:
67
71
  telegram_received: The telegram received event.
68
72
  """
69
73
  self.logger.debug(f"Telegram received: {telegram_received}")
70
- if self.progress_callback:
71
- self.progress_callback(telegram_received.frame)
74
+ self.on_progress.emit(telegram_received.frame)
72
75
 
73
76
  if not self.receive_response.received_telegrams:
74
77
  self.receive_response.received_telegrams = []
@@ -79,8 +82,7 @@ class ConbusReceiveService:
79
82
  timeout = self.conbus_protocol.timeout_seconds
80
83
  self.logger.info("Receive stopped after: %ss", timeout)
81
84
  self.receive_response.success = True
82
- if self.finish_callback:
83
- self.finish_callback(self.receive_response)
85
+ self.on_finish.emit(self.receive_response)
84
86
 
85
87
  def failed(self, message: str) -> None:
86
88
  """Handle failed connection event.
@@ -91,37 +93,37 @@ class ConbusReceiveService:
91
93
  self.logger.debug("Failed %s:", message)
92
94
  self.receive_response.success = False
93
95
  self.receive_response.error = message
94
- if self.finish_callback:
95
- self.finish_callback(self.receive_response)
96
+ self.on_finish.emit(self.receive_response)
97
+
98
+ def set_timeout(self, timeout_seconds: float) -> None:
99
+ """Setup callbacks and timeout for receiving telegrams.
96
100
 
97
- def init(
101
+ Args:
102
+ timeout_seconds: Optional timeout in seconds.
103
+ """
104
+ self.logger.debug("Set timeout")
105
+ self.conbus_protocol.timeout_seconds = timeout_seconds
106
+
107
+ def set_event_loop(
98
108
  self,
99
- progress_callback: Callable[[str], None],
100
- finish_callback: Callable[[ConbusReceiveResponse], None],
101
- timeout_seconds: Optional[float] = None,
102
- event_loop: Optional[asyncio.AbstractEventLoop] = None,
109
+ event_loop: asyncio.AbstractEventLoop,
103
110
  ) -> None:
104
111
  """Setup callbacks and timeout for receiving telegrams.
105
112
 
106
113
  Args:
107
- progress_callback: Callback for each received telegram.
108
- finish_callback: Callback when receiving completes.
109
- timeout_seconds: Optional timeout in seconds.
110
114
  event_loop: Optional event loop to use for async operations.
111
115
  """
112
- self.logger.info("Starting receive")
113
- if timeout_seconds:
114
- self.conbus_protocol.timeout_seconds = timeout_seconds
115
- self.progress_callback = progress_callback
116
- self.finish_callback = finish_callback
117
-
118
- if event_loop:
119
- self.conbus_protocol.set_event_loop(event_loop)
116
+ self.logger.debug("Set eventloop")
117
+ self.conbus_protocol.set_event_loop(event_loop)
120
118
 
121
119
  def start_reactor(self) -> None:
122
120
  """Start the reactor."""
123
121
  self.conbus_protocol.start_reactor()
124
122
 
123
+ def stop_reactor(self) -> None:
124
+ """Start the reactor."""
125
+ self.conbus_protocol.stop_reactor()
126
+
125
127
  def __enter__(self) -> "ConbusReceiveService":
126
128
  """Enter context manager.
127
129
 
@@ -141,3 +143,6 @@ class ConbusReceiveService:
141
143
  self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
142
144
  self.conbus_protocol.on_timeout.disconnect(self.timeout)
143
145
  self.conbus_protocol.on_failed.disconnect(self.failed)
146
+ self.on_progress.disconnect()
147
+ self.on_finish.disconnect()
148
+ self.stop_reactor()
@@ -63,8 +63,8 @@ protocol:
63
63
  "e":
64
64
  name: "Link 1 Off"
65
65
  telegrams:
66
- - E02L01I00M
67
- - E02L01I00B
66
+ - E02L01I09M
67
+ - E02L01I09B
68
68
 
69
69
  "f":
70
70
  name: "Link 2 On"
@@ -75,8 +75,8 @@ protocol:
75
75
  "g":
76
76
  name: "Link 2 Off"
77
77
  telegrams:
78
- - E02L02I00M
79
- - E02L02I00B
78
+ - E02L02I09M
79
+ - E02L02I09B
80
80
 
81
81
  "h":
82
82
  name: "Link 3 On"
@@ -87,8 +87,8 @@ protocol:
87
87
  "i":
88
88
  name: "Link 3 Off"
89
89
  telegrams:
90
- - E02L03I00M
91
- - E02L03I00B
90
+ - E02L03I09M
91
+ - E02L03I09B
92
92
 
93
93
  "j":
94
94
  name: "Link 4 On"
@@ -99,8 +99,8 @@ protocol:
99
99
  "k":
100
100
  name: "Link 4 Off"
101
101
  telegrams:
102
- - E02L04I00M
103
- - E02L04I00B
102
+ - E02L04I09M
103
+ - E02L04I09B
104
104
 
105
105
  "l":
106
106
  name: "Link 5 On"
@@ -111,8 +111,8 @@ protocol:
111
111
  "m":
112
112
  name: "Link 5 Off"
113
113
  telegrams:
114
- - E02L05I00M
115
- - E02L05I00B
114
+ - E02L05I09M
115
+ - E02L05I09B
116
116
 
117
117
  "n":
118
118
  name: "Link 6 On"
@@ -123,8 +123,8 @@ protocol:
123
123
  "o":
124
124
  name: "Link 6 Off"
125
125
  telegrams:
126
- - E02L06I00M
127
- - E02L06I00B
126
+ - E02L06I09M
127
+ - E02L06I09B
128
128
 
129
129
  "p":
130
130
  name: "Link 7 On"
@@ -135,5 +135,5 @@ protocol:
135
135
  "q":
136
136
  name: "Link 7 Off"
137
137
  telegrams:
138
- - E02L07I00M
139
- - E02L07I00B
138
+ - E02L07I09M
139
+ - E02L07I09B
@@ -12,7 +12,6 @@ from twisted.python.failure import Failure
12
12
  from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
13
13
  from xp.models.term.connection_state import ConnectionState
14
14
  from xp.models.term.status_message import StatusMessageChanged
15
- from xp.services.conbus.conbus_receive_service import ConbusReceiveService
16
15
  from xp.services.protocol import ConbusEventProtocol
17
16
 
18
17
 
@@ -26,7 +25,6 @@ class ProtocolLogWidget(Widget):
26
25
  container: ServiceContainer for dependency injection.
27
26
  connection_state: Current connection state (reactive).
28
27
  protocol: Reference to ConbusEventProtocol (prevents duplicate connections).
29
- service: ConbusReceiveService instance.
30
28
  logger: Logger instance for this widget.
31
29
  log_widget: RichLog widget for displaying messages.
32
30
  """
@@ -43,7 +41,6 @@ class ProtocolLogWidget(Widget):
43
41
  self.border_title = "Protocol"
44
42
  self.container = container
45
43
  self.protocol: Optional[ConbusEventProtocol] = None
46
- self.service: Optional[ConbusReceiveService] = None
47
44
  self.logger = logging.getLogger(__name__)
48
45
  self.log_widget: Optional[RichLog] = None
49
46
  self._state_machine = ConnectionState.create_state_machine()
@@ -64,8 +61,7 @@ class ProtocolLogWidget(Widget):
64
61
  Resolves ConbusReceiveService and connects signals.
65
62
  """
66
63
  # Resolve service from container (singleton)
67
- self.service = self.container.resolve(ConbusReceiveService)
68
- self.protocol = self.service.conbus_protocol
64
+ self.protocol = self.container.resolve(ConbusEventProtocol)
69
65
 
70
66
  # Connect psygnal signals
71
67
  self.protocol.on_connection_made.connect(self._on_connection_made)
@@ -86,10 +82,6 @@ class ProtocolLogWidget(Widget):
86
82
  Integrates Twisted reactor with Textual's asyncio loop cleanly.
87
83
  """
88
84
  # Guard against duplicate connections (race condition)
89
- if self.service is None:
90
- self.logger.error("Service not initialized")
91
- return
92
-
93
85
  if self.protocol is None:
94
86
  self.logger.error("Protocol not initialized")
95
87
  return
@@ -114,41 +106,12 @@ class ProtocolLogWidget(Widget):
114
106
  self.logger.info(f"Reactor object: {self.protocol._reactor}")
115
107
  self.logger.info(f"Reactor running: {self.protocol._reactor.running}")
116
108
 
117
- # Setup service callbacks
118
- def progress_callback(telegram: str) -> None:
119
- """Handle progress updates for telegram reception.
120
-
121
- Args:
122
- telegram: Received telegram string.
123
- """
124
- pass
125
-
126
- def finish_callback(response: Any) -> None:
127
- """Handle completion of telegram reception.
128
-
129
- Args:
130
- response: Response object from telegram reception.
131
- """
132
- pass
133
-
134
109
  # Get the currently running asyncio event loop (Textual's loop)
135
110
  event_loop = asyncio.get_running_loop()
136
111
  self.logger.info(f"Current running loop: {event_loop}")
137
112
  self.logger.info(f"Loop is running: {event_loop.is_running()}")
138
113
 
139
- self.service.init(
140
- progress_callback=progress_callback,
141
- finish_callback=finish_callback,
142
- timeout_seconds=None, # Continuous monitoring
143
- event_loop=event_loop,
144
- )
145
-
146
- reactor = self.service.conbus_protocol._reactor
147
- reactor.connectTCP(
148
- self.protocol.cli_config.ip,
149
- self.protocol.cli_config.port,
150
- self.protocol,
151
- )
114
+ self.protocol.connect()
152
115
 
153
116
  # Wait for connection to establish
154
117
  await asyncio.sleep(1.0)
@@ -43,8 +43,6 @@ class TestConbusReceiveService:
43
43
 
44
44
  def test_service_initialization(self, service, mock_protocol):
45
45
  """Test service can be initialized with required dependencies."""
46
- assert service.progress_callback is None
47
- assert service.finish_callback is None
48
46
  assert service.receive_response.success is True
49
47
  assert service.receive_response.received_telegrams == []
50
48
 
@@ -117,9 +115,9 @@ class TestConbusReceiveService:
117
115
  ]
118
116
 
119
117
  def test_telegram_received_with_progress_callback(self, service, mock_protocol):
120
- """Test telegram_received calls progress callback."""
118
+ """Test telegram_received emits progress signal."""
121
119
  progress_mock = Mock()
122
- service.progress_callback = progress_mock
120
+ service.on_progress.connect(progress_mock)
123
121
 
124
122
  telegram_event = TelegramReceivedEvent(
125
123
  protocol=mock_protocol,
@@ -137,9 +135,7 @@ class TestConbusReceiveService:
137
135
  progress_mock.assert_called_once_with("<T123456789012D0AK>")
138
136
 
139
137
  def test_telegram_received_without_progress_callback(self, service, mock_protocol):
140
- """Test telegram_received doesn't crash when progress_callback is None."""
141
- service.progress_callback = None
142
-
138
+ """Test telegram_received doesn't crash when no signal handlers connected."""
143
139
  telegram_event = TelegramReceivedEvent(
144
140
  protocol=mock_protocol,
145
141
  frame="<T123456789012D0AK>",
@@ -157,7 +153,7 @@ class TestConbusReceiveService:
157
153
  def test_timeout(self, service, mock_protocol):
158
154
  """Test timeout callback marks operation as successful."""
159
155
  finish_mock = Mock()
160
- service.finish_callback = finish_mock
156
+ service.on_finish.connect(finish_mock)
161
157
 
162
158
  service.timeout()
163
159
 
@@ -165,16 +161,14 @@ class TestConbusReceiveService:
165
161
  finish_mock.assert_called_once_with(service.receive_response)
166
162
 
167
163
  def test_timeout_without_finish_callback(self, service):
168
- """Test timeout doesn't crash when finish_callback is None."""
169
- service.finish_callback = None
170
-
164
+ """Test timeout doesn't crash when no signal handlers connected."""
171
165
  # Should not raise any errors
172
166
  service.timeout()
173
167
 
174
168
  def test_failed(self, service):
175
169
  """Test failed callback updates service response."""
176
170
  finish_mock = Mock()
177
- service.finish_callback = finish_mock
171
+ service.on_finish.connect(finish_mock)
178
172
 
179
173
  service.failed("Connection timeout")
180
174
 
@@ -183,43 +177,32 @@ class TestConbusReceiveService:
183
177
  finish_mock.assert_called_once_with(service.receive_response)
184
178
 
185
179
  def test_failed_without_finish_callback(self, service):
186
- """Test failed doesn't crash when finish_callback is None."""
187
- service.finish_callback = None
188
-
180
+ """Test failed doesn't crash when no signal handlers connected."""
189
181
  # Should not raise any errors
190
182
  service.failed("Connection timeout")
191
183
 
192
- def test_start(self, service, mock_protocol):
193
- """Test start method sets up service parameters."""
194
- finish_mock = Mock()
195
- progress_mock = Mock()
196
-
197
- service.init(
198
- progress_callback=progress_mock,
199
- finish_callback=finish_mock,
200
- timeout_seconds=10,
201
- )
184
+ def test_set_timeout(self, service, mock_protocol):
185
+ """Test set_timeout method sets timeout on protocol."""
186
+ service.set_timeout(timeout_seconds=10)
202
187
 
203
- assert service.progress_callback == progress_mock
204
- assert service.finish_callback == finish_mock
205
188
  assert mock_protocol.timeout_seconds == 10
206
189
 
207
- def test_start_without_timeout(self, service, mock_protocol):
208
- """Test start method with None timeout uses protocol default."""
190
+ def test_signal_connections(self, service):
191
+ """Test signals can be connected and emit correctly."""
209
192
  finish_mock = Mock()
210
193
  progress_mock = Mock()
211
- original_timeout = mock_protocol.timeout_seconds
212
194
 
213
- service.init(
214
- progress_callback=progress_mock,
215
- finish_callback=finish_mock,
216
- timeout_seconds=None,
217
- )
195
+ # Connect signals
196
+ service.on_progress.connect(progress_mock)
197
+ service.on_finish.connect(finish_mock)
198
+
199
+ # Emit signals
200
+ service.on_progress.emit("test_telegram")
201
+ service.on_finish.emit(service.receive_response)
218
202
 
219
- assert service.progress_callback == progress_mock
220
- assert service.finish_callback == finish_mock
221
- # Timeout should remain unchanged
222
- assert mock_protocol.timeout_seconds == original_timeout
203
+ # Verify callbacks were called
204
+ progress_mock.assert_called_once_with("test_telegram")
205
+ finish_mock.assert_called_once_with(service.receive_response)
223
206
 
224
207
  def test_start_reactor(self, service, mock_protocol):
225
208
  """Test start_reactor delegates to protocol."""
@@ -256,12 +239,8 @@ class TestConbusReceiveService:
256
239
 
257
240
  def test_context_manager_full_lifecycle(self, service, mock_protocol):
258
241
  """Test full context manager lifecycle with singleton reuse."""
259
- finish_mock = Mock()
260
- progress_mock = Mock()
261
-
262
242
  # First use
263
243
  with service:
264
- service.init(progress_mock, finish_mock, 5.0)
265
244
  # Simulate receiving a telegram
266
245
  service.receive_response.received_telegrams = ["<T123456789012D0AK>"]
267
246