conson-xp 1.5.0__tar.gz → 1.7.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 (259) hide show
  1. {conson_xp-1.5.0 → conson_xp-1.7.0}/PKG-INFO +1 -1
  2. {conson_xp-1.5.0 → conson_xp-1.7.0}/pyproject.toml +1 -1
  3. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/__init__.py +1 -1
  4. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +11 -2
  5. conson_xp-1.7.0/src/xp/services/actiontable/__init__.py +1 -0
  6. conson_xp-1.7.0/src/xp/services/actiontable/msactiontable_serializer.py +7 -0
  7. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.7.0/src/xp/services}/actiontable/msactiontable_xp20_serializer.py +13 -25
  8. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.7.0/src/xp/services}/actiontable/msactiontable_xp24_serializer.py +25 -39
  9. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.7.0/src/xp/services}/actiontable/msactiontable_xp33_serializer.py +4 -21
  10. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/actiontable/actiontable_service.py +1 -1
  11. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +44 -11
  12. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/protocol/conbus_protocol.py +0 -2
  13. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/base_server_service.py +83 -5
  14. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/cp20_server_service.py +9 -1
  15. conson_xp-1.7.0/src/xp/services/server/device_service_factory.py +94 -0
  16. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/server_service.py +16 -61
  17. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/xp130_server_service.py +10 -2
  18. conson_xp-1.7.0/src/xp/services/server/xp20_server_service.py +92 -0
  19. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/xp230_server_service.py +10 -2
  20. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/xp24_server_service.py +54 -1
  21. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/xp33_server_service.py +42 -1
  22. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_service.py +4 -1
  23. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/utils/dependencies.py +27 -6
  24. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_xp20_action_table_integration.py +4 -12
  25. conson_xp-1.7.0/tests/unit/test_services/test_device_service_factory.py +149 -0
  26. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_server_service.py +108 -65
  27. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +83 -20
  28. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +13 -15
  29. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_xp24_action_table_service.py +4 -3
  30. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +12 -14
  31. conson_xp-1.5.0/src/xp/services/server/xp20_server_service.py +0 -50
  32. {conson_xp-1.5.0 → conson_xp-1.7.0}/LICENSE +0 -0
  33. {conson_xp-1.5.0 → conson_xp-1.7.0}/README.md +0 -0
  34. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/__init__.py +0 -0
  35. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/__main__.py +0 -0
  36. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/__init__.py +0 -0
  37. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
  38. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
  39. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  40. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  41. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  42. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  43. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  44. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  45. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
  46. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  47. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  48. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  49. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
  50. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
  51. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  52. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/file_commands.py +0 -0
  53. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
  54. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
  55. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
  56. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/module_commands.py +0 -0
  57. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  58. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/server/__init__.py +0 -0
  59. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/server/server_commands.py +0 -0
  60. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
  61. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
  62. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  63. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  64. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  65. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  66. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  67. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  68. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/main.py +0 -0
  69. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/__init__.py +0 -0
  70. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/click_tree.py +0 -0
  71. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  72. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/decorators.py +0 -0
  73. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/error_handlers.py +0 -0
  74. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/formatters.py +0 -0
  75. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/serial_number_type.py +0 -0
  76. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/system_function_choice.py +0 -0
  77. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/cli/utils/xp_module_type.py +0 -0
  78. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/connection/__init__.py +0 -0
  79. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/connection/exceptions.py +0 -0
  80. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/__init__.py +0 -0
  81. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/actiontable/__init__.py +0 -0
  82. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/actiontable/actiontable.py +0 -0
  83. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  84. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  85. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  86. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/__init__.py +0 -0
  87. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus.py +0 -0
  88. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  89. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_blink.py +0 -0
  90. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
  91. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  92. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_custom.py +0 -0
  93. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  94. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_discover.py +0 -0
  95. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  96. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  97. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_output.py +0 -0
  98. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_raw.py +0 -0
  99. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_receive.py +0 -0
  100. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  101. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/homekit/__init__.py +0 -0
  102. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
  103. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/homekit/homekit_config.py +0 -0
  104. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
  105. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/log_entry.py +0 -0
  106. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/protocol/__init__.py +0 -0
  107. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
  108. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/response.py +0 -0
  109. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/__init__.py +0 -0
  110. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/action_type.py +0 -0
  111. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/datapoint_type.py +0 -0
  112. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/event_telegram.py +0 -0
  113. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/event_type.py +0 -0
  114. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/input_action_type.py +0 -0
  115. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/input_type.py +0 -0
  116. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/module_type.py +0 -0
  117. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/module_type_code.py +0 -0
  118. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/output_telegram.py +0 -0
  119. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/reply_telegram.py +0 -0
  120. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/system_function.py +0 -0
  121. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/system_telegram.py +0 -0
  122. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/telegram.py +0 -0
  123. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/telegram_type.py +0 -0
  124. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/telegram/timeparam_type.py +0 -0
  125. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/models/write_config_type.py +0 -0
  126. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/__init__.py +0 -0
  127. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.7.0/src/xp/services}/actiontable/actiontable_serializer.py +0 -0
  128. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/__init__.py +0 -0
  129. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  130. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  131. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  132. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  133. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  134. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  135. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_discover_service.py +0 -0
  136. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
  137. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
  138. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_receive_service.py +0 -0
  139. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  140. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/conbus/write_config_service.py +0 -0
  141. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/__init__.py +0 -0
  142. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
  143. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
  144. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
  145. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
  146. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
  147. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
  148. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
  149. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
  150. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
  151. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
  152. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
  153. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
  154. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/homekit/homekit_service.py +0 -0
  155. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/log_file_service.py +0 -0
  156. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/module_type_service.py +0 -0
  157. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/protocol/__init__.py +0 -0
  158. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/protocol/protocol_factory.py +0 -0
  159. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
  160. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/reverse_proxy_service.py +0 -0
  161. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/server/__init__.py +0 -0
  162. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/__init__.py +0 -0
  163. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  164. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  165. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  166. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  167. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  168. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
  169. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
  170. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/utils/__init__.py +0 -0
  171. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/utils/checksum.py +0 -0
  172. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/utils/event_helper.py +0 -0
  173. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/utils/serialization.py +0 -0
  174. {conson_xp-1.5.0 → conson_xp-1.7.0}/src/xp/utils/time_utils.py +0 -0
  175. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/.coverage +0 -0
  176. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/__init__.py +0 -0
  177. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/conftest.py +0 -0
  178. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/.coverage +0 -0
  179. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/__init__.py +0 -0
  180. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/telegram_test_data.py +0 -0
  181. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_actiontable_integration.py +0 -0
  182. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_api/.coverage +0 -0
  183. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_api/__init__.py +0 -0
  184. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_blink_integration.py +0 -0
  185. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_checksum_integration.py +0 -0
  186. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_conbus_blink_integration.py +0 -0
  187. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  188. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_conbus_raw_integration.py +0 -0
  189. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_conbus_receive_integration.py +0 -0
  190. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_discovery_integration.py +0 -0
  191. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_event_telegram_integration.py +0 -0
  192. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_homekit_config_integration.py +0 -0
  193. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_link_number_integration.py +0 -0
  194. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_module_integration.py +0 -0
  195. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_output_integration.py +0 -0
  196. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
  197. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  198. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_version_integration.py +0 -0
  199. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/integration/test_xp24_action_table_integration.py +0 -0
  200. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/__init__.py +0 -0
  201. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_api/__init__.py +0 -0
  202. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/__init__.py +0 -0
  203. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_click_tree.py +0 -0
  204. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  205. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  206. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  207. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_decorators.py +0 -0
  208. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
  209. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_formatters.py +0 -0
  210. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  211. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  212. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_connection/__init__.py +0 -0
  213. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_connection/test_connection_init.py +0 -0
  214. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_connection/test_exceptions.py +0 -0
  215. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_encoding/__init__.py +0 -0
  216. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  217. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/__init__.py +0 -0
  218. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_conbus.py +0 -0
  219. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  220. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
  221. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  222. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_event_telegram.py +0 -0
  223. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_log_entry.py +0 -0
  224. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_module_type.py +0 -0
  225. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
  226. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_system_telegram.py +0 -0
  227. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  228. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_version_telegram.py +0 -0
  229. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_write_config_type.py +0 -0
  230. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  231. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  232. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  233. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/__init__.py +0 -0
  234. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
  235. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_base_server_service.py +0 -0
  236. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_blink_service.py +0 -0
  237. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_checksum_service.py +0 -0
  238. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  239. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
  240. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  241. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_discovery_service.py +0 -0
  242. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
  243. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
  244. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
  245. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_homekit_services.py +0 -0
  246. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_log_file_service.py +0 -0
  247. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_module_type_service.py +0 -0
  248. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_protocol.py +0 -0
  249. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  250. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
  251. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_telegram_service.py +0 -0
  252. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_version_service.py +0 -0
  253. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  254. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
  255. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_utils/__init__.py +0 -0
  256. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_utils/test_checksum.py +0 -0
  257. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_utils/test_event_helper.py +0 -0
  258. {conson_xp-1.5.0 → conson_xp-1.7.0}/tests/unit/test_utils/test_serialization.py +0 -0
  259. {conson_xp-1.5.0 → conson_xp-1.7.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.5.0
3
+ Version: 1.7.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.5.0"
23
+ version = "1.7.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.5.0"
6
+ __version__ = "1.7.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,
@@ -0,0 +1 @@
1
+ """Action table utils."""
@@ -0,0 +1,7 @@
1
+ """Generic MsActionTable serializer base class for type hints."""
2
+
3
+
4
+ class MsActionTableSerializer:
5
+ """Serializer for ActionTable telegram encoding/decoding."""
6
+
7
+ pass
@@ -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)
@@ -10,7 +10,7 @@ from xp.models.actiontable.actiontable import ActionTable
10
10
  from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
11
11
  from xp.models.telegram.system_function import SystemFunction
12
12
  from xp.models.telegram.telegram_type import TelegramType
13
- from xp.services.conbus.actiontable.actiontable_serializer import ActionTableSerializer
13
+ from xp.services.actiontable.actiontable_serializer import ActionTableSerializer
14
14
  from xp.services.protocol import ConbusProtocol
15
15
  from xp.services.telegram.telegram_service import TelegramService
16
16
 
@@ -12,13 +12,13 @@ from xp.models.actiontable.msactiontable_xp33 import Xp33MsActionTable
12
12
  from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
13
13
  from xp.models.telegram.system_function import SystemFunction
14
14
  from xp.models.telegram.telegram_type import TelegramType
15
- from xp.services.conbus.actiontable.msactiontable_xp20_serializer import (
15
+ from xp.services.actiontable.msactiontable_xp20_serializer import (
16
16
  Xp20MsActionTableSerializer,
17
17
  )
18
- from xp.services.conbus.actiontable.msactiontable_xp24_serializer import (
18
+ from xp.services.actiontable.msactiontable_xp24_serializer import (
19
19
  Xp24MsActionTableSerializer,
20
20
  )
21
- from xp.services.conbus.actiontable.msactiontable_xp33_serializer import (
21
+ from xp.services.actiontable.msactiontable_xp33_serializer import (
22
22
  Xp33MsActionTableSerializer,
23
23
  )
24
24
  from xp.services.protocol import ConbusProtocol
@@ -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] = []
@@ -114,17 +115,32 @@ class MsActionTableService(ConbusProtocol):
114
115
  self.logger.debug("Not a reply response")
115
116
  return
116
117
 
117
- reply_telegram = self.telegram_service.parse_reply_telegram(telegram_received)
118
+ reply_telegram = self.telegram_service.parse_reply_telegram(
119
+ telegram_received.frame
120
+ )
118
121
  if reply_telegram.system_function not in (
119
122
  SystemFunction.MSACTIONTABLE,
123
+ SystemFunction.ACK,
124
+ SystemFunction.NAK,
120
125
  SystemFunction.EOF,
121
126
  ):
122
127
  self.logger.debug("Not a msactiontable response")
123
128
  return
124
129
 
125
- if reply_telegram.system_function == SystemFunction.ACTIONTABLE:
126
- self.logger.debug("Saving msactiontable response")
127
- self.msactiontable_data.append(reply_telegram.data_value)
130
+ if reply_telegram.system_function == SystemFunction.ACK:
131
+ self.logger.debug("Received ACK")
132
+ return
133
+
134
+ if reply_telegram.system_function == SystemFunction.NAK:
135
+ self.logger.debug("Received NAK")
136
+ self.failed("Received NAK")
137
+ return
138
+
139
+ if reply_telegram.system_function == SystemFunction.MSACTIONTABLE:
140
+ self.logger.debug("Received MSACTIONTABLE")
141
+ self.msactiontable_data.extend(
142
+ (reply_telegram.data, reply_telegram.data_value)
143
+ )
128
144
  if self.progress_callback:
129
145
  self.progress_callback(".")
130
146
 
@@ -137,11 +153,14 @@ class MsActionTableService(ConbusProtocol):
137
153
  return
138
154
 
139
155
  if reply_telegram.system_function == SystemFunction.EOF:
156
+ self.logger.debug("Received EOF")
140
157
  all_data = "".join(self.msactiontable_data)
141
158
  # Deserialize from received data
142
159
  msactiontable = self.serializer.from_data(all_data)
143
- if self.finish_callback:
144
- self.finish_callback(msactiontable)
160
+ self.succeed(msactiontable)
161
+ return
162
+
163
+ self.logger.debug("Invalid msactiontable response")
145
164
 
146
165
  def failed(self, message: str) -> None:
147
166
  """Handle failed connection event.
@@ -152,6 +171,20 @@ class MsActionTableService(ConbusProtocol):
152
171
  self.logger.debug(f"Failed: {message}")
153
172
  if self.error_callback:
154
173
  self.error_callback(message)
174
+ self._stop_reactor()
175
+
176
+ def succeed(
177
+ self,
178
+ msactiontable: Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable],
179
+ ) -> None:
180
+ """Handle succeed connection event.
181
+
182
+ Args:
183
+ msactiontable: result.
184
+ """
185
+ if self.finish_callback:
186
+ self.finish_callback(msactiontable)
187
+ self._stop_reactor()
155
188
 
156
189
  def start(
157
190
  self,
@@ -160,7 +193,7 @@ class MsActionTableService(ConbusProtocol):
160
193
  progress_callback: Callable[[str], None],
161
194
  error_callback: Callable[[str], None],
162
195
  finish_callback: Callable[
163
- [Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable]], None
196
+ [Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None]], None
164
197
  ],
165
198
  timeout_seconds: Optional[float] = None,
166
199
  ) -> 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."""
@@ -7,7 +7,7 @@ containing common functionality like module type response generation.
7
7
  import logging
8
8
  import threading
9
9
  from abc import ABC
10
- from typing import Optional
10
+ from typing import Any, Optional
11
11
 
12
12
  from xp.models import ModuleTypeCode
13
13
  from xp.models.telegram.datapoint_type import DataPointType
@@ -46,6 +46,9 @@ class BaseServerService(ABC):
46
46
  self.telegram_buffer: list[str] = []
47
47
  self.telegram_buffer_lock = threading.Lock() # Lock for socket set
48
48
 
49
+ # MsActionTable download state (None, "ack_sent", "data_sent")
50
+ self.msactiontable_download_state: Optional[str] = None
51
+
49
52
  def generate_datapoint_type_response(
50
53
  self, datapoint_type: DataPointType
51
54
  ) -> Optional[str]:
@@ -151,6 +154,76 @@ class BaseServerService(ABC):
151
154
 
152
155
  return None
153
156
 
157
+ def _get_msactiontable_serializer(self) -> Optional[Any]:
158
+ """Get the MsActionTable serializer for this device.
159
+
160
+ Subclasses should override this to return their specific serializer.
161
+
162
+ Returns:
163
+ The serializer instance, or None if not supported.
164
+ """
165
+ return None
166
+
167
+ def _get_msactiontable(self) -> Optional[Any]:
168
+ """Get the MsActionTable for this device.
169
+
170
+ Subclasses should override this to return their msactiontable instance.
171
+
172
+ Returns:
173
+ The msactiontable instance, or None if not supported.
174
+ """
175
+ return None
176
+
177
+ def _handle_download_msactiontable_request(
178
+ self, request: SystemTelegram
179
+ ) -> Optional[str]:
180
+ """Handle F13D - DOWNLOAD_MSACTIONTABLE request.
181
+
182
+ Args:
183
+ request: The system telegram request to process.
184
+
185
+ Returns:
186
+ ACK telegram if request is valid, NAK otherwise.
187
+ """
188
+ serializer = self._get_msactiontable_serializer()
189
+ msactiontable = self._get_msactiontable()
190
+
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
207
+
208
+ def _handle_download_msactiontable_ack_request(
209
+ self, _request: SystemTelegram
210
+ ) -> Optional[str]:
211
+ """Handle MsActionTable download ACK protocol.
212
+
213
+ Args:
214
+ _request: The system telegram request (unused, kept for signature consistency).
215
+
216
+ Returns:
217
+ Data telegram, EOF telegram, or NAK if state is invalid.
218
+ """
219
+ if self.msactiontable_download_state == "data_sent":
220
+ # Send EOF
221
+ eof_telegram = self._build_response_telegram(f"R{self.serial_number}F16D")
222
+ self.msactiontable_download_state = None
223
+ return eof_telegram
224
+
225
+ return self._build_response_telegram(f"R{self.serial_number}F19D") # NAK
226
+
154
227
  def process_system_telegram(self, request: SystemTelegram) -> Optional[str]:
155
228
  """Template method for processing system telegrams.
156
229
 
@@ -177,6 +250,15 @@ class BaseServerService(ABC):
177
250
  elif request.system_function == SystemFunction.ACTION:
178
251
  return self._handle_action_request(request)
179
252
 
253
+ elif request.system_function == SystemFunction.DOWNLOAD_MSACTIONTABLE:
254
+ return self._handle_download_msactiontable_request(request)
255
+
256
+ elif (
257
+ request.system_function == SystemFunction.ACK
258
+ and self.msactiontable_download_state
259
+ ):
260
+ return self._handle_download_msactiontable_ack_request(request)
261
+
180
262
  self.logger.warning(f"Unhandled {self.device_type} request: {request}")
181
263
  return None
182
264
 
@@ -278,11 +360,7 @@ class BaseServerService(ABC):
278
360
  Returns:
279
361
  List of telegram strings from the buffer. The buffer is cleared after collection.
280
362
  """
281
- self.logger.debug(
282
- f"Collecting {self.serial_number} telegrams from buffer: {len(self.telegram_buffer)}"
283
- )
284
363
  with self.telegram_buffer_lock:
285
364
  result = self.telegram_buffer.copy()
286
- self.logger.debug(f"Resetting {self.serial_number} buffer")
287
365
  self.telegram_buffer.clear()
288
366
  return result
@@ -8,6 +8,7 @@ from typing import Dict, Optional
8
8
 
9
9
  from xp.models import ModuleTypeCode
10
10
  from xp.models.telegram.system_telegram import SystemTelegram
11
+ from xp.services.actiontable.msactiontable_serializer import MsActionTableSerializer
11
12
  from xp.services.server.base_server_service import BaseServerService
12
13
 
13
14
 
@@ -25,11 +26,18 @@ class CP20ServerService(BaseServerService):
25
26
  and implements CP20 telegram format.
26
27
  """
27
28
 
28
- def __init__(self, serial_number: str):
29
+ def __init__(
30
+ self,
31
+ serial_number: str,
32
+ _variant: str = "",
33
+ _msactiontable_serializer: Optional[MsActionTableSerializer] = None,
34
+ ):
29
35
  """Initialize CP20 server service.
30
36
 
31
37
  Args:
32
38
  serial_number: The device serial number.
39
+ _variant: Reserved parameter for consistency (unused).
40
+ _msactiontable_serializer: Generic MsActionTable serializer (unused).
33
41
  """
34
42
  super().__init__(serial_number)
35
43
  self.device_type = "CP20"
@@ -0,0 +1,94 @@
1
+ """Device Service Factory for creating device instances.
2
+
3
+ This module provides a factory for creating device service instances
4
+ with proper dependency injection of serializers.
5
+ """
6
+
7
+ from xp.services.actiontable.msactiontable_serializer import MsActionTableSerializer
8
+ from xp.services.actiontable.msactiontable_xp20_serializer import (
9
+ Xp20MsActionTableSerializer,
10
+ )
11
+ from xp.services.actiontable.msactiontable_xp24_serializer import (
12
+ Xp24MsActionTableSerializer,
13
+ )
14
+ from xp.services.actiontable.msactiontable_xp33_serializer import (
15
+ Xp33MsActionTableSerializer,
16
+ )
17
+ from xp.services.server.base_server_service import BaseServerService
18
+ from xp.services.server.cp20_server_service import CP20ServerService
19
+ from xp.services.server.xp20_server_service import XP20ServerService
20
+ from xp.services.server.xp24_server_service import XP24ServerService
21
+ from xp.services.server.xp33_server_service import XP33ServerService
22
+ from xp.services.server.xp130_server_service import XP130ServerService
23
+ from xp.services.server.xp230_server_service import XP230ServerService
24
+
25
+
26
+ class DeviceServiceFactory:
27
+ """Factory for creating device service instances.
28
+
29
+ Encapsulates device creation logic and handles serializer injection
30
+ for different device types.
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ xp20ms_serializer: Xp20MsActionTableSerializer,
36
+ xp24ms_serializer: Xp24MsActionTableSerializer,
37
+ xp33ms_serializer: Xp33MsActionTableSerializer,
38
+ ms_serializer: MsActionTableSerializer,
39
+ ):
40
+ """Initialize device service factory.
41
+
42
+ Args:
43
+ xp20ms_serializer: XP20 MsActionTable serializer (injected via DI).
44
+ xp24ms_serializer: XP24 MsActionTable serializer (injected via DI).
45
+ xp33ms_serializer: XP33 MsActionTable serializer (injected via DI).
46
+ ms_serializer: Generic MsActionTable serializer (injected via DI).
47
+ """
48
+ self.xp20ms_serializer = xp20ms_serializer
49
+ self.xp24ms_serializer = xp24ms_serializer
50
+ self.xp33ms_serializer = xp33ms_serializer
51
+ self.ms_serializer = ms_serializer
52
+
53
+ def create_device(self, module_type: str, serial_number: str) -> BaseServerService:
54
+ """Create device instance for given module type.
55
+
56
+ Args:
57
+ module_type: Module type code (e.g., "XP20", "XP33LR").
58
+ serial_number: Device serial number.
59
+
60
+ Returns:
61
+ Device service instance configured with appropriate serializer.
62
+
63
+ Raises:
64
+ ValueError: If module_type is unknown or unsupported.
65
+ """
66
+ # Map module types to their constructors and parameters
67
+ if module_type == "CP20":
68
+ return CP20ServerService(serial_number, "CP20", self.ms_serializer)
69
+
70
+ elif module_type == "XP24":
71
+ return XP24ServerService(serial_number, "XP24", self.xp24ms_serializer)
72
+
73
+ elif module_type == "XP33":
74
+ return XP33ServerService(serial_number, "XP33", self.xp33ms_serializer)
75
+
76
+ elif module_type == "XP33LR":
77
+ return XP33ServerService(serial_number, "XP33LR", self.xp33ms_serializer)
78
+
79
+ elif module_type == "XP33LED":
80
+ return XP33ServerService(serial_number, "XP33LED", self.xp33ms_serializer)
81
+
82
+ elif module_type == "XP20":
83
+ return XP20ServerService(serial_number, "XP20", self.xp20ms_serializer)
84
+
85
+ elif module_type == "XP130":
86
+ return XP130ServerService(serial_number, "XP130", self.ms_serializer)
87
+
88
+ elif module_type == "XP230":
89
+ return XP230ServerService(serial_number, "XP230", self.ms_serializer)
90
+
91
+ else:
92
+ raise ValueError(
93
+ f"Unknown device type '{module_type}' for serial {serial_number}"
94
+ )