conson-xp 1.16.0__tar.gz → 1.18.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 (270) hide show
  1. {conson_xp-1.16.0 → conson_xp-1.18.0}/PKG-INFO +5 -1
  2. {conson_xp-1.16.0 → conson_xp-1.18.0}/README.md +4 -0
  3. {conson_xp-1.16.0 → conson_xp-1.18.0}/pyproject.toml +1 -1
  4. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/__init__.py +1 -1
  5. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/__init__.py +3 -0
  6. conson_xp-1.18.0/src/xp/cli/commands/conbus/conbus_event_commands.py +81 -0
  7. conson_xp-1.18.0/src/xp/cli/utils/module_type_choice.py +56 -0
  8. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/__init__.py +2 -0
  9. conson_xp-1.18.0/src/xp/models/conbus/conbus_event_raw.py +47 -0
  10. conson_xp-1.18.0/src/xp/services/conbus/conbus_event_raw_service.py +181 -0
  11. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/protocol/conbus_event_protocol.py +24 -6
  12. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/utils/dependencies.py +9 -0
  13. conson_xp-1.18.0/tests/unit/test_services/test_conbus_event_raw_service.py +171 -0
  14. {conson_xp-1.16.0 → conson_xp-1.18.0}/LICENSE +0 -0
  15. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/__init__.py +0 -0
  16. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/__main__.py +0 -0
  17. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
  18. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
  19. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  20. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  21. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  22. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  23. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  24. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  25. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
  26. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  27. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  28. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_modulenumber_commands.py +0 -0
  29. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +0 -0
  30. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  31. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
  32. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
  33. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  34. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/file_commands.py +0 -0
  35. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
  36. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
  37. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
  38. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/module_commands.py +0 -0
  39. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  40. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/server/__init__.py +0 -0
  41. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/server/server_commands.py +0 -0
  42. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
  43. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
  44. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  45. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  46. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  47. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  48. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  49. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  50. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/main.py +0 -0
  51. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/__init__.py +0 -0
  52. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/click_tree.py +0 -0
  53. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  54. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/decorators.py +0 -0
  55. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/error_handlers.py +0 -0
  56. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/formatters.py +0 -0
  57. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/serial_number_type.py +0 -0
  58. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/system_function_choice.py +0 -0
  59. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/cli/utils/xp_module_type.py +0 -0
  60. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/connection/__init__.py +0 -0
  61. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/connection/exceptions.py +0 -0
  62. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/actiontable/__init__.py +0 -0
  63. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/actiontable/actiontable.py +0 -0
  64. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  65. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  66. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  67. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/__init__.py +0 -0
  68. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus.py +0 -0
  69. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  70. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_blink.py +0 -0
  71. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
  72. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  73. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_custom.py +0 -0
  74. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  75. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_discover.py +0 -0
  76. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  77. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  78. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_output.py +0 -0
  79. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_raw.py +0 -0
  80. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_receive.py +0 -0
  81. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  82. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/homekit/__init__.py +0 -0
  83. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
  84. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/homekit/homekit_config.py +0 -0
  85. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
  86. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/log_entry.py +0 -0
  87. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/protocol/__init__.py +0 -0
  88. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
  89. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/response.py +0 -0
  90. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/__init__.py +0 -0
  91. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/action_type.py +0 -0
  92. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/datapoint_type.py +0 -0
  93. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/event_telegram.py +0 -0
  94. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/event_type.py +0 -0
  95. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/input_action_type.py +0 -0
  96. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/input_type.py +0 -0
  97. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/module_type.py +0 -0
  98. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/module_type_code.py +0 -0
  99. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/output_telegram.py +0 -0
  100. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/reply_telegram.py +0 -0
  101. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/system_function.py +0 -0
  102. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/system_telegram.py +0 -0
  103. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/telegram.py +0 -0
  104. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/telegram_type.py +0 -0
  105. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/telegram/timeparam_type.py +0 -0
  106. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/models/write_config_type.py +0 -0
  107. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/__init__.py +0 -0
  108. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/actiontable/__init__.py +0 -0
  109. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/actiontable/actiontable_serializer.py +0 -0
  110. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
  111. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +0 -0
  112. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +0 -0
  113. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +0 -0
  114. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/__init__.py +0 -0
  115. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  116. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/actiontable/actiontable_download_service.py +0 -0
  117. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/actiontable/actiontable_list_service.py +0 -0
  118. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/actiontable/actiontable_show_service.py +0 -0
  119. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/actiontable/actiontable_upload_service.py +0 -0
  120. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +0 -0
  121. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  122. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  123. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  124. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  125. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  126. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_discover_service.py +0 -0
  127. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
  128. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
  129. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_receive_service.py +0 -0
  130. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  131. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/conbus/write_config_service.py +0 -0
  132. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/__init__.py +0 -0
  133. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
  134. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
  135. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
  136. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
  137. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
  138. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
  139. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
  140. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
  141. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
  142. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
  143. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
  144. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
  145. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/homekit/homekit_service.py +0 -0
  146. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/log_file_service.py +0 -0
  147. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/module_type_service.py +0 -0
  148. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/protocol/__init__.py +0 -0
  149. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/protocol/conbus_protocol.py +0 -0
  150. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/protocol/protocol_factory.py +0 -0
  151. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
  152. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/reverse_proxy_service.py +0 -0
  153. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/__init__.py +0 -0
  154. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/base_server_service.py +0 -0
  155. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/cp20_server_service.py +0 -0
  156. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/device_service_factory.py +0 -0
  157. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/server_service.py +0 -0
  158. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/xp130_server_service.py +0 -0
  159. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/xp20_server_service.py +0 -0
  160. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/xp230_server_service.py +0 -0
  161. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/xp24_server_service.py +0 -0
  162. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/server/xp33_server_service.py +0 -0
  163. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/__init__.py +0 -0
  164. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  165. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  166. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  167. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  168. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  169. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
  170. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_service.py +0 -0
  171. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
  172. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/utils/__init__.py +0 -0
  173. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/utils/checksum.py +0 -0
  174. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/utils/event_helper.py +0 -0
  175. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/utils/serialization.py +0 -0
  176. {conson_xp-1.16.0 → conson_xp-1.18.0}/src/xp/utils/time_utils.py +0 -0
  177. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/.coverage +0 -0
  178. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/__init__.py +0 -0
  179. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/conftest.py +0 -0
  180. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/.coverage +0 -0
  181. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/__init__.py +0 -0
  182. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/telegram_test_data.py +0 -0
  183. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_actiontable_integration.py +0 -0
  184. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_api/.coverage +0 -0
  185. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_api/__init__.py +0 -0
  186. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_blink_integration.py +0 -0
  187. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_checksum_integration.py +0 -0
  188. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_conbus_blink_integration.py +0 -0
  189. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  190. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_conbus_raw_integration.py +0 -0
  191. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_conbus_receive_integration.py +0 -0
  192. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_discovery_integration.py +0 -0
  193. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_event_telegram_integration.py +0 -0
  194. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_homekit_config_integration.py +0 -0
  195. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_link_number_integration.py +0 -0
  196. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_module_integration.py +0 -0
  197. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_output_integration.py +0 -0
  198. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
  199. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  200. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_version_integration.py +0 -0
  201. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_xp20_action_table_integration.py +0 -0
  202. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/integration/test_xp24_action_table_integration.py +0 -0
  203. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/__init__.py +0 -0
  204. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_api/__init__.py +0 -0
  205. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/__init__.py +0 -0
  206. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_click_tree.py +0 -0
  207. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  208. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  209. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  210. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_decorators.py +0 -0
  211. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
  212. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_formatters.py +0 -0
  213. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  214. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  215. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_connection/__init__.py +0 -0
  216. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_connection/test_connection_init.py +0 -0
  217. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_connection/test_exceptions.py +0 -0
  218. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_encoding/__init__.py +0 -0
  219. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  220. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/__init__.py +0 -0
  221. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_conbus.py +0 -0
  222. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  223. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
  224. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  225. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_event_telegram.py +0 -0
  226. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_log_entry.py +0 -0
  227. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_module_type.py +0 -0
  228. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
  229. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_system_telegram.py +0 -0
  230. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  231. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_version_telegram.py +0 -0
  232. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_write_config_type.py +0 -0
  233. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  234. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  235. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  236. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/__init__.py +0 -0
  237. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_actiontable_serializer.py +0 -0
  238. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
  239. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_actiontable_upload_service.py +0 -0
  240. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_base_server_service.py +0 -0
  241. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_blink_service.py +0 -0
  242. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_checksum_service.py +0 -0
  243. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  244. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
  245. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  246. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_device_service_factory.py +0 -0
  247. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_discovery_service.py +0 -0
  248. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
  249. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
  250. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
  251. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_homekit_services.py +0 -0
  252. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_log_file_service.py +0 -0
  253. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_module_type_service.py +0 -0
  254. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_protocol.py +0 -0
  255. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_server_service.py +0 -0
  256. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  257. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
  258. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_telegram_service.py +0 -0
  259. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_version_service.py +0 -0
  260. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +0 -0
  261. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  262. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +0 -0
  263. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_xp24_action_table_service.py +0 -0
  264. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +0 -0
  265. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
  266. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_utils/__init__.py +0 -0
  267. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_utils/test_checksum.py +0 -0
  268. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_utils/test_event_helper.py +0 -0
  269. {conson_xp-1.16.0 → conson_xp-1.18.0}/tests/unit/test_utils/test_serialization.py +0 -0
  270. {conson_xp-1.16.0 → conson_xp-1.18.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.16.0
3
+ Version: 1.18.0
4
4
  Summary: XP Protocol Communication Tools
5
5
  Author-Email: ldvchosal <ldvchosal@github.com>
6
6
  License: MIT License
@@ -305,6 +305,10 @@ xp conbus datapoint query
305
305
 
306
306
  xp conbus discover
307
307
 
308
+ xp conbus event
309
+ xp conbus event raw
310
+
311
+
308
312
  xp conbus lightlevel
309
313
  xp conbus lightlevel get
310
314
  xp conbus lightlevel off
@@ -253,6 +253,10 @@ xp conbus datapoint query
253
253
 
254
254
  xp conbus discover
255
255
 
256
+ xp conbus event
257
+ xp conbus event raw
258
+
259
+
256
260
  xp conbus lightlevel
257
261
  xp conbus lightlevel get
258
262
  xp conbus lightlevel off
@@ -21,7 +21,7 @@ dependencies = [
21
21
  ]
22
22
  requires-python = ">=3.11"
23
23
  readme = "README.md"
24
- version = "1.16.0"
24
+ version = "1.18.0"
25
25
 
26
26
  [project.license]
27
27
  file = "LICENSE"
@@ -3,7 +3,7 @@
3
3
  conson-xp package.
4
4
  """
5
5
 
6
- __version__ = "1.16.0"
6
+ __version__ = "1.18.0"
7
7
  __manufacturer__ = "salchichon"
8
8
  __model__ = "xp.cli"
9
9
  __serial__ = "2025.09.23.000"
@@ -37,6 +37,7 @@ from xp.cli.commands.conbus.conbus_datapoint_commands import (
37
37
  query_datapoint,
38
38
  )
39
39
  from xp.cli.commands.conbus.conbus_discover_commands import send_discover_telegram
40
+ from xp.cli.commands.conbus.conbus_event_commands import conbus_event, send_event_raw
40
41
  from xp.cli.commands.conbus.conbus_lightlevel_commands import (
41
42
  xp_lightlevel_get,
42
43
  xp_lightlevel_off,
@@ -97,6 +98,7 @@ __all__ = [
97
98
  "conbus_lightlevel",
98
99
  "conbus_msactiontable",
99
100
  "conbus_actiontable",
101
+ "conbus_event",
100
102
  "file",
101
103
  "module",
102
104
  "reverse_proxy",
@@ -118,6 +120,7 @@ __all__ = [
118
120
  "show_config",
119
121
  "send_custom_telegram",
120
122
  "send_discover_telegram",
123
+ "send_event_raw",
121
124
  "xp_output_on",
122
125
  "xp_output_off",
123
126
  "xp_output_status",
@@ -0,0 +1,81 @@
1
+ """Conbus event operations CLI commands."""
2
+
3
+ import json
4
+
5
+ import click
6
+
7
+ from xp.cli.commands.conbus.conbus import conbus
8
+ from xp.cli.utils.decorators import connection_command
9
+ from xp.cli.utils.module_type_choice import MODULE_TYPE
10
+ from xp.models import ConbusEventRawResponse
11
+ from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
12
+
13
+
14
+ @click.group(name="event")
15
+ def conbus_event() -> None:
16
+ """Send event telegrams to Conbus modules."""
17
+ pass
18
+
19
+
20
+ @conbus_event.command("raw")
21
+ @click.argument("module_type", type=MODULE_TYPE)
22
+ @click.argument("link_number", type=click.IntRange(0, 99))
23
+ @click.argument("input_number", type=click.IntRange(0, 9))
24
+ @click.argument("time_ms", type=click.IntRange(min=1), default=1000)
25
+ @click.pass_context
26
+ @connection_command()
27
+ def send_event_raw(
28
+ ctx: click.Context,
29
+ module_type: int,
30
+ link_number: int,
31
+ input_number: int,
32
+ time_ms: int,
33
+ ) -> None:
34
+ r"""Send raw event telegrams to simulate button presses.
35
+
36
+ Args:
37
+ ctx: Click context object.
38
+ module_type: Module type code (e.g., CP20, XP33).
39
+ link_number: Link number (0-99).
40
+ input_number: Input number (0-9).
41
+ time_ms: Delay between MAKE/BREAK events in milliseconds (default: 1000).
42
+
43
+ Examples:
44
+ \b
45
+ xp conbus event raw CP20 00 00
46
+ xp conbus event raw XP33 00 00 500
47
+ """
48
+
49
+ def on_finish(response: ConbusEventRawResponse) -> None:
50
+ """Handle successful completion of event raw operation.
51
+
52
+ Args:
53
+ response: Event raw response with sent and received telegrams.
54
+ """
55
+ click.echo(json.dumps(response.to_dict(), indent=2))
56
+
57
+ def on_progress(telegram: str) -> None:
58
+ """Handle progress updates during event operation.
59
+
60
+ Args:
61
+ telegram: Received telegram.
62
+ """
63
+ click.echo(json.dumps({"telegram": telegram}))
64
+
65
+ service: ConbusEventRawService = (
66
+ ctx.obj.get("container").get_container().resolve(ConbusEventRawService)
67
+ )
68
+ service.run(
69
+ module_type_code=module_type,
70
+ link_number=link_number,
71
+ input_number=input_number,
72
+ time_ms=time_ms,
73
+ progress_callback=on_progress,
74
+ finish_callback=on_finish,
75
+ timeout_seconds=5,
76
+ )
77
+ service.start_reactor()
78
+
79
+
80
+ # Register the event command group with conbus
81
+ conbus.add_command(conbus_event)
@@ -0,0 +1,56 @@
1
+ """Click parameter type for ModuleTypeCode enum validation."""
2
+
3
+ from typing import Any, Optional
4
+
5
+ import click
6
+
7
+ from xp.models.telegram.module_type_code import ModuleTypeCode
8
+
9
+
10
+ class ModuleTypeChoice(click.ParamType):
11
+ """Click parameter type for validating ModuleTypeCode enum values.
12
+
13
+ Attributes:
14
+ name: The parameter type name.
15
+ choices: List of valid choice strings.
16
+ """
17
+
18
+ name = "module_type"
19
+
20
+ def __init__(self) -> None:
21
+ """Initialize the ModuleTypeChoice parameter type."""
22
+ self.choices = [key for key in ModuleTypeCode.__members__.keys()]
23
+
24
+ def convert(
25
+ self, value: Any, param: Optional[click.Parameter], ctx: Optional[click.Context]
26
+ ) -> int:
27
+ """Convert and validate input to ModuleTypeCode value.
28
+
29
+ Args:
30
+ value: The input value to convert.
31
+ param: The Click parameter.
32
+ ctx: The Click context.
33
+
34
+ Returns:
35
+ Module type code integer value if valid.
36
+ """
37
+ if value is None:
38
+ self.fail("Module type is required", param, ctx)
39
+
40
+ # Convert to upper for comparison
41
+ normalized_value = value.upper()
42
+
43
+ if normalized_value in self.choices:
44
+ # Return the actual enum value (integer)
45
+ return ModuleTypeCode[normalized_value].value
46
+
47
+ # If not found, show error with available choices
48
+ choices_list = "\n".join(f" - {choice}" for choice in sorted(self.choices))
49
+ self.fail(
50
+ f"{value!r} is not a valid module type. " f"Choose from:\n{choices_list}",
51
+ param,
52
+ ctx,
53
+ )
54
+
55
+
56
+ MODULE_TYPE = ModuleTypeChoice()
@@ -5,6 +5,7 @@ from xp.models.conbus.conbus_client_config import ConbusClientConfig
5
5
  from xp.models.conbus.conbus_connection_status import ConbusConnectionStatus
6
6
  from xp.models.conbus.conbus_datapoint import ConbusDatapointResponse
7
7
  from xp.models.conbus.conbus_discover import ConbusDiscoverResponse
8
+ from xp.models.conbus.conbus_event_raw import ConbusEventRawResponse
8
9
  from xp.models.log_entry import LogEntry
9
10
  from xp.models.telegram.event_telegram import EventTelegram
10
11
  from xp.models.telegram.event_type import EventType
@@ -30,5 +31,6 @@ __all__ = [
30
31
  "ConbusResponse",
31
32
  "ConbusDatapointResponse",
32
33
  "ConbusDiscoverResponse",
34
+ "ConbusEventRawResponse",
33
35
  "ConbusConnectionStatus",
34
36
  ]
@@ -0,0 +1,47 @@
1
+ """Conbus event raw response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional
6
+
7
+
8
+ @dataclass
9
+ class ConbusEventRawResponse:
10
+ """Represents a response from Conbus event raw operation.
11
+
12
+ Attributes:
13
+ success: Whether the operation was successful.
14
+ sent_telegrams: List of event telegrams sent (MAKE and BREAK).
15
+ received_telegrams: List of all telegrams received.
16
+ error: Error message if operation failed.
17
+ timestamp: Timestamp of the response.
18
+ """
19
+
20
+ success: bool
21
+ sent_telegrams: Optional[list[str]] = None
22
+ received_telegrams: Optional[list[str]] = None
23
+ error: Optional[str] = None
24
+ timestamp: Optional[datetime] = None
25
+
26
+ def __post_init__(self) -> None:
27
+ """Initialize timestamp and telegram lists if not provided."""
28
+ if self.timestamp is None:
29
+ self.timestamp = datetime.now()
30
+ if self.sent_telegrams is None:
31
+ self.sent_telegrams = []
32
+ if self.received_telegrams is None:
33
+ self.received_telegrams = []
34
+
35
+ def to_dict(self) -> Dict[str, Any]:
36
+ """Convert to dictionary for JSON serialization.
37
+
38
+ Returns:
39
+ Dictionary representation of the response.
40
+ """
41
+ return {
42
+ "success": self.success,
43
+ "sent_telegrams": self.sent_telegrams,
44
+ "received_telegrams": self.received_telegrams,
45
+ "error": self.error,
46
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
47
+ }
@@ -0,0 +1,181 @@
1
+ """Conbus Event Raw Service for sending raw event telegrams.
2
+
3
+ This service implements a TCP client that connects to Conbus servers and sends
4
+ raw event telegrams to simulate button presses on Conbus modules.
5
+ """
6
+
7
+ import logging
8
+ from typing import Callable, Optional
9
+
10
+ from twisted.internet.base import DelayedCall
11
+
12
+ from xp.models import ConbusEventRawResponse
13
+ from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
14
+ from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
15
+
16
+
17
+ class ConbusEventRawService:
18
+ """Service for sending raw event telegrams to Conbus servers.
19
+
20
+ Uses ConbusEventProtocol to send MAKE/BREAK event sequences to
21
+ simulate button presses on Conbus modules.
22
+
23
+ Attributes:
24
+ conbus_protocol: Protocol instance for Conbus communication.
25
+ """
26
+
27
+ conbus_protocol: ConbusEventProtocol
28
+
29
+ def __init__(self, conbus_protocol: ConbusEventProtocol) -> None:
30
+ """Initialize the Conbus event raw service.
31
+
32
+ Args:
33
+ conbus_protocol: ConbusEventProtocol instance.
34
+ """
35
+ self.progress_callback: Optional[Callable[[str], None]] = None
36
+ self.finish_callback: Optional[Callable[[ConbusEventRawResponse], None]] = None
37
+
38
+ self.conbus_protocol: ConbusEventProtocol = conbus_protocol
39
+ self.conbus_protocol.on_connection_made.connect(self.connection_made)
40
+ self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
41
+ self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
42
+ self.conbus_protocol.on_timeout.connect(self.timeout)
43
+ self.conbus_protocol.on_failed.connect(self.failed)
44
+
45
+ self.event_result = ConbusEventRawResponse(success=False)
46
+ self.logger = logging.getLogger(__name__)
47
+
48
+ # Event parameters
49
+ self.module_type_code: int = 0
50
+ self.link_number: int = 0
51
+ self.input_number: int = 0
52
+ self.time_ms: int = 1000
53
+ self.break_event_call: Optional[DelayedCall] = None
54
+
55
+ def connection_made(self) -> None:
56
+ """Handle connection established event."""
57
+ self.logger.debug("Connection established")
58
+ self.logger.debug("Sending MAKE event telegram")
59
+ self._send_make_event()
60
+
61
+ def _send_make_event(self) -> None:
62
+ """Send MAKE event telegram."""
63
+ payload = f"E{self.module_type_code:02d}L{self.link_number:02d}I{self.input_number:02d}M"
64
+ self.logger.debug(f"Sending MAKE event: {payload}")
65
+ self.conbus_protocol.telegram_queue.put_nowait(payload.encode())
66
+ self.conbus_protocol.call_later(0.0, self.conbus_protocol.start_queue_manager)
67
+
68
+ # Schedule BREAK event after delay
69
+ delay_seconds = self.time_ms / 1000.0
70
+ self.break_event_call = self.conbus_protocol.call_later(
71
+ delay_seconds, self._send_break_event
72
+ )
73
+
74
+ def _send_break_event(self) -> None:
75
+ """Send BREAK event telegram."""
76
+ payload = f"E{self.module_type_code:02d}L{self.link_number:02d}I{self.input_number:02d}B"
77
+ self.logger.debug(f"Sending BREAK event: {payload}")
78
+ self.conbus_protocol.telegram_queue.put_nowait(payload.encode())
79
+ self.conbus_protocol.call_later(0.0, self.conbus_protocol.start_queue_manager)
80
+
81
+ def telegram_sent(self, telegram_sent: str) -> None:
82
+ """Handle telegram sent event.
83
+
84
+ Args:
85
+ telegram_sent: The telegram that was sent.
86
+ """
87
+ self.logger.debug(f"Telegram sent: {telegram_sent}")
88
+ if self.event_result.sent_telegrams is None:
89
+ self.event_result.sent_telegrams = []
90
+ self.event_result.sent_telegrams.append(telegram_sent)
91
+
92
+ def telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
93
+ """Handle telegram received event.
94
+
95
+ Args:
96
+ telegram_received: The telegram received event.
97
+ """
98
+ self.logger.debug(f"Telegram received: {telegram_received.frame}")
99
+ if self.event_result.received_telegrams is None:
100
+ self.event_result.received_telegrams = []
101
+ self.event_result.received_telegrams.append(telegram_received.frame)
102
+
103
+ # Display progress - show ALL received telegrams
104
+ if self.progress_callback:
105
+ self.progress_callback(telegram_received.frame)
106
+
107
+ def timeout(self) -> None:
108
+ """Handle timeout event.
109
+
110
+ Timeout is the normal/expected way to finish this service.
111
+ """
112
+ timeout_seconds = self.conbus_protocol.timeout_seconds
113
+ self.logger.info("Event raw finished after timeout: %ss", timeout_seconds)
114
+ self.event_result.success = True
115
+ self.event_result.error = None
116
+ if self.finish_callback:
117
+ self.finish_callback(self.event_result)
118
+
119
+ self.stop_reactor()
120
+
121
+ def failed(self, message: str) -> None:
122
+ """Handle failed connection event.
123
+
124
+ Args:
125
+ message: Failure message.
126
+ """
127
+ self.logger.debug(f"Failed: {message}")
128
+ self.event_result.success = False
129
+ self.event_result.error = message
130
+ if self.finish_callback:
131
+ self.finish_callback(self.event_result)
132
+
133
+ self.stop_reactor()
134
+
135
+ def stop_reactor(self) -> None:
136
+ """Stop reactor."""
137
+ self.logger.info("Stopping reactor")
138
+ # Cancel break event call if it's still pending
139
+ if self.break_event_call and self.break_event_call.active():
140
+ self.break_event_call.cancel()
141
+ self.conbus_protocol.stop_reactor()
142
+
143
+ def start_reactor(self) -> None:
144
+ """Start reactor."""
145
+ self.logger.info("Starting reactor")
146
+ self.conbus_protocol.start_reactor()
147
+
148
+ def run(
149
+ self,
150
+ module_type_code: int,
151
+ link_number: int,
152
+ input_number: int,
153
+ time_ms: int,
154
+ progress_callback: Optional[Callable[[str], None]],
155
+ finish_callback: Callable[[ConbusEventRawResponse], None],
156
+ timeout_seconds: int = 5,
157
+ ) -> None:
158
+ """Run reactor in dedicated thread with its own event loop.
159
+
160
+ Args:
161
+ module_type_code: Module type code (numeric, e.g., 2 for CP20, 33 for XP33).
162
+ link_number: Link number (0-99).
163
+ input_number: Input number (0-9).
164
+ time_ms: Delay in milliseconds between MAKE and BREAK events.
165
+ progress_callback: Callback for progress updates (received telegrams).
166
+ finish_callback: Callback when operation completes.
167
+ timeout_seconds: Timeout in seconds (default: 5).
168
+ """
169
+ self.logger.info(
170
+ f"Starting event raw: module={module_type_code}, "
171
+ f"link={link_number}, input={input_number}, time={time_ms}ms"
172
+ )
173
+
174
+ self.module_type_code = module_type_code
175
+ self.link_number = link_number
176
+ self.input_number = input_number
177
+ self.time_ms = time_ms
178
+
179
+ self.conbus_protocol.timeout_seconds = timeout_seconds
180
+ self.progress_callback = progress_callback
181
+ self.finish_callback = finish_callback
@@ -7,7 +7,7 @@ import logging
7
7
  from queue import SimpleQueue
8
8
  from random import randint
9
9
  from threading import Lock
10
- from typing import Any, Optional
10
+ from typing import Any, Callable, Optional
11
11
 
12
12
  from psygnal import Signal
13
13
  from twisted.internet import protocol
@@ -209,7 +209,27 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
209
209
  f"D{data_value}"
210
210
  )
211
211
  self.telegram_queue.put_nowait(payload.encode())
212
- self._reactor.callLater(0.0, self.start_queue_manager)
212
+ self.call_later(0.0, self.start_queue_manager)
213
+
214
+ def call_later(
215
+ self,
216
+ delay: float,
217
+ callable_action: Callable[..., Any],
218
+ *args: object,
219
+ **kw: object,
220
+ ) -> DelayedCall:
221
+ """Schedule a callable to be called later.
222
+
223
+ Args:
224
+ delay: Delay in seconds before calling.
225
+ callable_action: The callable to execute.
226
+ args: Positional arguments to pass to callable.
227
+ kw: Keyword arguments to pass to callable.
228
+
229
+ Returns:
230
+ DelayedCall object that can be cancelled.
231
+ """
232
+ return self._reactor.callLater(delay, callable_action, *args, **kw)
213
233
 
214
234
  def buildProtocol(self, addr: IAddress) -> protocol.Protocol:
215
235
  """Build protocol instance for connection.
@@ -264,9 +284,7 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
264
284
  def _reset_timeout(self) -> None:
265
285
  """Reset the inactivity timeout."""
266
286
  self._cancel_timeout()
267
- self.timeout_call = self._reactor.callLater(
268
- self.timeout_seconds, self._on_timeout
269
- )
287
+ self.timeout_call = self.call_later(self.timeout_seconds, self._on_timeout)
270
288
 
271
289
  def _cancel_timeout(self) -> None:
272
290
  """Cancel the inactivity timeout."""
@@ -320,7 +338,7 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
320
338
  telegram = self.telegram_queue.get_nowait()
321
339
  self.sendFrame(telegram)
322
340
  later = randint(10, 80) / 100
323
- self._reactor.callLater(later, self.process_telegram_queue)
341
+ self.call_later(later, self.process_telegram_queue)
324
342
 
325
343
  def __enter__(self) -> "ConbusEventProtocol":
326
344
  """Enter context manager.
@@ -43,6 +43,7 @@ from xp.services.conbus.conbus_datapoint_service import (
43
43
  ConbusDatapointService,
44
44
  )
45
45
  from xp.services.conbus.conbus_discover_service import ConbusDiscoverService
46
+ from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
46
47
  from xp.services.conbus.conbus_output_service import ConbusOutputService
47
48
  from xp.services.conbus.conbus_raw_service import ConbusRawService
48
49
  from xp.services.conbus.conbus_receive_service import ConbusReceiveService
@@ -180,6 +181,14 @@ class ServiceContainer:
180
181
  scope=punq.Scope.singleton,
181
182
  )
182
183
 
184
+ self.container.register(
185
+ ConbusEventRawService,
186
+ factory=lambda: ConbusEventRawService(
187
+ conbus_protocol=self.container.resolve(ConbusEventProtocol)
188
+ ),
189
+ scope=punq.Scope.singleton,
190
+ )
191
+
183
192
  self.container.register(
184
193
  ConbusBlinkService,
185
194
  factory=lambda: ConbusBlinkService(