conson-xp 1.6.0__tar.gz → 1.8.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 (258) hide show
  1. {conson_xp-1.6.0 → conson_xp-1.8.0}/PKG-INFO +1 -1
  2. {conson_xp-1.6.0 → conson_xp-1.8.0}/pyproject.toml +1 -1
  3. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/__init__.py +1 -1
  4. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +11 -2
  5. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/input_action_type.py +2 -2
  6. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp20_serializer.py +13 -25
  7. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp24_serializer.py +25 -39
  8. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_xp33_serializer.py +4 -21
  9. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/actiontable_service.py +6 -2
  10. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +44 -9
  11. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/conbus_protocol.py +0 -2
  12. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/base_server_service.py +19 -30
  13. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/server_service.py +1 -8
  14. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_service.py +4 -1
  15. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/dependencies.py +6 -0
  16. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_xp20_action_table_integration.py +4 -12
  17. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_xp24_action_table_integration.py +2 -2
  18. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +82 -19
  19. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +12 -14
  20. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp24_action_table_service.py +4 -3
  21. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +12 -14
  22. {conson_xp-1.6.0 → conson_xp-1.8.0}/LICENSE +0 -0
  23. {conson_xp-1.6.0 → conson_xp-1.8.0}/README.md +0 -0
  24. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/__init__.py +0 -0
  25. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/__main__.py +0 -0
  26. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/__init__.py +0 -0
  27. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
  28. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
  29. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  30. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  31. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  32. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  33. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  34. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  35. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
  36. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  37. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  38. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  39. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
  40. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
  41. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  42. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/file_commands.py +0 -0
  43. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
  44. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
  45. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
  46. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/module_commands.py +0 -0
  47. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  48. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/server/__init__.py +0 -0
  49. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/server/server_commands.py +0 -0
  50. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
  51. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
  52. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  53. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  54. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  55. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  56. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  57. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  58. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/main.py +0 -0
  59. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/__init__.py +0 -0
  60. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/click_tree.py +0 -0
  61. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  62. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/decorators.py +0 -0
  63. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/error_handlers.py +0 -0
  64. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/formatters.py +0 -0
  65. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/serial_number_type.py +0 -0
  66. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/system_function_choice.py +0 -0
  67. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/cli/utils/xp_module_type.py +0 -0
  68. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/connection/__init__.py +0 -0
  69. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/connection/exceptions.py +0 -0
  70. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/__init__.py +0 -0
  71. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/__init__.py +0 -0
  72. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/actiontable.py +0 -0
  73. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  74. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  75. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  76. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/__init__.py +0 -0
  77. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus.py +0 -0
  78. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  79. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_blink.py +0 -0
  80. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
  81. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  82. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_custom.py +0 -0
  83. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  84. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_discover.py +0 -0
  85. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  86. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  87. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_output.py +0 -0
  88. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_raw.py +0 -0
  89. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_receive.py +0 -0
  90. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  91. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/__init__.py +0 -0
  92. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
  93. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/homekit_config.py +0 -0
  94. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
  95. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/log_entry.py +0 -0
  96. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/protocol/__init__.py +0 -0
  97. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
  98. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/response.py +0 -0
  99. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/__init__.py +0 -0
  100. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/action_type.py +0 -0
  101. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/datapoint_type.py +0 -0
  102. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/event_telegram.py +0 -0
  103. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/event_type.py +0 -0
  104. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/input_type.py +0 -0
  105. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/module_type.py +0 -0
  106. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/module_type_code.py +0 -0
  107. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/output_telegram.py +0 -0
  108. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/reply_telegram.py +0 -0
  109. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/system_function.py +0 -0
  110. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/system_telegram.py +0 -0
  111. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/telegram.py +0 -0
  112. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/telegram_type.py +0 -0
  113. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/telegram/timeparam_type.py +0 -0
  114. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/models/write_config_type.py +0 -0
  115. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/__init__.py +0 -0
  116. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/__init__.py +0 -0
  117. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/actiontable_serializer.py +0 -0
  118. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/actiontable/msactiontable_serializer.py +0 -0
  119. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/__init__.py +0 -0
  120. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  121. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  122. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  123. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  124. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  125. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  126. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_discover_service.py +0 -0
  127. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
  128. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
  129. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_receive_service.py +0 -0
  130. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  131. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/conbus/write_config_service.py +0 -0
  132. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/__init__.py +0 -0
  133. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
  134. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
  135. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
  136. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
  137. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
  138. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
  139. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
  140. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
  141. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
  142. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
  143. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
  144. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
  145. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/homekit/homekit_service.py +0 -0
  146. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/log_file_service.py +0 -0
  147. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/module_type_service.py +0 -0
  148. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/__init__.py +0 -0
  149. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/protocol_factory.py +0 -0
  150. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
  151. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/reverse_proxy_service.py +0 -0
  152. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/__init__.py +0 -0
  153. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/cp20_server_service.py +0 -0
  154. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/device_service_factory.py +0 -0
  155. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp130_server_service.py +0 -0
  156. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp20_server_service.py +0 -0
  157. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp230_server_service.py +0 -0
  158. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp24_server_service.py +0 -0
  159. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/server/xp33_server_service.py +0 -0
  160. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/__init__.py +0 -0
  161. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  162. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  163. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  164. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  165. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  166. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
  167. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
  168. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/__init__.py +0 -0
  169. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/checksum.py +0 -0
  170. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/event_helper.py +0 -0
  171. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/serialization.py +0 -0
  172. {conson_xp-1.6.0 → conson_xp-1.8.0}/src/xp/utils/time_utils.py +0 -0
  173. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/.coverage +0 -0
  174. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/__init__.py +0 -0
  175. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/conftest.py +0 -0
  176. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/.coverage +0 -0
  177. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/__init__.py +0 -0
  178. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/telegram_test_data.py +0 -0
  179. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_actiontable_integration.py +0 -0
  180. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_api/.coverage +0 -0
  181. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_api/__init__.py +0 -0
  182. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_blink_integration.py +0 -0
  183. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_checksum_integration.py +0 -0
  184. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_blink_integration.py +0 -0
  185. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  186. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_raw_integration.py +0 -0
  187. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_conbus_receive_integration.py +0 -0
  188. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_discovery_integration.py +0 -0
  189. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_event_telegram_integration.py +0 -0
  190. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_homekit_config_integration.py +0 -0
  191. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_link_number_integration.py +0 -0
  192. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_module_integration.py +0 -0
  193. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_output_integration.py +0 -0
  194. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
  195. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  196. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/integration/test_version_integration.py +0 -0
  197. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/__init__.py +0 -0
  198. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_api/__init__.py +0 -0
  199. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/__init__.py +0 -0
  200. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_click_tree.py +0 -0
  201. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  202. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  203. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  204. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_decorators.py +0 -0
  205. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
  206. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_formatters.py +0 -0
  207. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  208. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  209. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_connection/__init__.py +0 -0
  210. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_connection/test_connection_init.py +0 -0
  211. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_connection/test_exceptions.py +0 -0
  212. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_encoding/__init__.py +0 -0
  213. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  214. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/__init__.py +0 -0
  215. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus.py +0 -0
  216. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  217. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
  218. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  219. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_event_telegram.py +0 -0
  220. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_log_entry.py +0 -0
  221. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_module_type.py +0 -0
  222. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
  223. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_system_telegram.py +0 -0
  224. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  225. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_version_telegram.py +0 -0
  226. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_write_config_type.py +0 -0
  227. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  228. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  229. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  230. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/__init__.py +0 -0
  231. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
  232. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_base_server_service.py +0 -0
  233. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_blink_service.py +0 -0
  234. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_checksum_service.py +0 -0
  235. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  236. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
  237. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  238. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_device_service_factory.py +0 -0
  239. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_discovery_service.py +0 -0
  240. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
  241. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
  242. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
  243. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_homekit_services.py +0 -0
  244. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_log_file_service.py +0 -0
  245. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_module_type_service.py +0 -0
  246. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_protocol.py +0 -0
  247. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_server_service.py +0 -0
  248. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  249. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
  250. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_telegram_service.py +0 -0
  251. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_version_service.py +0 -0
  252. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  253. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
  254. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/__init__.py +0 -0
  255. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/test_checksum.py +0 -0
  256. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/test_event_helper.py +0 -0
  257. {conson_xp-1.6.0 → conson_xp-1.8.0}/tests/unit/test_utils/test_serialization.py +0 -0
  258. {conson_xp-1.6.0 → conson_xp-1.8.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.6.0
3
+ Version: 1.8.0
4
4
  Summary: XP Protocol Communication Tools
5
5
  Author-Email: ldvchosal <ldvchosal@github.com>
6
6
  License: MIT License
@@ -20,7 +20,7 @@ dependencies = [
20
20
  ]
21
21
  requires-python = ">=3.11"
22
22
  readme = "README.md"
23
- version = "1.6.0"
23
+ version = "1.8.0"
24
24
 
25
25
  [project.license]
26
26
  file = "LICENSE"
@@ -3,7 +3,7 @@
3
3
  conson-xp package.
4
4
  """
5
5
 
6
- __version__ = "1.6.0"
6
+ __version__ = "1.8.0"
7
7
  __manufacturer__ = "salchichon"
8
8
  __model__ = "xp.cli"
9
9
  __serial__ = "2025.09.23.000"
@@ -49,13 +49,22 @@ def conbus_download_msactiontable(
49
49
  click.echo(progress, nl=False)
50
50
 
51
51
  def on_finish(
52
- action_table: Union[Xp20MsActionTable | Xp24MsActionTable | Xp33MsActionTable],
52
+ action_table: Union[
53
+ Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None
54
+ ],
53
55
  ) -> None:
54
56
  """Handle successful completion of MS action table download.
55
57
 
56
58
  Args:
57
- action_table: Downloaded MS action table object.
59
+ action_table: Downloaded MS action table object or None if failed.
60
+
61
+ Raises:
62
+ Abort: If action table download failed.
58
63
  """
64
+ if action_table is None:
65
+ click.echo("Error: Failed to download MS action table")
66
+ raise click.Abort()
67
+
59
68
  output = {
60
69
  "serial_number": serial_number,
61
70
  "xpmoduletype": xpmoduletype,
@@ -1,9 +1,9 @@
1
1
  """Input action types for XP24 module based on Feature-Action-Table.md."""
2
2
 
3
- from enum import IntEnum
3
+ from enum import Enum
4
4
 
5
5
 
6
- class InputActionType(IntEnum):
6
+ class InputActionType(Enum):
7
7
  """Input action types for XP24 module (based on Feature-Action-Table.md).
8
8
 
9
9
  Attributes:
@@ -46,8 +46,9 @@ class Xp20MsActionTableSerializer:
46
46
  input_channel, input_index, raw_bytes
47
47
  )
48
48
 
49
+ encoded_data = nibbles(raw_bytes)
49
50
  # Convert raw bytes to hex string with A-P encoding
50
- return nibbles(raw_bytes)
51
+ return "AAAA" + encoded_data
51
52
 
52
53
  @staticmethod
53
54
  def from_data(msactiontable_rawdata: str) -> Xp20MsActionTable:
@@ -62,13 +63,20 @@ class Xp20MsActionTableSerializer:
62
63
  Raises:
63
64
  ValueError: If input length is not 64 characters
64
65
  """
65
- if len(msactiontable_rawdata) != 64:
66
+ raw_length = len(msactiontable_rawdata)
67
+ if raw_length < 68: # Minimum: 4 char prefix + 64 chars data
66
68
  raise ValueError(
67
- f"XP20 action table data must be 64 characters long, got {len(msactiontable_rawdata)}"
69
+ f"XP20 action table data must be 68 characters long, got {len(msactiontable_rawdata)}"
68
70
  )
69
71
 
70
- # Convert hex string to bytes using de_nibble (A-P encoding)
71
- raw_bytes = de_nibbles(msactiontable_rawdata)
72
+ # Remove action table count prefix (first 4 characters: AAAA, AAAB, etc.)
73
+ data = msactiontable_rawdata[4:]
74
+
75
+ # Take first 64 chars (32 bytes) as per pseudocode
76
+ hex_data = data[:64]
77
+
78
+ # Convert hex string to bytes using deNibble (A-P encoding)
79
+ raw_bytes = de_nibbles(hex_data)
72
80
 
73
81
  # Decode input channels
74
82
  input_channels = []
@@ -159,23 +167,3 @@ class Xp20MsActionTableSerializer:
159
167
  and_functions_byte |= 1 << bit_index
160
168
 
161
169
  raw_bytes[AND_FUNCTIONS_INDEX + input_index] = and_functions_byte
162
-
163
- @staticmethod
164
- def from_telegrams(ms_telegrams: str) -> Xp20MsActionTable:
165
- """Legacy method for backward compatibility. Use from_data() instead.
166
-
167
- Args:
168
- ms_telegrams: Full telegram string
169
-
170
- Returns:
171
- Decoded XP20 action table
172
- """
173
- # Extract data portion from telegram (skip header, take action table data)
174
- # Based on XP24 pattern: telegram[16:84] gives us the 68-char data portion
175
- # For XP20, we need 64 chars, so we take the first 64 chars after removing count
176
- data_parts = ms_telegrams[16:84]
177
-
178
- # Remove action table count (first 4 chars: AAAA, AAAB, etc.)
179
- hex_data = data_parts[4:68] # Take 64 chars after count
180
-
181
- return Xp20MsActionTableSerializer.from_data(hex_data)
@@ -3,7 +3,7 @@
3
3
  from xp.models.actiontable.msactiontable_xp24 import InputAction, Xp24MsActionTable
4
4
  from xp.models.telegram.input_action_type import InputActionType
5
5
  from xp.models.telegram.timeparam_type import TimeParam
6
- from xp.utils.serialization import de_nibbles
6
+ from xp.utils.serialization import de_nibbles, nibbles
7
7
 
8
8
 
9
9
  class Xp24MsActionTableSerializer:
@@ -17,11 +17,12 @@ class Xp24MsActionTableSerializer:
17
17
  action_table: XP24 MS action table to serialize.
18
18
 
19
19
  Returns:
20
- Serialized action table data string.
20
+ Serialized action table data string (68 characters).
21
21
  """
22
- data_parts: list[str] = []
22
+ # Build byte array for the action table (32 bytes total)
23
+ raw_bytes = bytearray()
23
24
 
24
- # Encode all 4 input actions
25
+ # Encode all 4 input actions (2 bytes each = 8 bytes total)
25
26
  input_actions = [
26
27
  action_table.input1_action,
27
28
  action_table.input2_action,
@@ -30,26 +31,24 @@ class Xp24MsActionTableSerializer:
30
31
  ]
31
32
 
32
33
  for action in input_actions:
33
- # Use enum value directly as function ID
34
- function_id = action.type.value
35
- # Convert parameter to int (None becomes 0)
36
- param_id = action.param.value
37
- data_parts.append(f"{function_id:02X}{param_id:02X}")
38
-
39
- # Add settings as hex values
40
- data_parts.extend(
41
- [
42
- "AB" if action_table.mutex12 else "AA",
43
- "AB" if action_table.mutex34 else "AA",
44
- f"{action_table.mutual_deadtime:02X}",
45
- "AB" if action_table.curtain12 else "AA",
46
- "AB" if action_table.curtain34 else "AA",
47
- "A" * 38, # padding
48
- ]
49
- )
34
+ raw_bytes.append(action.type.value)
35
+ raw_bytes.append(action.param.value)
36
+
37
+ # Add settings (5 bytes)
38
+ raw_bytes.append(0x01 if action_table.mutex12 else 0x00)
39
+ raw_bytes.append(0x01 if action_table.mutex34 else 0x00)
40
+ raw_bytes.append(action_table.mutual_deadtime)
41
+ raw_bytes.append(0x01 if action_table.curtain12 else 0x00)
42
+ raw_bytes.append(0x01 if action_table.curtain34 else 0x00)
43
+
44
+ # Add padding to reach 32 bytes (19 more bytes needed)
45
+ raw_bytes.extend([0x00] * 19)
46
+
47
+ # Encode to A-P nibbles (32 bytes -> 64 chars)
48
+ encoded_data = nibbles(bytes(raw_bytes))
50
49
 
51
- data = "AAAA".join(data_parts)
52
- return data
50
+ # Prepend action table count "AAAA" (4 chars) -> total 68 chars
51
+ return "AAAA" + encoded_data
53
52
 
54
53
  @staticmethod
55
54
  def from_data(msactiontable_rawdata: str) -> Xp24MsActionTable:
@@ -66,7 +65,9 @@ class Xp24MsActionTableSerializer:
66
65
  """
67
66
  raw_length = len(msactiontable_rawdata)
68
67
  if raw_length != 68:
69
- raise ValueError(f"Msactiontable is not 68 bytes long ({raw_length})")
68
+ raise ValueError(
69
+ f"Msactiontable is not 68 bytes long ({raw_length}): {msactiontable_rawdata}"
70
+ )
70
71
 
71
72
  # Remove action table count AAAA, AAAB .
72
73
  data = msactiontable_rawdata[4:]
@@ -117,18 +118,3 @@ class Xp24MsActionTableSerializer:
117
118
  param_type = TimeParam(param_id)
118
119
 
119
120
  return InputAction(action_type, param_type)
120
-
121
- @staticmethod
122
- def from_telegrams(ms_telegrams: str) -> Xp24MsActionTable:
123
- """Legacy method for backward compatibility. Use from_data() instead.
124
-
125
- Args:
126
- ms_telegrams: Telegram data string.
127
-
128
- Returns:
129
- Deserialized XP24 MS action table.
130
- """
131
- # For backward compatibility, assume full telegrams and extract data
132
- data_parts = ms_telegrams[16:84]
133
-
134
- return Xp24MsActionTableSerializer.from_data(data_parts)
@@ -6,7 +6,7 @@ from xp.models.actiontable.msactiontable_xp33 import (
6
6
  Xp33Scene,
7
7
  )
8
8
  from xp.models.telegram.timeparam_type import TimeParam
9
- from xp.utils.serialization import bits_to_byte, byte_to_bits, de_nibbles, nibble
9
+ from xp.utils.serialization import bits_to_byte, byte_to_bits, de_nibbles, nibbles
10
10
 
11
11
 
12
12
  class Xp33MsActionTableSerializer:
@@ -96,13 +96,11 @@ class Xp33MsActionTableSerializer:
96
96
  raw_bytes[24] = bits_to_byte(leading_edge_bits)
97
97
 
98
98
  # Bytes 25-31 are padding (already 0)
99
-
100
99
  # Convert to hex string using nibble encoding
101
- hex_data = "AAAA"
102
- for byte_val in raw_bytes:
103
- hex_data += nibble(byte_val)
100
+ encoded_data = nibbles(raw_bytes)
104
101
 
105
- return hex_data
102
+ # Convert raw bytes to hex string with A-P encoding
103
+ return "AAAA" + encoded_data
106
104
 
107
105
  @staticmethod
108
106
  def from_data(msactiontable_rawdata: str) -> Xp33MsActionTable:
@@ -239,18 +237,3 @@ class Xp33MsActionTableSerializer:
239
237
  output3_level=output3_level,
240
238
  time=time_param,
241
239
  )
242
-
243
- @staticmethod
244
- def from_telegrams(ms_telegrams: str) -> Xp33MsActionTable:
245
- """Legacy method for backward compatibility. Use from_data() instead.
246
-
247
- Args:
248
- ms_telegrams: Telegram data string.
249
-
250
- Returns:
251
- Deserialized XP33 MS action table.
252
- """
253
- # For backward compatibility, assume full telegrams and extract data
254
- data_parts = ms_telegrams[16:152] # Adjusted for XP33 length
255
-
256
- return Xp33MsActionTableSerializer.from_data(data_parts)
@@ -51,7 +51,9 @@ class ActionTableService(ConbusProtocol):
51
51
 
52
52
  def connection_established(self) -> None:
53
53
  """Handle connection established event."""
54
- self.logger.debug("Connection established, sending discover telegram")
54
+ self.logger.debug(
55
+ "Connection established, sending download actiontable telegram"
56
+ )
55
57
  self.send_telegram(
56
58
  telegram_type=TelegramType.SYSTEM,
57
59
  serial_number=self.serial_number,
@@ -82,7 +84,9 @@ class ActionTableService(ConbusProtocol):
82
84
  self.logger.debug("Not a reply response")
83
85
  return
84
86
 
85
- reply_telegram = self.telegram_service.parse_reply_telegram(telegram_received)
87
+ reply_telegram = self.telegram_service.parse_reply_telegram(
88
+ telegram_received.frame
89
+ )
86
90
  if reply_telegram.system_function not in (
87
91
  SystemFunction.ACTIONTABLE,
88
92
  SystemFunction.EOF,
@@ -74,7 +74,8 @@ class MsActionTableService(ConbusProtocol):
74
74
  self.error_callback: Optional[Callable[[str], None]] = None
75
75
  self.finish_callback: Optional[
76
76
  Callable[
77
- [Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable]], None
77
+ [Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None]],
78
+ None,
78
79
  ]
79
80
  ] = None
80
81
  self.msactiontable_data: list[str] = []
@@ -83,7 +84,9 @@ class MsActionTableService(ConbusProtocol):
83
84
 
84
85
  def connection_established(self) -> None:
85
86
  """Handle connection established event."""
86
- self.logger.debug("Connection established, sending discover telegram")
87
+ self.logger.debug(
88
+ "Connection established, sending download msactiontable telegram"
89
+ )
87
90
  self.send_telegram(
88
91
  telegram_type=TelegramType.SYSTEM,
89
92
  serial_number=self.serial_number,
@@ -114,17 +117,32 @@ class MsActionTableService(ConbusProtocol):
114
117
  self.logger.debug("Not a reply response")
115
118
  return
116
119
 
117
- reply_telegram = self.telegram_service.parse_reply_telegram(telegram_received)
120
+ reply_telegram = self.telegram_service.parse_reply_telegram(
121
+ telegram_received.frame
122
+ )
118
123
  if reply_telegram.system_function not in (
119
124
  SystemFunction.MSACTIONTABLE,
125
+ SystemFunction.ACK,
126
+ SystemFunction.NAK,
120
127
  SystemFunction.EOF,
121
128
  ):
122
129
  self.logger.debug("Not a msactiontable response")
123
130
  return
124
131
 
125
- if reply_telegram.system_function == SystemFunction.ACTIONTABLE:
126
- self.logger.debug("Saving msactiontable response")
127
- self.msactiontable_data.append(reply_telegram.data_value)
132
+ if reply_telegram.system_function == SystemFunction.ACK:
133
+ self.logger.debug("Received ACK")
134
+ return
135
+
136
+ if reply_telegram.system_function == SystemFunction.NAK:
137
+ self.logger.debug("Received NAK")
138
+ self.failed("Received NAK")
139
+ return
140
+
141
+ if reply_telegram.system_function == SystemFunction.MSACTIONTABLE:
142
+ self.logger.debug("Received MSACTIONTABLE")
143
+ self.msactiontable_data.extend(
144
+ (reply_telegram.data, reply_telegram.data_value)
145
+ )
128
146
  if self.progress_callback:
129
147
  self.progress_callback(".")
130
148
 
@@ -137,11 +155,14 @@ class MsActionTableService(ConbusProtocol):
137
155
  return
138
156
 
139
157
  if reply_telegram.system_function == SystemFunction.EOF:
158
+ self.logger.debug("Received EOF")
140
159
  all_data = "".join(self.msactiontable_data)
141
160
  # Deserialize from received data
142
161
  msactiontable = self.serializer.from_data(all_data)
143
- if self.finish_callback:
144
- self.finish_callback(msactiontable)
162
+ self.succeed(msactiontable)
163
+ return
164
+
165
+ self.logger.debug("Invalid msactiontable response")
145
166
 
146
167
  def failed(self, message: str) -> None:
147
168
  """Handle failed connection event.
@@ -152,6 +173,20 @@ class MsActionTableService(ConbusProtocol):
152
173
  self.logger.debug(f"Failed: {message}")
153
174
  if self.error_callback:
154
175
  self.error_callback(message)
176
+ self._stop_reactor()
177
+
178
+ def succeed(
179
+ self,
180
+ msactiontable: Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable],
181
+ ) -> None:
182
+ """Handle succeed connection event.
183
+
184
+ Args:
185
+ msactiontable: result.
186
+ """
187
+ if self.finish_callback:
188
+ self.finish_callback(msactiontable)
189
+ self._stop_reactor()
155
190
 
156
191
  def start(
157
192
  self,
@@ -160,7 +195,7 @@ class MsActionTableService(ConbusProtocol):
160
195
  progress_callback: Callable[[str], None],
161
196
  error_callback: Callable[[str], None],
162
197
  finish_callback: Callable[
163
- [Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable]], None
198
+ [Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None]], None
164
199
  ],
165
200
  timeout_seconds: Optional[float] = None,
166
201
  ) -> None:
@@ -230,13 +230,11 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
230
230
  self.timeout_call = self.reactor.callLater(
231
231
  self.timeout_seconds, self._on_timeout
232
232
  )
233
- self.logger.debug(f"Timeout set for {self.timeout_seconds} seconds")
234
233
 
235
234
  def _cancel_timeout(self) -> None:
236
235
  """Cancel the inactivity timeout."""
237
236
  if self.timeout_call and self.timeout_call.active():
238
237
  self.timeout_call.cancel()
239
- self.logger.debug("Timeout cancelled")
240
238
 
241
239
  def _on_timeout(self) -> None:
242
240
  """Handle inactivity timeout expiration."""
@@ -185,15 +185,25 @@ class BaseServerService(ABC):
185
185
  Returns:
186
186
  ACK telegram if request is valid, NAK otherwise.
187
187
  """
188
- if (
189
- request.system_function == SystemFunction.DOWNLOAD_MSACTIONTABLE
190
- and self.msactiontable_download_state is None
191
- ):
192
- self.msactiontable_download_state = "ack_sent"
193
- # Send ACK and queue data telegram
194
- return self._build_response_telegram(f"R{self.serial_number}F18D") # ACK
188
+ serializer = self._get_msactiontable_serializer()
189
+ msactiontable = self._get_msactiontable()
195
190
 
196
- return self._build_response_telegram(f"R{self.serial_number}F19D") # NAK
191
+ # Only handle if serializer and msactiontable are available
192
+ if not serializer or msactiontable is None:
193
+ return None
194
+
195
+ # Send ACK and queue data telegram
196
+ ack_data = self._build_response_telegram(f"R{self.serial_number}F18D") # ACK
197
+
198
+ # Send MsActionTable data
199
+ encoded_data = serializer.to_data(msactiontable)
200
+ data_telegram = self._build_response_telegram(
201
+ f"R{self.serial_number}F17D{encoded_data}"
202
+ )
203
+ self.msactiontable_download_state = "data_sent"
204
+
205
+ # Return ACK and TABLE
206
+ return ack_data + data_telegram
197
207
 
198
208
  def _handle_download_msactiontable_ack_request(
199
209
  self, _request: SystemTelegram
@@ -206,24 +216,7 @@ class BaseServerService(ABC):
206
216
  Returns:
207
217
  Data telegram, EOF telegram, or NAK if state is invalid.
208
218
  """
209
- serializer = self._get_msactiontable_serializer()
210
- msactiontable = self._get_msactiontable()
211
-
212
- # Only handle if serializer and msactiontable are available
213
- if not serializer or msactiontable is None:
214
- return None
215
-
216
- # Handle F18D - CONTINUE (after ACK or data)
217
- if self.msactiontable_download_state == "ack_sent":
218
- # Send MsActionTable data
219
- encoded_data = serializer.to_data(msactiontable)
220
- data_telegram = self._build_response_telegram(
221
- f"R{self.serial_number}F17D{encoded_data}"
222
- )
223
- self.msactiontable_download_state = "data_sent"
224
- return data_telegram
225
-
226
- elif self.msactiontable_download_state == "data_sent":
219
+ if self.msactiontable_download_state == "data_sent":
227
220
  # Send EOF
228
221
  eof_telegram = self._build_response_telegram(f"R{self.serial_number}F16D")
229
222
  self.msactiontable_download_state = None
@@ -367,11 +360,7 @@ class BaseServerService(ABC):
367
360
  Returns:
368
361
  List of telegram strings from the buffer. The buffer is cleared after collection.
369
362
  """
370
- self.logger.debug(
371
- f"Collecting {self.serial_number} telegrams from buffer: {len(self.telegram_buffer)}"
372
- )
373
363
  with self.telegram_buffer_lock:
374
364
  result = self.telegram_buffer.copy()
375
- self.logger.debug(f"Resetting {self.serial_number} buffer")
376
365
  self.telegram_buffer.clear()
377
366
  return result
@@ -209,14 +209,11 @@ class ServerService:
209
209
  self.logger.debug(f"Sent buffer to {client_address}")
210
210
 
211
211
  # Receive data from client
212
- self.logger.debug(f"Receiving data {client_address}")
213
212
  data = None
214
213
  try:
215
214
  data = client_socket.recv(1024)
216
215
  except socket.timeout:
217
- self.logger.debug(
218
- f"Timeout receiving data {client_address} ({timeout})"
219
- )
216
+ pass
220
217
  finally:
221
218
  timeout -= 1
222
219
 
@@ -421,9 +418,6 @@ class ServerService:
421
418
  self.logger.info("Collector thread starting")
422
419
 
423
420
  while True:
424
- self.logger.debug(
425
- f"Collector thread collecting ({len(self.collector_buffer)})"
426
- )
427
421
  collected = 0
428
422
  for device_service in self.device_services.values():
429
423
  telegram_buffer = device_service.collect_telegram_buffer()
@@ -431,5 +425,4 @@ class ServerService:
431
425
  collected += len(telegram_buffer)
432
426
 
433
427
  # Wait a bit before checking again
434
- self.logger.debug(f"Collector thread collected ({collected})")
435
428
  self.collector_stop_event.wait(timeout=1)
@@ -3,6 +3,7 @@
3
3
  This module provides telegram parsing functionality for event, system, and reply telegrams.
4
4
  """
5
5
 
6
+ import logging
6
7
  import re
7
8
  from typing import Union
8
9
 
@@ -48,7 +49,8 @@ class TelegramService:
48
49
 
49
50
  def __init__(self) -> None:
50
51
  """Initialize the telegram service."""
51
- pass
52
+ # Set up logging
53
+ self.logger = logging.getLogger(__name__)
52
54
 
53
55
  def parse_event_telegram(self, raw_telegram: str) -> EventTelegram:
54
56
  """Parse a raw telegram string into an EventTelegram object.
@@ -242,6 +244,7 @@ class TelegramService:
242
244
  raise TelegramParsingError("Empty telegram string")
243
245
 
244
246
  # Validate and parse using regex
247
+ self.logger.debug(f"Parsing reply telegram {raw_telegram}")
245
248
  match = self.REPLY_TELEGRAM_PATTERN.match(raw_telegram.strip())
246
249
  if not match:
247
250
  raise TelegramParsingError(f"Invalid reply telegram format: {raw_telegram}")
@@ -326,6 +326,12 @@ class ServiceContainer:
326
326
  # Module type services layer
327
327
  self.container.register(ModuleTypeService, scope=punq.Scope.singleton)
328
328
 
329
+ # MsActionTable serializers
330
+ self.container.register(MsActionTableSerializer, scope=punq.Scope.singleton)
331
+ self.container.register(Xp20MsActionTableSerializer, scope=punq.Scope.singleton)
332
+ self.container.register(Xp24MsActionTableSerializer, scope=punq.Scope.singleton)
333
+ self.container.register(Xp33MsActionTableSerializer, scope=punq.Scope.singleton)
334
+
329
335
  # Device service factory
330
336
  self.container.register(
331
337
  DeviceServiceFactory,
@@ -33,16 +33,8 @@ class TestXp20ActionTableIntegration:
33
33
  # Serialize it
34
34
  serialized = Xp20MsActionTableSerializer.to_data(action_table)
35
35
 
36
- # Create mock telegram data
37
- mock_telegram = (
38
- "0123456789ABCDEF" # 16 chars header
39
- "AAAA"
40
- + serialized # 4 chars count + 64 chars data
41
- + "PADDING" # Additional padding
42
- )
43
-
44
- # Test legacy from_telegrams method
45
- result = Xp20MsActionTableSerializer.from_telegrams(mock_telegram)
36
+ # Deserialize from data
37
+ result = Xp20MsActionTableSerializer.from_data(serialized)
46
38
 
47
39
  # Verify the round-trip worked
48
40
  assert result.input1.invert == action_table.input1.invert
@@ -166,7 +158,7 @@ class TestXp20ActionTableIntegration:
166
158
  def test_specification_compliance(self):
167
159
  """Test compliance with the specification example."""
168
160
  spec_example = (
169
- "AAAAAAAAAAABACAEAIBACAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
161
+ "AAAAAAAAAAAAAAABACAEAIBACAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
170
162
  )
171
163
 
172
164
  # Should decode without errors
@@ -177,7 +169,7 @@ class TestXp20ActionTableIntegration:
177
169
 
178
170
  # Test that we can re-encode it
179
171
  re_encoded = Xp20MsActionTableSerializer.to_data(result)
180
- assert len(re_encoded) == 64
172
+ assert len(re_encoded) == 68
181
173
 
182
174
  # Round-trip should work
183
175
  final_result = Xp20MsActionTableSerializer.from_data(re_encoded)
@@ -92,9 +92,9 @@ class TestXp24ActionTableIntegration:
92
92
 
93
93
  # Verify action table structure
94
94
  action_table = output["action_table"]
95
- assert action_table["input1_action"]["type"] == InputActionType.TOGGLE.value
95
+ assert action_table["input1_action"]["type"] == str(InputActionType.TOGGLE)
96
96
  assert action_table["input1_action"]["param"] == TimeParam.NONE.value
97
- assert action_table["input2_action"]["type"] == InputActionType.TURNON.value
97
+ assert action_table["input2_action"]["type"] == str(InputActionType.TURNON)
98
98
  assert action_table["input2_action"]["param"] == TimeParam.T5SEC.value
99
99
  assert action_table["mutex34"] is True
100
100
  assert action_table["curtain34"] is True