conson-xp 1.22.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.22.0 → conson_xp-1.24.0}/PKG-INFO +1 -1
  2. {conson_xp-1.22.0 → conson_xp-1.24.0}/pyproject.toml +1 -1
  3. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/__init__.py +1 -1
  4. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +7 -2
  5. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +5 -2
  6. conson_xp-1.24.0/src/xp/models/term/connection_state.py +58 -0
  7. conson_xp-1.24.0/src/xp/models/term/status_message.py +16 -0
  8. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_discover_service.py +61 -53
  9. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_receive_service.py +30 -25
  10. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/protocol/conbus_event_protocol.py +19 -6
  11. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/protocol.py +10 -0
  12. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/protocol.tcss +1 -1
  13. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/protocol.yml +14 -14
  14. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/widgets/protocol_log.py +39 -123
  15. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/widgets/status_footer.py +10 -0
  16. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_receive_service.py +22 -43
  17. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_tui/test_protocol_log.py +0 -1
  18. {conson_xp-1.22.0 → conson_xp-1.24.0}/LICENSE +0 -0
  19. {conson_xp-1.22.0 → conson_xp-1.24.0}/README.md +0 -0
  20. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/__init__.py +0 -0
  21. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/__main__.py +0 -0
  22. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/__init__.py +0 -0
  23. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
  24. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
  25. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  26. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  27. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  28. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  29. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  30. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  31. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_event_commands.py +0 -0
  32. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  33. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  34. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_modulenumber_commands.py +0 -0
  35. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +0 -0
  36. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  37. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
  38. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  39. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/file_commands.py +0 -0
  40. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
  41. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
  42. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
  43. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/module_commands.py +0 -0
  44. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  45. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/server/__init__.py +0 -0
  46. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/server/server_commands.py +0 -0
  47. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
  48. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
  49. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  50. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  51. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  52. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  53. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  54. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  55. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/term/__init__.py +0 -0
  56. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/term/term.py +0 -0
  57. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/commands/term/term_commands.py +0 -0
  58. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/main.py +0 -0
  59. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/__init__.py +0 -0
  60. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/click_tree.py +0 -0
  61. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  62. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/decorators.py +0 -0
  63. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/error_handlers.py +0 -0
  64. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/formatters.py +0 -0
  65. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/module_type_choice.py +0 -0
  66. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/serial_number_type.py +0 -0
  67. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/system_function_choice.py +0 -0
  68. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/cli/utils/xp_module_type.py +0 -0
  69. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/connection/__init__.py +0 -0
  70. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/connection/exceptions.py +0 -0
  71. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/__init__.py +0 -0
  72. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/actiontable/__init__.py +0 -0
  73. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/actiontable/actiontable.py +0 -0
  74. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  75. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  76. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  77. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/__init__.py +0 -0
  78. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus.py +0 -0
  79. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  80. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_blink.py +0 -0
  81. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
  82. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  83. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_custom.py +0 -0
  84. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  85. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_discover.py +0 -0
  86. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_event_list.py +0 -0
  87. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_event_raw.py +0 -0
  88. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  89. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  90. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_logger_config.py +0 -0
  91. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_output.py +0 -0
  92. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_raw.py +0 -0
  93. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_receive.py +0 -0
  94. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  95. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/homekit/__init__.py +0 -0
  96. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
  97. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/homekit/homekit_config.py +0 -0
  98. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
  99. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/log_entry.py +0 -0
  100. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/protocol/__init__.py +0 -0
  101. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
  102. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/response.py +0 -0
  103. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/__init__.py +0 -0
  104. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/action_type.py +0 -0
  105. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/datapoint_type.py +0 -0
  106. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/event_telegram.py +0 -0
  107. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/event_type.py +0 -0
  108. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/input_action_type.py +0 -0
  109. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/input_type.py +0 -0
  110. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/module_type.py +0 -0
  111. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/module_type_code.py +0 -0
  112. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/output_telegram.py +0 -0
  113. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/reply_telegram.py +0 -0
  114. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/system_function.py +0 -0
  115. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/system_telegram.py +0 -0
  116. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/telegram.py +0 -0
  117. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/telegram_type.py +0 -0
  118. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/telegram/timeparam_type.py +0 -0
  119. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/term/__init__.py +0 -0
  120. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/term/protocol_keys_config.py +0 -0
  121. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/models/write_config_type.py +0 -0
  122. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/__init__.py +0 -0
  123. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/actiontable/__init__.py +0 -0
  124. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/actiontable/actiontable_serializer.py +0 -0
  125. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
  126. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +0 -0
  127. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +0 -0
  128. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +0 -0
  129. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/__init__.py +0 -0
  130. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  131. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_download_service.py +0 -0
  132. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_list_service.py +0 -0
  133. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_show_service.py +0 -0
  134. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/actiontable_upload_service.py +0 -0
  135. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +0 -0
  136. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  137. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  138. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  139. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  140. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  141. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_event_list_service.py +0 -0
  142. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_event_raw_service.py +0 -0
  143. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
  144. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
  145. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  146. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/conbus/write_config_service.py +0 -0
  147. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/__init__.py +0 -0
  148. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
  149. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
  150. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
  151. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
  152. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
  153. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
  154. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
  155. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
  156. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
  157. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
  158. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
  159. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
  160. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/homekit/homekit_service.py +0 -0
  161. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/log_file_service.py +0 -0
  162. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/module_type_service.py +0 -0
  163. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/protocol/__init__.py +0 -0
  164. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/protocol/conbus_protocol.py +0 -0
  165. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/protocol/protocol_factory.py +0 -0
  166. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
  167. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/reverse_proxy_service.py +0 -0
  168. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/__init__.py +0 -0
  169. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/base_server_service.py +0 -0
  170. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/cp20_server_service.py +0 -0
  171. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/device_service_factory.py +0 -0
  172. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/server_service.py +0 -0
  173. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/xp130_server_service.py +0 -0
  174. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/xp20_server_service.py +0 -0
  175. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/xp230_server_service.py +0 -0
  176. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/xp24_server_service.py +0 -0
  177. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/server/xp33_server_service.py +0 -0
  178. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/__init__.py +0 -0
  179. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  180. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  181. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  182. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  183. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  184. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
  185. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_service.py +0 -0
  186. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
  187. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/__init__.py +0 -0
  188. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/widgets/__init__.py +0 -0
  189. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/term/widgets/help_menu.py +0 -0
  190. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/__init__.py +0 -0
  191. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/checksum.py +0 -0
  192. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/dependencies.py +0 -0
  193. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/event_helper.py +0 -0
  194. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/logging.py +0 -0
  195. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/serialization.py +0 -0
  196. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/state_machine.py +0 -0
  197. {conson_xp-1.22.0 → conson_xp-1.24.0}/src/xp/utils/time_utils.py +0 -0
  198. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/.coverage +0 -0
  199. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/__init__.py +0 -0
  200. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/conftest.py +0 -0
  201. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/.coverage +0 -0
  202. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/__init__.py +0 -0
  203. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/telegram_test_data.py +0 -0
  204. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_actiontable_integration.py +0 -0
  205. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_api/.coverage +0 -0
  206. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_api/__init__.py +0 -0
  207. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_blink_integration.py +0 -0
  208. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_checksum_integration.py +0 -0
  209. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_conbus_blink_integration.py +0 -0
  210. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  211. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_conbus_raw_integration.py +0 -0
  212. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_conbus_receive_integration.py +0 -0
  213. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_discovery_integration.py +0 -0
  214. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_event_telegram_integration.py +0 -0
  215. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_homekit_config_integration.py +0 -0
  216. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_link_number_integration.py +0 -0
  217. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_module_integration.py +0 -0
  218. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_output_integration.py +0 -0
  219. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
  220. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  221. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_term_logging_integration.py +0 -0
  222. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_version_integration.py +0 -0
  223. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_xp20_action_table_integration.py +0 -0
  224. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/integration/test_xp24_action_table_integration.py +0 -0
  225. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/__init__.py +0 -0
  226. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_api/__init__.py +0 -0
  227. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/__init__.py +0 -0
  228. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_click_tree.py +0 -0
  229. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  230. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  231. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  232. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_decorators.py +0 -0
  233. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
  234. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_formatters.py +0 -0
  235. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  236. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  237. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_cli/test_term_commands.py +0 -0
  238. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_connection/__init__.py +0 -0
  239. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_connection/test_connection_init.py +0 -0
  240. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_connection/test_exceptions.py +0 -0
  241. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_encoding/__init__.py +0 -0
  242. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  243. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/__init__.py +0 -0
  244. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus.py +0 -0
  245. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  246. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
  247. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  248. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_event_telegram.py +0 -0
  249. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_log_entry.py +0 -0
  250. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_logger_config.py +0 -0
  251. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_module_type.py +0 -0
  252. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
  253. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_system_telegram.py +0 -0
  254. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  255. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_version_telegram.py +0 -0
  256. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_write_config_type.py +0 -0
  257. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  258. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  259. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  260. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/__init__.py +0 -0
  261. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_actiontable_serializer.py +0 -0
  262. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
  263. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_actiontable_upload_service.py +0 -0
  264. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_base_server_service.py +0 -0
  265. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_blink_service.py +0 -0
  266. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_checksum_service.py +0 -0
  267. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  268. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_event_list_service.py +0 -0
  269. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_event_raw_service.py +0 -0
  270. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
  271. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  272. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_device_service_factory.py +0 -0
  273. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_discovery_service.py +0 -0
  274. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
  275. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
  276. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
  277. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_homekit_services.py +0 -0
  278. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_log_file_service.py +0 -0
  279. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_module_type_service.py +0 -0
  280. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_protocol.py +0 -0
  281. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_server_service.py +0 -0
  282. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  283. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
  284. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_telegram_service.py +0 -0
  285. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_version_service.py +0 -0
  286. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +0 -0
  287. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  288. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +0 -0
  289. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp24_action_table_service.py +0 -0
  290. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +0 -0
  291. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
  292. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_tui/__init__.py +0 -0
  293. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_utils/__init__.py +0 -0
  294. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_checksum.py +0 -0
  295. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_event_helper.py +0 -0
  296. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_logging.py +0 -0
  297. {conson_xp-1.22.0 → conson_xp-1.24.0}/tests/unit/test_utils/test_serialization.py +0 -0
  298. {conson_xp-1.22.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.22.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.22.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.22.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()
@@ -0,0 +1,58 @@
1
+ """Connection state management module."""
2
+
3
+ from enum import Enum
4
+
5
+ from xp.utils.state_machine import StateMachine
6
+
7
+
8
+ class ConnectionState(str, Enum):
9
+ """Connection state enumeration.
10
+
11
+ Attributes:
12
+ DISCONNECTING: Disconnecting to server.
13
+ DISCONNECTED: Not connected to server.
14
+ CONNECTING: Connection in progress.
15
+ CONNECTED: Successfully connected.
16
+ FAILED: Connection failed.
17
+ """
18
+
19
+ DISCONNECTING = "DISCONNECTING"
20
+ DISCONNECTED = "DISCONNECTED"
21
+ CONNECTING = "CONNECTING"
22
+ CONNECTED = "CONNECTED"
23
+ FAILED = "FAILED"
24
+
25
+ @staticmethod
26
+ def create_state_machine() -> StateMachine:
27
+ """Create and configure state machine for connection management.
28
+
29
+ Returns:
30
+ Configured StateMachine with connection state transitions.
31
+ """
32
+ sm = StateMachine(ConnectionState.DISCONNECTED)
33
+
34
+ # Define valid transitions
35
+ sm.define_transition(
36
+ "connect", {ConnectionState.DISCONNECTED, ConnectionState.FAILED}
37
+ )
38
+ sm.define_transition(
39
+ "disconnect", {ConnectionState.CONNECTED, ConnectionState.CONNECTING}
40
+ )
41
+ sm.define_transition(
42
+ "connecting", {ConnectionState.DISCONNECTED, ConnectionState.FAILED}
43
+ )
44
+ sm.define_transition("connected", {ConnectionState.CONNECTING})
45
+ sm.define_transition(
46
+ "disconnecting", {ConnectionState.CONNECTED, ConnectionState.CONNECTING}
47
+ )
48
+ sm.define_transition("disconnected", {ConnectionState.DISCONNECTING})
49
+ sm.define_transition(
50
+ "failed",
51
+ {
52
+ ConnectionState.CONNECTING,
53
+ ConnectionState.CONNECTED,
54
+ ConnectionState.DISCONNECTING,
55
+ },
56
+ )
57
+
58
+ return sm
@@ -0,0 +1,16 @@
1
+ """Status message models for terminal UI."""
2
+
3
+ from textual.message import Message
4
+
5
+
6
+ class StatusMessageChanged(Message):
7
+ """Message posted when status message changes."""
8
+
9
+ def __init__(self, message: str) -> None:
10
+ """Initialize the message.
11
+
12
+ Args:
13
+ message: The status message to display.
14
+ """
15
+ super().__init__()
16
+ self.message = message
@@ -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()
@@ -17,7 +17,7 @@ from twisted.internet.interfaces import IAddress, IConnector
17
17
  from twisted.internet.posixbase import PosixReactorBase
18
18
  from twisted.python.failure import Failure
19
19
 
20
- from xp.models import ConbusClientConfig
20
+ from xp.models import ConbusClientConfig, ModuleTypeCode
21
21
  from xp.models.protocol.conbus_protocol import (
22
22
  TelegramReceivedEvent,
23
23
  )
@@ -168,9 +168,6 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
168
168
 
169
169
  Args:
170
170
  data: Raw telegram payload (without checksum/framing).
171
-
172
- Raises:
173
- IOError: If transport is not open.
174
171
  """
175
172
  self.on_send_frame.emit(data)
176
173
 
@@ -180,8 +177,9 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
180
177
  frame = b"<" + frame_data.encode() + b">"
181
178
 
182
179
  if not self.transport:
183
- self.logger.info("Invalid transport")
184
- raise IOError("Transport is not open")
180
+ self.logger.info("Invalid transport, connection closed.")
181
+ self.on_connection_failed.emit(Failure("Invalid transport."))
182
+ return
185
183
 
186
184
  self.logger.debug(f"Sending frame: {frame.decode()}")
187
185
  self.transport.write(frame) # type: ignore
@@ -211,6 +209,21 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
211
209
  )
212
210
  self.send_raw_telegram(payload)
213
211
 
212
+ def send_event_telegram(
213
+ self, module_type_code: ModuleTypeCode, link_number: int, input_number: int
214
+ ) -> None:
215
+ """Send telegram with specified parameters.
216
+
217
+ Args:
218
+ module_type_code: Type code of module.
219
+ link_number: Link number.
220
+ input_number: Input number.
221
+ """
222
+ payload = (
223
+ f"E" f"{module_type_code}" f"L{link_number:02d}" f"I{input_number:02d}"
224
+ )
225
+ self.send_raw_telegram(payload)
226
+
214
227
  def send_raw_telegram(self, payload: str) -> None:
215
228
  """Send telegram with specified parameters.
216
229
 
@@ -7,6 +7,7 @@ from textual.app import App, ComposeResult
7
7
  from textual.containers import Horizontal
8
8
 
9
9
  from xp.models.term import ProtocolKeysConfig
10
+ from xp.models.term.status_message import StatusMessageChanged
10
11
  from xp.term.widgets.help_menu import HelpMenuWidget
11
12
  from xp.term.widgets.protocol_log import ProtocolLogWidget
12
13
  from xp.term.widgets.status_footer import StatusFooterWidget
@@ -125,3 +126,12 @@ class ProtocolMonitorApp(App[None]):
125
126
  """
126
127
  if self.footer_widget:
127
128
  self.footer_widget.update_status(state)
129
+
130
+ def on_status_message_changed(self, message: StatusMessageChanged) -> None:
131
+ """Handle status message changes from protocol widget.
132
+
133
+ Args:
134
+ message: Message containing the status text.
135
+ """
136
+ if self.footer_widget:
137
+ self.footer_widget.update_message(message.message)
@@ -119,7 +119,7 @@ Footer {
119
119
  #status-text {
120
120
  dock: right;
121
121
  width: auto;
122
- padding: 0 1;
122
+ padding: 0 3;
123
123
  background: $background;
124
124
  color: $text;
125
125
  text-align: right;
@@ -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