conson-xp 1.18.0__tar.gz → 1.19.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 (273) hide show
  1. {conson_xp-1.18.0 → conson_xp-1.19.0}/PKG-INFO +2 -1
  2. {conson_xp-1.18.0 → conson_xp-1.19.0}/README.md +1 -0
  3. {conson_xp-1.18.0 → conson_xp-1.19.0}/pyproject.toml +1 -1
  4. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/__init__.py +1 -1
  5. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_event_commands.py +25 -0
  6. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/__init__.py +2 -0
  7. conson_xp-1.19.0/src/xp/models/conbus/conbus_event_list.py +34 -0
  8. conson_xp-1.19.0/src/xp/services/conbus/conbus_event_list_service.py +91 -0
  9. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/utils/dependencies.py +9 -0
  10. conson_xp-1.19.0/tests/unit/test_services/test_conbus_event_list_service.py +272 -0
  11. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_telegram_service.py +19 -0
  12. {conson_xp-1.18.0 → conson_xp-1.19.0}/LICENSE +0 -0
  13. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/__init__.py +0 -0
  14. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/__main__.py +0 -0
  15. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/__init__.py +0 -0
  16. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
  17. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
  18. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  19. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  20. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  21. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  22. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  23. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  24. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
  25. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  26. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  27. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_modulenumber_commands.py +0 -0
  28. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +0 -0
  29. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  30. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
  31. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
  32. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  33. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/file_commands.py +0 -0
  34. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
  35. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
  36. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
  37. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/module_commands.py +0 -0
  38. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  39. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/server/__init__.py +0 -0
  40. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/server/server_commands.py +0 -0
  41. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
  42. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
  43. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  44. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  45. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  46. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  47. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  48. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  49. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/main.py +0 -0
  50. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/__init__.py +0 -0
  51. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/click_tree.py +0 -0
  52. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  53. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/decorators.py +0 -0
  54. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/error_handlers.py +0 -0
  55. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/formatters.py +0 -0
  56. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/module_type_choice.py +0 -0
  57. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/serial_number_type.py +0 -0
  58. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/system_function_choice.py +0 -0
  59. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/cli/utils/xp_module_type.py +0 -0
  60. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/connection/__init__.py +0 -0
  61. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/connection/exceptions.py +0 -0
  62. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/actiontable/__init__.py +0 -0
  63. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/actiontable/actiontable.py +0 -0
  64. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  65. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  66. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  67. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/__init__.py +0 -0
  68. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus.py +0 -0
  69. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  70. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_blink.py +0 -0
  71. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
  72. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  73. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_custom.py +0 -0
  74. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  75. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_discover.py +0 -0
  76. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_event_raw.py +0 -0
  77. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  78. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  79. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_output.py +0 -0
  80. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_raw.py +0 -0
  81. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_receive.py +0 -0
  82. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  83. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/homekit/__init__.py +0 -0
  84. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
  85. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/homekit/homekit_config.py +0 -0
  86. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
  87. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/log_entry.py +0 -0
  88. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/protocol/__init__.py +0 -0
  89. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
  90. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/response.py +0 -0
  91. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/__init__.py +0 -0
  92. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/action_type.py +0 -0
  93. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/datapoint_type.py +0 -0
  94. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/event_telegram.py +0 -0
  95. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/event_type.py +0 -0
  96. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/input_action_type.py +0 -0
  97. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/input_type.py +0 -0
  98. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/module_type.py +0 -0
  99. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/module_type_code.py +0 -0
  100. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/output_telegram.py +0 -0
  101. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/reply_telegram.py +0 -0
  102. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/system_function.py +0 -0
  103. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/system_telegram.py +0 -0
  104. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/telegram.py +0 -0
  105. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/telegram_type.py +0 -0
  106. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/telegram/timeparam_type.py +0 -0
  107. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/models/write_config_type.py +0 -0
  108. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/__init__.py +0 -0
  109. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/actiontable/__init__.py +0 -0
  110. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/actiontable/actiontable_serializer.py +0 -0
  111. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
  112. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +0 -0
  113. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +0 -0
  114. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +0 -0
  115. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/__init__.py +0 -0
  116. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  117. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/actiontable/actiontable_download_service.py +0 -0
  118. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/actiontable/actiontable_list_service.py +0 -0
  119. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/actiontable/actiontable_show_service.py +0 -0
  120. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/actiontable/actiontable_upload_service.py +0 -0
  121. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +0 -0
  122. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  123. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  124. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  125. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  126. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  127. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_discover_service.py +0 -0
  128. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_event_raw_service.py +0 -0
  129. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
  130. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
  131. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_receive_service.py +0 -0
  132. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  133. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/conbus/write_config_service.py +0 -0
  134. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/__init__.py +0 -0
  135. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
  136. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
  137. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
  138. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
  139. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
  140. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
  141. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
  142. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
  143. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
  144. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
  145. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
  146. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
  147. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/homekit/homekit_service.py +0 -0
  148. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/log_file_service.py +0 -0
  149. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/module_type_service.py +0 -0
  150. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/protocol/__init__.py +0 -0
  151. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/protocol/conbus_event_protocol.py +0 -0
  152. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/protocol/conbus_protocol.py +0 -0
  153. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/protocol/protocol_factory.py +0 -0
  154. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
  155. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/reverse_proxy_service.py +0 -0
  156. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/__init__.py +0 -0
  157. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/base_server_service.py +0 -0
  158. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/cp20_server_service.py +0 -0
  159. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/device_service_factory.py +0 -0
  160. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/server_service.py +0 -0
  161. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/xp130_server_service.py +0 -0
  162. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/xp20_server_service.py +0 -0
  163. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/xp230_server_service.py +0 -0
  164. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/xp24_server_service.py +0 -0
  165. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/server/xp33_server_service.py +0 -0
  166. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/__init__.py +0 -0
  167. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  168. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  169. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  170. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  171. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  172. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
  173. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_service.py +0 -0
  174. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
  175. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/utils/__init__.py +0 -0
  176. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/utils/checksum.py +0 -0
  177. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/utils/event_helper.py +0 -0
  178. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/utils/serialization.py +0 -0
  179. {conson_xp-1.18.0 → conson_xp-1.19.0}/src/xp/utils/time_utils.py +0 -0
  180. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/.coverage +0 -0
  181. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/__init__.py +0 -0
  182. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/conftest.py +0 -0
  183. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/.coverage +0 -0
  184. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/__init__.py +0 -0
  185. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/telegram_test_data.py +0 -0
  186. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_actiontable_integration.py +0 -0
  187. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_api/.coverage +0 -0
  188. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_api/__init__.py +0 -0
  189. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_blink_integration.py +0 -0
  190. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_checksum_integration.py +0 -0
  191. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_conbus_blink_integration.py +0 -0
  192. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  193. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_conbus_raw_integration.py +0 -0
  194. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_conbus_receive_integration.py +0 -0
  195. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_discovery_integration.py +0 -0
  196. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_event_telegram_integration.py +0 -0
  197. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_homekit_config_integration.py +0 -0
  198. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_link_number_integration.py +0 -0
  199. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_module_integration.py +0 -0
  200. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_output_integration.py +0 -0
  201. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
  202. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  203. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_version_integration.py +0 -0
  204. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_xp20_action_table_integration.py +0 -0
  205. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/integration/test_xp24_action_table_integration.py +0 -0
  206. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/__init__.py +0 -0
  207. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_api/__init__.py +0 -0
  208. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/__init__.py +0 -0
  209. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_click_tree.py +0 -0
  210. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  211. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  212. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  213. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_decorators.py +0 -0
  214. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
  215. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_formatters.py +0 -0
  216. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  217. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  218. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_connection/__init__.py +0 -0
  219. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_connection/test_connection_init.py +0 -0
  220. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_connection/test_exceptions.py +0 -0
  221. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_encoding/__init__.py +0 -0
  222. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  223. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/__init__.py +0 -0
  224. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_conbus.py +0 -0
  225. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  226. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
  227. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  228. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_event_telegram.py +0 -0
  229. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_log_entry.py +0 -0
  230. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_module_type.py +0 -0
  231. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
  232. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_system_telegram.py +0 -0
  233. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  234. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_version_telegram.py +0 -0
  235. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_write_config_type.py +0 -0
  236. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  237. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  238. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  239. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/__init__.py +0 -0
  240. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_actiontable_serializer.py +0 -0
  241. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
  242. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_actiontable_upload_service.py +0 -0
  243. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_base_server_service.py +0 -0
  244. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_blink_service.py +0 -0
  245. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_checksum_service.py +0 -0
  246. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  247. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_conbus_event_raw_service.py +0 -0
  248. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
  249. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  250. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_device_service_factory.py +0 -0
  251. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_discovery_service.py +0 -0
  252. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
  253. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
  254. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
  255. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_homekit_services.py +0 -0
  256. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_log_file_service.py +0 -0
  257. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_module_type_service.py +0 -0
  258. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_protocol.py +0 -0
  259. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_server_service.py +0 -0
  260. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  261. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
  262. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_version_service.py +0 -0
  263. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +0 -0
  264. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  265. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +0 -0
  266. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_xp24_action_table_service.py +0 -0
  267. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +0 -0
  268. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
  269. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_utils/__init__.py +0 -0
  270. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_utils/test_checksum.py +0 -0
  271. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_utils/test_event_helper.py +0 -0
  272. {conson_xp-1.18.0 → conson_xp-1.19.0}/tests/unit/test_utils/test_serialization.py +0 -0
  273. {conson_xp-1.18.0 → conson_xp-1.19.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.18.0
3
+ Version: 1.19.0
4
4
  Summary: XP Protocol Communication Tools
5
5
  Author-Email: ldvchosal <ldvchosal@github.com>
6
6
  License: MIT License
@@ -306,6 +306,7 @@ xp conbus datapoint query
306
306
  xp conbus discover
307
307
 
308
308
  xp conbus event
309
+ xp conbus event list
309
310
  xp conbus event raw
310
311
 
311
312
 
@@ -254,6 +254,7 @@ xp conbus datapoint query
254
254
  xp conbus discover
255
255
 
256
256
  xp conbus event
257
+ xp conbus event list
257
258
  xp conbus event raw
258
259
 
259
260
 
@@ -21,7 +21,7 @@ dependencies = [
21
21
  ]
22
22
  requires-python = ">=3.11"
23
23
  readme = "README.md"
24
- version = "1.18.0"
24
+ version = "1.19.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.18.0"
6
+ __version__ = "1.19.0"
7
7
  __manufacturer__ = "salchichon"
8
8
  __model__ = "xp.cli"
9
9
  __serial__ = "2025.09.23.000"
@@ -8,6 +8,7 @@ from xp.cli.commands.conbus.conbus import conbus
8
8
  from xp.cli.utils.decorators import connection_command
9
9
  from xp.cli.utils.module_type_choice import MODULE_TYPE
10
10
  from xp.models import ConbusEventRawResponse
11
+ from xp.services.conbus.conbus_event_list_service import ConbusEventListService
11
12
  from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
12
13
 
13
14
 
@@ -17,6 +18,30 @@ def conbus_event() -> None:
17
18
  pass
18
19
 
19
20
 
21
+ @conbus_event.command("list")
22
+ @click.pass_context
23
+ def list_events(ctx: click.Context) -> None:
24
+ r"""List configured event telegrams from module action tables.
25
+
26
+ Reads conson.yml configuration, parses action tables, and groups
27
+ modules by their event keys to show which modules are assigned to
28
+ each event (button configuration).
29
+
30
+ Output is sorted by module count (most frequently used events first).
31
+
32
+ Args:
33
+ ctx: Click context object.
34
+
35
+ Examples:
36
+ \b
37
+ xp conbus event list
38
+ """
39
+ service: ConbusEventListService = (
40
+ ctx.obj.get("container").get_container().resolve(ConbusEventListService)
41
+ )
42
+ click.echo(json.dumps(service.list_events().to_dict(), indent=2))
43
+
44
+
20
45
  @conbus_event.command("raw")
21
46
  @click.argument("module_type", type=MODULE_TYPE)
22
47
  @click.argument("link_number", type=click.IntRange(0, 99))
@@ -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_list import ConbusEventListResponse
8
9
  from xp.models.conbus.conbus_event_raw import ConbusEventRawResponse
9
10
  from xp.models.log_entry import LogEntry
10
11
  from xp.models.telegram.event_telegram import EventTelegram
@@ -31,6 +32,7 @@ __all__ = [
31
32
  "ConbusResponse",
32
33
  "ConbusDatapointResponse",
33
34
  "ConbusDiscoverResponse",
35
+ "ConbusEventListResponse",
34
36
  "ConbusEventRawResponse",
35
37
  "ConbusConnectionStatus",
36
38
  ]
@@ -0,0 +1,34 @@
1
+ """Conbus event list 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 ConbusEventListResponse:
10
+ """Represents a response from Conbus event list operation.
11
+
12
+ Attributes:
13
+ events: Dict mapping event keys to list of module names.
14
+ timestamp: Timestamp of the response.
15
+ """
16
+
17
+ events: Dict[str, list[str]]
18
+ timestamp: Optional[datetime] = None
19
+
20
+ def __post_init__(self) -> None:
21
+ """Initialize timestamp if not provided."""
22
+ if self.timestamp is None:
23
+ self.timestamp = datetime.now()
24
+
25
+ def to_dict(self) -> Dict[str, Any]:
26
+ """Convert to dictionary for JSON serialization.
27
+
28
+ Returns:
29
+ Dictionary representation of the response.
30
+ """
31
+ return {
32
+ "events": self.events,
33
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
34
+ }
@@ -0,0 +1,91 @@
1
+ """Conbus Event List Service for listing configured event telegrams.
2
+
3
+ This service parses action tables from conson.yml and groups events
4
+ by button configuration to show which modules are assigned to each event.
5
+ """
6
+
7
+ import logging
8
+ from collections import defaultdict
9
+ from typing import Dict, List
10
+
11
+ from xp.models import ConbusEventListResponse
12
+ from xp.models.homekit.homekit_conson_config import ConsonModuleListConfig
13
+ from xp.services.actiontable.actiontable_serializer import ActionTableSerializer
14
+
15
+
16
+ class ConbusEventListService:
17
+ """Service for listing configured event telegrams from action tables.
18
+
19
+ Parses action tables from conson.yml configuration and groups modules
20
+ by their event keys to identify common button configurations.
21
+
22
+ Attributes:
23
+ conson_config: Configuration containing module action tables.
24
+ logger: Logger instance for the service.
25
+ """
26
+
27
+ def __init__(self, conson_config: ConsonModuleListConfig) -> None:
28
+ """Initialize the Conbus event list service.
29
+
30
+ Args:
31
+ conson_config: ConsonModuleListConfig instance with module action tables.
32
+ """
33
+ self.conson_config = conson_config
34
+ self.logger = logging.getLogger(__name__)
35
+
36
+ def list_events(self) -> ConbusEventListResponse:
37
+ """List all configured events from module action tables.
38
+
39
+ Parses action tables, extracts event information (module_type, link, input),
40
+ groups modules by event key, and sorts by usage count.
41
+
42
+ Returns:
43
+ ConbusEventListResponse with events dict mapping event keys to module names.
44
+ """
45
+ # Dict to track which modules are assigned to each event
46
+ # event_key -> set of module names (using set for automatic deduplication)
47
+ event_modules: Dict[str, set[str]] = defaultdict(set)
48
+
49
+ # Process each module's action table
50
+ for module in self.conson_config.root:
51
+ # Skip modules without action table
52
+ if not module.action_table:
53
+ continue
54
+
55
+ # Process each action in the module's action table
56
+ for action in module.action_table:
57
+ try:
58
+ # Use existing ActionTableSerializer to parse action
59
+ entry = ActionTableSerializer.parse_action_string(action)
60
+
61
+ # Extract event data from parsed entry
62
+ module_type_name = entry.module_type.name
63
+ link = entry.link_number
64
+ input_num = entry.module_input
65
+
66
+ # Create event key (space-separated format)
67
+ event_key = f"{module_type_name} {link:02d} {input_num:02d}"
68
+
69
+ # Add this module to the event (set automatically deduplicates)
70
+ event_modules[event_key].add(
71
+ f"{module.serial_number}:{entry.module_output}"
72
+ )
73
+
74
+ except ValueError as e:
75
+ # Invalid action format - log warning and skip
76
+ self.logger.warning(
77
+ f"Invalid action '{action}' in module '{module.serial_number}': {e}"
78
+ )
79
+ continue
80
+
81
+ # Convert sets to sorted lists and sort events by module count (descending)
82
+ events_dict: Dict[str, List[str]] = {
83
+ event_key: sorted(list(modules))
84
+ for event_key, modules in sorted(
85
+ event_modules.items(),
86
+ key=lambda item: len(item[1]),
87
+ reverse=True,
88
+ )
89
+ }
90
+
91
+ return ConbusEventListResponse(events=events_dict)
@@ -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_list_service import ConbusEventListService
46
47
  from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
47
48
  from xp.services.conbus.conbus_output_service import ConbusOutputService
48
49
  from xp.services.conbus.conbus_raw_service import ConbusRawService
@@ -189,6 +190,14 @@ class ServiceContainer:
189
190
  scope=punq.Scope.singleton,
190
191
  )
191
192
 
193
+ self.container.register(
194
+ ConbusEventListService,
195
+ factory=lambda: ConbusEventListService(
196
+ conson_config=self.container.resolve(ConsonModuleListConfig)
197
+ ),
198
+ scope=punq.Scope.singleton,
199
+ )
200
+
192
201
  self.container.register(
193
202
  ConbusBlinkService,
194
203
  factory=lambda: ConbusBlinkService(
@@ -0,0 +1,272 @@
1
+ """Unit tests for ConbusEventListService."""
2
+
3
+ import pytest
4
+
5
+ from xp.models.homekit.homekit_conson_config import (
6
+ ConsonModuleConfig,
7
+ ConsonModuleListConfig,
8
+ )
9
+ from xp.services.conbus.conbus_event_list_service import ConbusEventListService
10
+
11
+
12
+ class TestConbusEventListService:
13
+ """Unit tests for ConbusEventListService functionality."""
14
+
15
+ @pytest.fixture
16
+ def empty_config(self):
17
+ """Create empty config with no modules."""
18
+ return ConsonModuleListConfig(root=[])
19
+
20
+ @pytest.fixture
21
+ def single_module_config(self):
22
+ """Create config with single module and one action."""
23
+ module = ConsonModuleConfig(
24
+ name="A1",
25
+ serial_number="0012345001",
26
+ module_type="XP20",
27
+ module_type_code=33,
28
+ link_number=0,
29
+ action_table=["XP20 10 0 > 0 OFF"],
30
+ )
31
+ return ConsonModuleListConfig(root=[module])
32
+
33
+ @pytest.fixture
34
+ def multiple_modules_same_event_config(self):
35
+ """Create config with multiple modules sharing same event."""
36
+ module1 = ConsonModuleConfig(
37
+ name="A1",
38
+ serial_number="0012345001",
39
+ module_type="XP20",
40
+ module_type_code=33,
41
+ link_number=0,
42
+ action_table=["XP20 10 0 > 0 OFF"],
43
+ )
44
+ module2 = ConsonModuleConfig(
45
+ name="A2",
46
+ serial_number="0012345002",
47
+ module_type="XP20",
48
+ module_type_code=33,
49
+ link_number=0,
50
+ action_table=["XP20 10 0 > 1 ON"],
51
+ )
52
+ module3 = ConsonModuleConfig(
53
+ name="A3",
54
+ serial_number="0012345003",
55
+ module_type="XP20",
56
+ module_type_code=33,
57
+ link_number=0,
58
+ action_table=["XP20 10 0 > 2 OFF"],
59
+ )
60
+ return ConsonModuleListConfig(root=[module1, module2, module3])
61
+
62
+ @pytest.fixture
63
+ def duplicate_actions_config(self):
64
+ """Create config with duplicate actions in same module."""
65
+ module = ConsonModuleConfig(
66
+ name="A1",
67
+ serial_number="0012345001",
68
+ module_type="XP20",
69
+ module_type_code=33,
70
+ link_number=0,
71
+ action_table=[
72
+ "XP20 10 0 > 0 OFF",
73
+ "XP20 10 0 > 1 OFF",
74
+ "XP20 10 0 > 2 OFF",
75
+ ],
76
+ )
77
+ return ConsonModuleListConfig(root=[module])
78
+
79
+ @pytest.fixture
80
+ def invalid_action_config(self):
81
+ """Create config with invalid action format."""
82
+ module = ConsonModuleConfig(
83
+ name="A1",
84
+ serial_number="0012345001",
85
+ module_type="XP20",
86
+ module_type_code=33,
87
+ link_number=0,
88
+ action_table=[
89
+ "XP20 10 0 > 0 OFF", # Valid
90
+ "INVALID ACTION FORMAT", # Invalid
91
+ "XP20 10 8 > 0 ON", # Valid
92
+ ],
93
+ )
94
+ return ConsonModuleListConfig(root=[module])
95
+
96
+ @pytest.fixture
97
+ def empty_action_table_config(self):
98
+ """Create config with module having empty action table."""
99
+ module1 = ConsonModuleConfig(
100
+ name="A1",
101
+ serial_number="0012345001",
102
+ module_type="XP20",
103
+ module_type_code=33,
104
+ link_number=0,
105
+ action_table=[],
106
+ )
107
+ module2 = ConsonModuleConfig(
108
+ name="A2",
109
+ serial_number="0012345002",
110
+ module_type="XP20",
111
+ module_type_code=33,
112
+ link_number=0,
113
+ action_table=["XP20 10 0 > 0 OFF"],
114
+ )
115
+ return ConsonModuleListConfig(root=[module1, module2])
116
+
117
+ @pytest.fixture
118
+ def sorting_config(self):
119
+ """Create config for testing sorting by module count."""
120
+ # Event XP20 10 00 has 3 modules
121
+ module1 = ConsonModuleConfig(
122
+ name="A1",
123
+ serial_number="0012345001",
124
+ module_type="XP20",
125
+ module_type_code=33,
126
+ link_number=0,
127
+ action_table=["XP20 10 0 > 0 OFF"],
128
+ )
129
+ module2 = ConsonModuleConfig(
130
+ name="A2",
131
+ serial_number="0012345002",
132
+ module_type="XP20",
133
+ module_type_code=33,
134
+ link_number=0,
135
+ action_table=["XP20 10 0 > 1 ON"],
136
+ )
137
+ module3 = ConsonModuleConfig(
138
+ name="A3",
139
+ serial_number="0012345003",
140
+ module_type="XP20",
141
+ module_type_code=33,
142
+ link_number=0,
143
+ action_table=["XP20 10 0 > 2 OFF"],
144
+ )
145
+ # Event XP20 10 08 has 2 modules
146
+ module4 = ConsonModuleConfig(
147
+ name="A4",
148
+ serial_number="0012345004",
149
+ module_type="XP20",
150
+ module_type_code=33,
151
+ link_number=0,
152
+ action_table=["XP20 10 8 > 0 ON"],
153
+ )
154
+ module5 = ConsonModuleConfig(
155
+ name="A5",
156
+ serial_number="0012345005",
157
+ module_type="XP20",
158
+ module_type_code=33,
159
+ link_number=0,
160
+ action_table=["XP20 10 8 > 1 OFF"],
161
+ )
162
+ # Event CP20 00 00 has 1 module
163
+ module6 = ConsonModuleConfig(
164
+ name="A6",
165
+ serial_number="0012345006",
166
+ module_type="CP20",
167
+ module_type_code=2,
168
+ link_number=0,
169
+ action_table=["CP20 0 0 > 0 OFF"],
170
+ )
171
+ return ConsonModuleListConfig(
172
+ root=[module1, module2, module3, module4, module5, module6]
173
+ )
174
+
175
+ def test_empty_config(self, empty_config):
176
+ """Test with empty configuration (no modules)."""
177
+ response = ConbusEventListService(conson_config=empty_config).list_events()
178
+
179
+ assert response.events == {}
180
+ assert response.timestamp is not None
181
+
182
+ def test_single_module(self, single_module_config):
183
+ """Test with single module and one action."""
184
+ response = ConbusEventListService(
185
+ conson_config=single_module_config
186
+ ).list_events()
187
+
188
+ assert len(response.events) == 1
189
+ assert "XP20 10 00" in response.events
190
+ assert response.events["XP20 10 00"] == ["0012345001:0"]
191
+
192
+ def test_multiple_modules_same_event(self, multiple_modules_same_event_config):
193
+ """Test multiple modules sharing same event."""
194
+ response = ConbusEventListService(
195
+ conson_config=multiple_modules_same_event_config
196
+ ).list_events()
197
+
198
+ assert len(response.events) == 1
199
+ assert "XP20 10 00" in response.events
200
+ assert sorted(response.events["XP20 10 00"]) == [
201
+ "0012345001:0",
202
+ "0012345002:1",
203
+ "0012345003:2",
204
+ ]
205
+
206
+ def test_duplicate_actions_deduplication(self, duplicate_actions_config):
207
+ """Test that duplicate actions in same module are deduplicated."""
208
+ response = ConbusEventListService(
209
+ conson_config=duplicate_actions_config
210
+ ).list_events()
211
+
212
+ assert len(response.events) == 1
213
+ assert "XP20 10 00" in response.events
214
+ assert response.events["XP20 10 00"] == [
215
+ "0012345001:0",
216
+ "0012345001:1",
217
+ "0012345001:2",
218
+ ] # Only once, not three times
219
+
220
+ def test_invalid_action_format(self, invalid_action_config, caplog):
221
+ """Test that invalid actions are skipped with warning."""
222
+ response = ConbusEventListService(
223
+ conson_config=invalid_action_config
224
+ ).list_events()
225
+
226
+ # Should have 2 valid events
227
+ assert len(response.events) == 2
228
+ assert "XP20 10 00" in response.events
229
+ assert "XP20 10 08" in response.events
230
+
231
+ # Should have logged warning about invalid action
232
+ assert "Invalid action" in caplog.text
233
+ assert "INVALID ACTION FORMAT" in caplog.text
234
+
235
+ def test_empty_action_table(self, empty_action_table_config):
236
+ """Test that modules with empty action table are silently skipped."""
237
+ response = ConbusEventListService(
238
+ conson_config=empty_action_table_config
239
+ ).list_events()
240
+
241
+ # Only A2 should be in result (A1 has empty action_table)
242
+ assert len(response.events) == 1
243
+ assert "XP20 10 00" in response.events
244
+ assert response.events["XP20 10 00"] == ["0012345002:0"]
245
+
246
+ def test_sorting_by_module_count(self, sorting_config):
247
+ """Test that events are sorted by module count (descending)."""
248
+ response = ConbusEventListService(conson_config=sorting_config).list_events()
249
+
250
+ # Get events in order
251
+ event_keys = list(response.events.keys())
252
+
253
+ # Should be sorted by count: XP20 10 00 (3), XP20 10 08 (2), CP20 00 00 (1)
254
+ assert event_keys[0] == "XP20 10 00"
255
+ assert len(response.events[event_keys[0]]) == 3
256
+ assert event_keys[1] == "XP20 10 08"
257
+ assert len(response.events[event_keys[1]]) == 2
258
+ assert event_keys[2] == "CP20 00 00"
259
+ assert len(response.events[event_keys[2]]) == 1
260
+
261
+ def test_to_dict_serialization(self, single_module_config):
262
+ """Test that response can be serialized to dict."""
263
+ result_dict = (
264
+ ConbusEventListService(conson_config=single_module_config)
265
+ .list_events()
266
+ .to_dict()
267
+ )
268
+
269
+ assert "events" in result_dict
270
+ assert "timestamp" in result_dict
271
+ assert isinstance(result_dict["events"], dict)
272
+ assert isinstance(result_dict["timestamp"], str) # ISO format
@@ -383,6 +383,25 @@ class TestReplyTelegramParsing:
383
383
  assert "Timestamp:" in summary
384
384
  assert "Checksum: IL" in summary
385
385
 
386
+ def test_parse_actiontable_reply_telegram(self):
387
+ """Test parsing an actiontable reply telegram (F17).
388
+
389
+ This tests a real actiontable telegram received from a module.
390
+ The F17 function code indicates ACTIONTABLE data response.
391
+ """
392
+ raw = "<R0020042796F17DAAAADDBAAABAAADDBAAABBAADDBAAABCAADDBAAIAIAADDBAAIAJAA>"
393
+ result = self.service.parse_reply_telegram(raw)
394
+
395
+ assert isinstance(result, ReplyTelegram)
396
+ assert result.serial_number == "0020042796"
397
+ assert result.system_function == SystemFunction.ACTIONTABLE
398
+ assert result.data == "AA"
399
+ assert result.data_value == "AADDBAAABAAADDBAAABBAADDBAAABCAADDBAAIAIAADDBAAIAJ"
400
+ assert result.checksum == "AA"
401
+ assert not result.checksum_validated
402
+ assert result.raw_telegram == raw
403
+ assert result.timestamp is not None
404
+
386
405
 
387
406
  class TestAutoDetectTelegramParsing:
388
407
  """Test cases for auto-detect telegram parsing in TelegramService."""
File without changes