conson-xp 1.5.0__tar.gz → 1.6.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.6.0}/PKG-INFO +1 -1
  2. {conson_xp-1.5.0 → conson_xp-1.6.0}/pyproject.toml +1 -1
  3. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/__init__.py +1 -1
  4. conson_xp-1.6.0/src/xp/services/actiontable/__init__.py +1 -0
  5. conson_xp-1.6.0/src/xp/services/actiontable/msactiontable_serializer.py +7 -0
  6. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/actiontable/actiontable_service.py +1 -1
  7. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/actiontable/msactiontable_service.py +3 -3
  8. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/base_server_service.py +90 -1
  9. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/cp20_server_service.py +9 -1
  10. conson_xp-1.6.0/src/xp/services/server/device_service_factory.py +94 -0
  11. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/server_service.py +15 -53
  12. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/xp130_server_service.py +10 -2
  13. conson_xp-1.6.0/src/xp/services/server/xp20_server_service.py +92 -0
  14. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/xp230_server_service.py +10 -2
  15. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/xp24_server_service.py +54 -1
  16. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/xp33_server_service.py +42 -1
  17. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/utils/dependencies.py +21 -6
  18. conson_xp-1.6.0/tests/unit/test_services/test_device_service_factory.py +149 -0
  19. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_server_service.py +108 -65
  20. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_xp20_action_table_serializer.py +1 -1
  21. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_xp24_action_table_serializer.py +1 -1
  22. conson_xp-1.5.0/src/xp/services/server/xp20_server_service.py +0 -50
  23. {conson_xp-1.5.0 → conson_xp-1.6.0}/LICENSE +0 -0
  24. {conson_xp-1.5.0 → conson_xp-1.6.0}/README.md +0 -0
  25. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/__init__.py +0 -0
  26. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/__main__.py +0 -0
  27. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/__init__.py +0 -0
  28. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/__init__.py +0 -0
  29. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus.py +0 -0
  30. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_actiontable_commands.py +0 -0
  31. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_autoreport_commands.py +0 -0
  32. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_blink_commands.py +0 -0
  33. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_config_commands.py +0 -0
  34. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_custom_commands.py +0 -0
  35. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_datapoint_commands.py +0 -0
  36. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_discover_commands.py +0 -0
  37. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_lightlevel_commands.py +0 -0
  38. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_linknumber_commands.py +0 -0
  39. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_msactiontable_commands.py +0 -0
  40. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_output_commands.py +0 -0
  41. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_raw_commands.py +0 -0
  42. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_receive_commands.py +0 -0
  43. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/conbus/conbus_scan_commands.py +0 -0
  44. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/file_commands.py +0 -0
  45. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/homekit/__init__.py +0 -0
  46. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/homekit/homekit.py +0 -0
  47. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/homekit/homekit_start_commands.py +0 -0
  48. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/module_commands.py +0 -0
  49. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/reverse_proxy_commands.py +0 -0
  50. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/server/__init__.py +0 -0
  51. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/server/server_commands.py +0 -0
  52. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/__init__.py +0 -0
  53. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/telegram.py +0 -0
  54. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/telegram_blink_commands.py +0 -0
  55. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/telegram_checksum_commands.py +0 -0
  56. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/telegram_discover_commands.py +0 -0
  57. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/telegram_linknumber_commands.py +0 -0
  58. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/telegram_parse_commands.py +0 -0
  59. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/commands/telegram/telegram_version_commands.py +0 -0
  60. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/main.py +0 -0
  61. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/__init__.py +0 -0
  62. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/click_tree.py +0 -0
  63. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/datapoint_type_choice.py +0 -0
  64. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/decorators.py +0 -0
  65. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/error_handlers.py +0 -0
  66. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/formatters.py +0 -0
  67. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/serial_number_type.py +0 -0
  68. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/system_function_choice.py +0 -0
  69. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/cli/utils/xp_module_type.py +0 -0
  70. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/connection/__init__.py +0 -0
  71. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/connection/exceptions.py +0 -0
  72. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/__init__.py +0 -0
  73. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/actiontable/__init__.py +0 -0
  74. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/actiontable/actiontable.py +0 -0
  75. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/actiontable/msactiontable_xp20.py +0 -0
  76. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/actiontable/msactiontable_xp24.py +0 -0
  77. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/actiontable/msactiontable_xp33.py +0 -0
  78. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/__init__.py +0 -0
  79. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus.py +0 -0
  80. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_autoreport.py +0 -0
  81. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_blink.py +0 -0
  82. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_client_config.py +0 -0
  83. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_connection_status.py +0 -0
  84. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_custom.py +0 -0
  85. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_datapoint.py +0 -0
  86. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_discover.py +0 -0
  87. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_lightlevel.py +0 -0
  88. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_linknumber.py +0 -0
  89. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_output.py +0 -0
  90. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_raw.py +0 -0
  91. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_receive.py +0 -0
  92. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/conbus/conbus_writeconfig.py +0 -0
  93. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/homekit/__init__.py +0 -0
  94. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/homekit/homekit_accessory.py +0 -0
  95. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/homekit/homekit_config.py +0 -0
  96. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/homekit/homekit_conson_config.py +0 -0
  97. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/log_entry.py +0 -0
  98. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/protocol/__init__.py +0 -0
  99. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/protocol/conbus_protocol.py +0 -0
  100. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/response.py +0 -0
  101. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/__init__.py +0 -0
  102. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/action_type.py +0 -0
  103. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/datapoint_type.py +0 -0
  104. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/event_telegram.py +0 -0
  105. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/event_type.py +0 -0
  106. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/input_action_type.py +0 -0
  107. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/input_type.py +0 -0
  108. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/module_type.py +0 -0
  109. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/module_type_code.py +0 -0
  110. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/output_telegram.py +0 -0
  111. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/reply_telegram.py +0 -0
  112. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/system_function.py +0 -0
  113. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/system_telegram.py +0 -0
  114. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/telegram.py +0 -0
  115. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/telegram_type.py +0 -0
  116. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/telegram/timeparam_type.py +0 -0
  117. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/models/write_config_type.py +0 -0
  118. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/__init__.py +0 -0
  119. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.6.0/src/xp/services}/actiontable/actiontable_serializer.py +0 -0
  120. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.6.0/src/xp/services}/actiontable/msactiontable_xp20_serializer.py +0 -0
  121. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.6.0/src/xp/services}/actiontable/msactiontable_xp24_serializer.py +0 -0
  122. {conson_xp-1.5.0/src/xp/services/conbus → conson_xp-1.6.0/src/xp/services}/actiontable/msactiontable_xp33_serializer.py +0 -0
  123. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/__init__.py +0 -0
  124. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/actiontable/__init__.py +0 -0
  125. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_blink_all_service.py +0 -0
  126. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_blink_service.py +0 -0
  127. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_custom_service.py +0 -0
  128. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_datapoint_queryall_service.py +0 -0
  129. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_datapoint_service.py +0 -0
  130. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_discover_service.py +0 -0
  131. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_output_service.py +0 -0
  132. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_raw_service.py +0 -0
  133. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_receive_service.py +0 -0
  134. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/conbus_scan_service.py +0 -0
  135. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/conbus/write_config_service.py +0 -0
  136. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/__init__.py +0 -0
  137. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_cache_service.py +0 -0
  138. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_conbus_service.py +0 -0
  139. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_config_validator.py +0 -0
  140. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_conson_validator.py +0 -0
  141. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_dimminglight.py +0 -0
  142. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_dimminglight_service.py +0 -0
  143. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_hap_service.py +0 -0
  144. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_lightbulb.py +0 -0
  145. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_lightbulb_service.py +0 -0
  146. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_module_service.py +0 -0
  147. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_outlet.py +0 -0
  148. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_outlet_service.py +0 -0
  149. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/homekit/homekit_service.py +0 -0
  150. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/log_file_service.py +0 -0
  151. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/module_type_service.py +0 -0
  152. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/protocol/__init__.py +0 -0
  153. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/protocol/conbus_protocol.py +0 -0
  154. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/protocol/protocol_factory.py +0 -0
  155. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/protocol/telegram_protocol.py +0 -0
  156. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/reverse_proxy_service.py +0 -0
  157. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/server/__init__.py +0 -0
  158. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/__init__.py +0 -0
  159. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_blink_service.py +0 -0
  160. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_checksum_service.py +0 -0
  161. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_datapoint_service.py +0 -0
  162. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_discover_service.py +0 -0
  163. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_link_number_service.py +0 -0
  164. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_output_service.py +0 -0
  165. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_service.py +0 -0
  166. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/services/telegram/telegram_version_service.py +0 -0
  167. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/utils/__init__.py +0 -0
  168. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/utils/checksum.py +0 -0
  169. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/utils/event_helper.py +0 -0
  170. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/utils/serialization.py +0 -0
  171. {conson_xp-1.5.0 → conson_xp-1.6.0}/src/xp/utils/time_utils.py +0 -0
  172. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/.coverage +0 -0
  173. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/__init__.py +0 -0
  174. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/conftest.py +0 -0
  175. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/.coverage +0 -0
  176. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/__init__.py +0 -0
  177. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/telegram_test_data.py +0 -0
  178. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_actiontable_integration.py +0 -0
  179. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_api/.coverage +0 -0
  180. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_api/__init__.py +0 -0
  181. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_blink_integration.py +0 -0
  182. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_checksum_integration.py +0 -0
  183. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_conbus_blink_integration.py +0 -0
  184. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_conbus_datapoint_integration.py +0 -0
  185. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_conbus_raw_integration.py +0 -0
  186. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_conbus_receive_integration.py +0 -0
  187. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_discovery_integration.py +0 -0
  188. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_event_telegram_integration.py +0 -0
  189. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_homekit_config_integration.py +0 -0
  190. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_link_number_integration.py +0 -0
  191. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_module_integration.py +0 -0
  192. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_output_integration.py +0 -0
  193. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_reverse_proxy_integration.py +0 -0
  194. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_system_reply_telegram_integration.py +0 -0
  195. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_version_integration.py +0 -0
  196. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_xp20_action_table_integration.py +0 -0
  197. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/integration/test_xp24_action_table_integration.py +0 -0
  198. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/__init__.py +0 -0
  199. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_api/__init__.py +0 -0
  200. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/__init__.py +0 -0
  201. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_click_tree.py +0 -0
  202. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_conbus_actiontable_commands.py +0 -0
  203. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_conbus_blink_commands.py +0 -0
  204. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_datapoint_type_choice.py +0 -0
  205. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_decorators.py +0 -0
  206. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_error_handlers.py +0 -0
  207. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_formatters.py +0 -0
  208. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_serial_number_type.py +0 -0
  209. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_cli/test_system_function_choice.py +0 -0
  210. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_connection/__init__.py +0 -0
  211. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_connection/test_connection_init.py +0 -0
  212. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_connection/test_exceptions.py +0 -0
  213. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_encoding/__init__.py +0 -0
  214. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_encoding/test_latin1_edge_cases.py +0 -0
  215. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/__init__.py +0 -0
  216. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_conbus.py +0 -0
  217. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_conbus_client_send.py +0 -0
  218. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_conbus_discover.py +0 -0
  219. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_conbus_linknumber.py +0 -0
  220. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_event_telegram.py +0 -0
  221. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_log_entry.py +0 -0
  222. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_module_type.py +0 -0
  223. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_reply_telegram.py +0 -0
  224. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_system_telegram.py +0 -0
  225. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_system_telegram_enhancements.py +0 -0
  226. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_version_telegram.py +0 -0
  227. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_write_config_type.py +0 -0
  228. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_xp20_action_table.py +0 -0
  229. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_xp24_action_table.py +0 -0
  230. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_models/test_xp24_action_telegram.py +0 -0
  231. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/__init__.py +0 -0
  232. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_actiontable_service.py +0 -0
  233. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_base_server_service.py +0 -0
  234. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_blink_service.py +0 -0
  235. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_checksum_service.py +0 -0
  236. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_conbus_blink_service.py +0 -0
  237. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_conbus_raw_service.py +0 -0
  238. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_conbus_reverse_proxy_service.py +0 -0
  239. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_discovery_service.py +0 -0
  240. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_homekit_cache_service.py +0 -0
  241. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_homekit_config_validator.py +0 -0
  242. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_homekit_conson_service.py +0 -0
  243. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_homekit_services.py +0 -0
  244. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_log_file_service.py +0 -0
  245. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_module_type_service.py +0 -0
  246. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_protocol.py +0 -0
  247. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_telegram_input_service.py +0 -0
  248. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_telegram_protocol.py +0 -0
  249. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_telegram_service.py +0 -0
  250. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_version_service.py +0 -0
  251. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_xp24_action_service.py +0 -0
  252. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_xp24_action_table_service.py +0 -0
  253. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_xp33_action_table_serializer.py +0 -0
  254. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_services/test_xp_server_services.py +0 -0
  255. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_utils/__init__.py +0 -0
  256. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_utils/test_checksum.py +0 -0
  257. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_utils/test_event_helper.py +0 -0
  258. {conson_xp-1.5.0 → conson_xp-1.6.0}/tests/unit/test_utils/test_serialization.py +0 -0
  259. {conson_xp-1.5.0 → conson_xp-1.6.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.6.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.6.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.6.0"
7
7
  __manufacturer__ = "salchichon"
8
8
  __model__ = "xp.cli"
9
9
  __serial__ = "2025.09.23.000"
@@ -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
@@ -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
@@ -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,83 @@ 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
+ 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
195
+
196
+ return self._build_response_telegram(f"R{self.serial_number}F19D") # NAK
197
+
198
+ def _handle_download_msactiontable_ack_request(
199
+ self, _request: SystemTelegram
200
+ ) -> Optional[str]:
201
+ """Handle MsActionTable download ACK protocol.
202
+
203
+ Args:
204
+ _request: The system telegram request (unused, kept for signature consistency).
205
+
206
+ Returns:
207
+ Data telegram, EOF telegram, or NAK if state is invalid.
208
+ """
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":
227
+ # Send EOF
228
+ eof_telegram = self._build_response_telegram(f"R{self.serial_number}F16D")
229
+ self.msactiontable_download_state = None
230
+ return eof_telegram
231
+
232
+ return self._build_response_telegram(f"R{self.serial_number}F19D") # NAK
233
+
154
234
  def process_system_telegram(self, request: SystemTelegram) -> Optional[str]:
155
235
  """Template method for processing system telegrams.
156
236
 
@@ -177,6 +257,15 @@ class BaseServerService(ABC):
177
257
  elif request.system_function == SystemFunction.ACTION:
178
258
  return self._handle_action_request(request)
179
259
 
260
+ elif request.system_function == SystemFunction.DOWNLOAD_MSACTIONTABLE:
261
+ return self._handle_download_msactiontable_request(request)
262
+
263
+ elif (
264
+ request.system_function == SystemFunction.ACK
265
+ and self.msactiontable_download_state
266
+ ):
267
+ return self._handle_download_msactiontable_ack_request(request)
268
+
180
269
  self.logger.warning(f"Unhandled {self.device_type} request: {request}")
181
270
  return None
182
271
 
@@ -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
+ )
@@ -8,19 +8,14 @@ import logging
8
8
  import socket
9
9
  import threading
10
10
  from pathlib import Path
11
- from typing import Dict, List, Optional, Union
11
+ from typing import Dict, List, Optional
12
12
 
13
13
  from xp.models.homekit.homekit_conson_config import (
14
14
  ConsonModuleConfig,
15
15
  ConsonModuleListConfig,
16
16
  )
17
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
18
+ from xp.services.server.device_service_factory import DeviceServiceFactory
24
19
  from xp.services.telegram.telegram_discover_service import TelegramDiscoverService
25
20
  from xp.services.telegram.telegram_service import TelegramService
26
21
 
@@ -43,6 +38,7 @@ class ServerService:
43
38
  self,
44
39
  telegram_service: TelegramService,
45
40
  discover_service: TelegramDiscoverService,
41
+ device_factory: DeviceServiceFactory,
46
42
  config_path: str = "server.yml",
47
43
  port: int = 10001,
48
44
  ):
@@ -51,25 +47,21 @@ class ServerService:
51
47
  Args:
52
48
  telegram_service: Service for parsing system telegrams.
53
49
  discover_service: Service for handling discover requests.
50
+ device_factory: Factory for creating device service instances (injected via DI).
54
51
  config_path: Path to the server configuration file.
55
52
  port: TCP port to listen on.
56
53
  """
57
54
  self.telegram_service = telegram_service
58
55
  self.discover_service = discover_service
56
+ self.device_factory = device_factory
59
57
  self.config_path = config_path
60
58
  self.port = port
61
59
  self.server_socket: Optional[socket.socket] = None
62
60
  self.is_running = False
63
61
  self.devices: List[ConsonModuleConfig] = []
64
- self.device_services: Dict[
65
- str,
66
- Union[
67
- BaseServerService,
68
- XP33ServerService,
69
- XP20ServerService,
70
- XP130ServerService,
71
- ],
72
- ] = {} # serial -> device service instance
62
+ self.device_services: Dict[str, BaseServerService] = (
63
+ {}
64
+ ) # serial -> device service instance
73
65
 
74
66
  # Collect device buffer to broadcast to client
75
67
  self.collector_thread: Optional[threading.Thread] = (
@@ -112,44 +104,14 @@ class ServerService:
112
104
  serial_number = module.serial_number
113
105
 
114
106
  try:
107
+ # Use factory to create device instance
108
+ self.device_services[serial_number] = self.device_factory.create_device(
109
+ module_type, serial_number
110
+ )
115
111
 
116
- # Serial number is already a string from config
117
- if module_type == "CP20":
118
- self.device_services[serial_number] = CP20ServerService(
119
- serial_number
120
- )
121
- if module_type == "XP24":
122
- self.device_services[serial_number] = XP24ServerService(
123
- serial_number
124
- )
125
- elif module_type == "XP33":
126
- self.device_services[serial_number] = XP33ServerService(
127
- serial_number, "XP33"
128
- )
129
- elif module_type == "XP33LR":
130
- self.device_services[serial_number] = XP33ServerService(
131
- serial_number, "XP33LR"
132
- )
133
- elif module_type == "XP33LED":
134
- self.device_services[serial_number] = XP33ServerService(
135
- serial_number, "XP33LED"
136
- )
137
- elif module_type == "XP20":
138
- self.device_services[serial_number] = XP20ServerService(
139
- serial_number
140
- )
141
- elif module_type == "XP130":
142
- self.device_services[serial_number] = XP130ServerService(
143
- serial_number
144
- )
145
- elif module_type == "XP230":
146
- self.device_services[serial_number] = XP230ServerService(
147
- serial_number
148
- )
149
- else:
150
- self.logger.warning(
151
- f"Unknown device type '{module_type}' for serial {serial_number}"
152
- )
112
+ except ValueError as e:
113
+ # Factory raises ValueError for unknown device types
114
+ self.logger.warning(str(e))
153
115
 
154
116
  except Exception as e:
155
117
  self.logger.error(
@@ -5,9 +5,10 @@ including response generation and device configuration handling.
5
5
  XP130 is an Ethernet/TCPIP interface module.
6
6
  """
7
7
 
8
- from typing import Dict
8
+ from typing import Dict, Optional
9
9
 
10
10
  from xp.models import ModuleTypeCode
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 XP130ServerService(BaseServerService):
25
26
  and implements XP130 telegram format for Ethernet/TCPIP interface module.
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 XP130 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 = "XP130"
@@ -0,0 +1,92 @@
1
+ """XP20 Server Service for device emulation.
2
+
3
+ This service provides XP20-specific device emulation functionality,
4
+ including response generation and device configuration handling.
5
+ """
6
+
7
+ from typing import Dict, Optional
8
+
9
+ from xp.models import ModuleTypeCode
10
+ from xp.models.actiontable.msactiontable_xp20 import Xp20MsActionTable
11
+ from xp.services.actiontable.msactiontable_xp20_serializer import (
12
+ Xp20MsActionTableSerializer,
13
+ )
14
+ from xp.services.server.base_server_service import BaseServerService
15
+
16
+
17
+ class XP20ServerError(Exception):
18
+ """Raised when XP20 server operations fail."""
19
+
20
+ pass
21
+
22
+
23
+ class XP20ServerService(BaseServerService):
24
+ """
25
+ XP20 device emulation service.
26
+
27
+ Generates XP20-specific responses, handles XP20 device configuration,
28
+ and implements XP20 telegram format.
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ serial_number: str,
34
+ _variant: str = "",
35
+ msactiontable_serializer: Optional[Xp20MsActionTableSerializer] = None,
36
+ ):
37
+ """Initialize XP20 server service.
38
+
39
+ Args:
40
+ serial_number: The device serial number.
41
+ _variant: Reserved parameter for consistency (unused).
42
+ msactiontable_serializer: MsActionTable serializer (injected via DI).
43
+ """
44
+ super().__init__(serial_number)
45
+ self.device_type = "XP20"
46
+ self.module_type_code = ModuleTypeCode.XP20 # XP20 module type from registry
47
+ self.firmware_version = "XP20_V0.01.05"
48
+
49
+ # MsActionTable support
50
+ self.msactiontable_serializer = (
51
+ msactiontable_serializer or Xp20MsActionTableSerializer()
52
+ )
53
+ self.msactiontable = self._get_default_msactiontable()
54
+
55
+ def _get_msactiontable_serializer(self) -> Optional[Xp20MsActionTableSerializer]:
56
+ """Get the MsActionTable serializer for XP20.
57
+
58
+ Returns:
59
+ The XP20 MsActionTable serializer instance.
60
+ """
61
+ return self.msactiontable_serializer
62
+
63
+ def _get_msactiontable(self) -> Optional[Xp20MsActionTable]:
64
+ """Get the MsActionTable for XP20.
65
+
66
+ Returns:
67
+ The XP20 MsActionTable instance.
68
+ """
69
+ return self.msactiontable
70
+
71
+ def _get_default_msactiontable(self) -> Xp20MsActionTable:
72
+ """Generate default MsActionTable configuration.
73
+
74
+ Returns:
75
+ Default XP20 MsActionTable with all inputs unconfigured.
76
+ """
77
+ # All inputs unconfigured (all flags False, AND functions empty)
78
+ return Xp20MsActionTable()
79
+
80
+ def get_device_info(self) -> Dict:
81
+ """Get XP20 device information.
82
+
83
+ Returns:
84
+ Dictionary containing device information.
85
+ """
86
+ return {
87
+ "serial_number": self.serial_number,
88
+ "device_type": self.device_type,
89
+ "firmware_version": self.firmware_version,
90
+ "status": self.device_status,
91
+ "link_number": self.link_number,
92
+ }
@@ -4,9 +4,10 @@ This service provides XP230-specific device emulation functionality,
4
4
  including response generation and device configuration handling.
5
5
  """
6
6
 
7
- from typing import Dict
7
+ from typing import Dict, Optional
8
8
 
9
9
  from xp.models import ModuleTypeCode
10
+ from xp.services.actiontable.msactiontable_serializer import MsActionTableSerializer
10
11
  from xp.services.server.base_server_service import BaseServerService
11
12
 
12
13
 
@@ -24,11 +25,18 @@ class XP230ServerService(BaseServerService):
24
25
  and implements XP230 telegram format.
25
26
  """
26
27
 
27
- def __init__(self, serial_number: str):
28
+ def __init__(
29
+ self,
30
+ serial_number: str,
31
+ _variant: str = "",
32
+ _msactiontable_serializer: Optional[MsActionTableSerializer] = None,
33
+ ):
28
34
  """Initialize XP230 server service.
29
35
 
30
36
  Args:
31
37
  serial_number: The device serial number.
38
+ _variant: Reserved parameter for consistency (unused).
39
+ _msactiontable_serializer: Generic MsActionTable serializer (unused).
32
40
  """
33
41
  super().__init__(serial_number)
34
42
  self.device_type = "XP230"
@@ -7,9 +7,15 @@ including response generation and device configuration handling.
7
7
  from typing import Dict, Optional
8
8
 
9
9
  from xp.models import ModuleTypeCode
10
+ from xp.models.actiontable.msactiontable_xp24 import InputAction, Xp24MsActionTable
10
11
  from xp.models.telegram.datapoint_type import DataPointType
12
+ from xp.models.telegram.input_action_type import InputActionType
11
13
  from xp.models.telegram.system_function import SystemFunction
12
14
  from xp.models.telegram.system_telegram import SystemTelegram
15
+ from xp.models.telegram.timeparam_type import TimeParam
16
+ from xp.services.actiontable.msactiontable_xp24_serializer import (
17
+ Xp24MsActionTableSerializer,
18
+ )
13
19
  from xp.services.server.base_server_service import BaseServerService
14
20
 
15
21
 
@@ -37,11 +43,18 @@ class XP24ServerService(BaseServerService):
37
43
  and implements XP24 telegram format.
38
44
  """
39
45
 
40
- def __init__(self, serial_number: str):
46
+ def __init__(
47
+ self,
48
+ serial_number: str,
49
+ _variant: str = "",
50
+ msactiontable_serializer: Optional[Xp24MsActionTableSerializer] = None,
51
+ ):
41
52
  """Initialize XP24 server service.
42
53
 
43
54
  Args:
44
55
  serial_number: The device serial number.
56
+ _variant: Reserved parameter for consistency (unused).
57
+ msactiontable_serializer: MsActionTable serializer (injected via DI).
45
58
  """
46
59
  super().__init__(serial_number)
47
60
  self.device_type = "XP24"
@@ -53,6 +66,12 @@ class XP24ServerService(BaseServerService):
53
66
  self.output_2: XP24Output = XP24Output()
54
67
  self.output_3: XP24Output = XP24Output()
55
68
 
69
+ # MsActionTable support
70
+ self.msactiontable_serializer = (
71
+ msactiontable_serializer or Xp24MsActionTableSerializer()
72
+ )
73
+ self.msactiontable = self._get_default_msactiontable()
74
+
56
75
  def _handle_device_specific_action_request(
57
76
  self, request: SystemTelegram
58
77
  ) -> Optional[str]:
@@ -175,6 +194,40 @@ class XP24ServerService(BaseServerService):
175
194
  f"{1 if self.output_3.state else 0}"
176
195
  )
177
196
 
197
+ def _get_msactiontable_serializer(self) -> Optional[Xp24MsActionTableSerializer]:
198
+ """Get the MsActionTable serializer for XP24.
199
+
200
+ Returns:
201
+ The XP24 MsActionTable serializer instance.
202
+ """
203
+ return self.msactiontable_serializer
204
+
205
+ def _get_msactiontable(self) -> Optional[Xp24MsActionTable]:
206
+ """Get the MsActionTable for XP24.
207
+
208
+ Returns:
209
+ The XP24 MsActionTable instance.
210
+ """
211
+ return self.msactiontable
212
+
213
+ def _get_default_msactiontable(self) -> Xp24MsActionTable:
214
+ """Generate default MsActionTable configuration.
215
+
216
+ Returns:
217
+ Default XP24 MsActionTable with all inputs set to VOID.
218
+ """
219
+ return Xp24MsActionTable(
220
+ input1_action=InputAction(type=InputActionType.VOID, param=TimeParam.NONE),
221
+ input2_action=InputAction(type=InputActionType.VOID, param=TimeParam.NONE),
222
+ input3_action=InputAction(type=InputActionType.VOID, param=TimeParam.NONE),
223
+ input4_action=InputAction(type=InputActionType.VOID, param=TimeParam.NONE),
224
+ mutex12=False,
225
+ mutex34=False,
226
+ curtain12=False,
227
+ curtain34=False,
228
+ mutual_deadtime=12, # MS300
229
+ )
230
+
178
231
  def get_device_info(self) -> Dict:
179
232
  """Get XP24 device information.
180
233