conson-xp 1.1.0__py3-none-any.whl → 1.3.0__py3-none-any.whl

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 (174) hide show
  1. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/METADATA +1 -5
  2. conson_xp-1.3.0.dist-info/RECORD +164 -0
  3. xp/__init__.py +4 -3
  4. xp/cli/__init__.py +1 -1
  5. xp/cli/commands/__init__.py +1 -2
  6. xp/cli/commands/conbus/conbus.py +9 -37
  7. xp/cli/commands/conbus/conbus_actiontable_commands.py +26 -4
  8. xp/cli/commands/conbus/conbus_autoreport_commands.py +58 -30
  9. xp/cli/commands/conbus/conbus_blink_commands.py +61 -29
  10. xp/cli/commands/conbus/conbus_config_commands.py +10 -5
  11. xp/cli/commands/conbus/conbus_custom_commands.py +16 -5
  12. xp/cli/commands/conbus/conbus_datapoint_commands.py +32 -10
  13. xp/cli/commands/conbus/conbus_discover_commands.py +20 -7
  14. xp/cli/commands/conbus/conbus_lightlevel_commands.py +114 -39
  15. xp/cli/commands/conbus/conbus_linknumber_commands.py +50 -25
  16. xp/cli/commands/conbus/conbus_msactiontable_commands.py +36 -5
  17. xp/cli/commands/conbus/conbus_output_commands.py +52 -14
  18. xp/cli/commands/conbus/conbus_raw_commands.py +17 -6
  19. xp/cli/commands/conbus/conbus_receive_commands.py +20 -10
  20. xp/cli/commands/conbus/conbus_scan_commands.py +17 -4
  21. xp/cli/commands/file_commands.py +35 -18
  22. xp/cli/commands/homekit/homekit.py +14 -8
  23. xp/cli/commands/homekit/homekit_start_commands.py +8 -6
  24. xp/cli/commands/module_commands.py +38 -23
  25. xp/cli/commands/reverse_proxy_commands.py +27 -19
  26. xp/cli/commands/server/server_commands.py +18 -18
  27. xp/cli/commands/telegram/telegram.py +4 -12
  28. xp/cli/commands/telegram/telegram_blink_commands.py +10 -8
  29. xp/cli/commands/telegram/telegram_checksum_commands.py +19 -8
  30. xp/cli/commands/telegram/telegram_discover_commands.py +2 -4
  31. xp/cli/commands/telegram/telegram_linknumber_commands.py +11 -8
  32. xp/cli/commands/telegram/telegram_parse_commands.py +10 -9
  33. xp/cli/commands/telegram/telegram_version_commands.py +8 -4
  34. xp/cli/main.py +5 -3
  35. xp/cli/utils/click_tree.py +23 -3
  36. xp/cli/utils/datapoint_type_choice.py +20 -0
  37. xp/cli/utils/decorators.py +165 -14
  38. xp/cli/utils/error_handlers.py +49 -18
  39. xp/cli/utils/formatters.py +95 -10
  40. xp/cli/utils/serial_number_type.py +18 -0
  41. xp/cli/utils/system_function_choice.py +20 -0
  42. xp/cli/utils/xp_module_type.py +20 -0
  43. xp/connection/__init__.py +1 -1
  44. xp/connection/exceptions.py +5 -5
  45. xp/models/__init__.py +1 -1
  46. xp/models/actiontable/__init__.py +1 -0
  47. xp/models/actiontable/actiontable.py +17 -1
  48. xp/models/actiontable/msactiontable_xp20.py +10 -0
  49. xp/models/actiontable/msactiontable_xp24.py +20 -3
  50. xp/models/actiontable/msactiontable_xp33.py +27 -4
  51. xp/models/conbus/__init__.py +1 -0
  52. xp/models/conbus/conbus.py +34 -4
  53. xp/models/conbus/conbus_autoreport.py +20 -2
  54. xp/models/conbus/conbus_blink.py +22 -2
  55. xp/models/conbus/conbus_client_config.py +22 -1
  56. xp/models/conbus/conbus_connection_status.py +16 -2
  57. xp/models/conbus/conbus_custom.py +21 -2
  58. xp/models/conbus/conbus_datapoint.py +25 -2
  59. xp/models/conbus/conbus_discover.py +18 -2
  60. xp/models/conbus/conbus_lightlevel.py +20 -2
  61. xp/models/conbus/conbus_linknumber.py +20 -2
  62. xp/models/conbus/conbus_output.py +22 -2
  63. xp/models/conbus/conbus_raw.py +17 -2
  64. xp/models/conbus/conbus_receive.py +16 -2
  65. xp/models/conbus/conbus_writeconfig.py +60 -0
  66. xp/models/homekit/__init__.py +1 -0
  67. xp/models/homekit/homekit_accessory.py +15 -1
  68. xp/models/homekit/homekit_config.py +52 -0
  69. xp/models/homekit/homekit_conson_config.py +32 -0
  70. xp/models/log_entry.py +49 -9
  71. xp/models/protocol/__init__.py +1 -0
  72. xp/models/protocol/conbus_protocol.py +130 -21
  73. xp/models/telegram/__init__.py +1 -0
  74. xp/models/telegram/action_type.py +16 -2
  75. xp/models/telegram/datapoint_type.py +36 -2
  76. xp/models/telegram/event_telegram.py +46 -10
  77. xp/models/telegram/event_type.py +8 -1
  78. xp/models/telegram/input_action_type.py +34 -2
  79. xp/models/telegram/input_type.py +9 -1
  80. xp/models/telegram/module_type.py +69 -19
  81. xp/models/telegram/module_type_code.py +43 -1
  82. xp/models/telegram/output_telegram.py +30 -6
  83. xp/models/telegram/reply_telegram.py +56 -11
  84. xp/models/telegram/system_function.py +35 -3
  85. xp/models/telegram/system_telegram.py +18 -4
  86. xp/models/telegram/telegram.py +12 -3
  87. xp/models/telegram/telegram_type.py +8 -1
  88. xp/models/telegram/timeparam_type.py +27 -0
  89. xp/models/write_config_type.py +17 -2
  90. xp/services/__init__.py +1 -1
  91. xp/services/conbus/__init__.py +1 -0
  92. xp/services/conbus/actiontable/__init__.py +1 -0
  93. xp/services/conbus/actiontable/actiontable_service.py +33 -2
  94. xp/services/conbus/actiontable/msactiontable_service.py +40 -3
  95. xp/services/conbus/actiontable/msactiontable_xp24_serializer.py +36 -4
  96. xp/services/conbus/actiontable/msactiontable_xp33_serializer.py +45 -5
  97. xp/services/conbus/conbus_blink_all_service.py +40 -21
  98. xp/services/conbus/conbus_blink_service.py +37 -13
  99. xp/services/conbus/conbus_custom_service.py +29 -13
  100. xp/services/conbus/conbus_datapoint_queryall_service.py +40 -16
  101. xp/services/conbus/conbus_datapoint_service.py +42 -18
  102. xp/services/conbus/conbus_discover_service.py +43 -7
  103. xp/services/conbus/conbus_output_service.py +33 -13
  104. xp/services/conbus/conbus_raw_service.py +36 -16
  105. xp/services/conbus/conbus_receive_service.py +38 -6
  106. xp/services/conbus/conbus_scan_service.py +44 -18
  107. xp/services/conbus/write_config_service.py +193 -0
  108. xp/services/homekit/__init__.py +1 -0
  109. xp/services/homekit/homekit_cache_service.py +31 -6
  110. xp/services/homekit/homekit_conbus_service.py +33 -2
  111. xp/services/homekit/homekit_config_validator.py +97 -15
  112. xp/services/homekit/homekit_conson_validator.py +51 -7
  113. xp/services/homekit/homekit_dimminglight.py +47 -1
  114. xp/services/homekit/homekit_dimminglight_service.py +35 -1
  115. xp/services/homekit/homekit_hap_service.py +71 -18
  116. xp/services/homekit/homekit_lightbulb.py +35 -1
  117. xp/services/homekit/homekit_lightbulb_service.py +30 -2
  118. xp/services/homekit/homekit_module_service.py +23 -1
  119. xp/services/homekit/homekit_outlet.py +47 -1
  120. xp/services/homekit/homekit_outlet_service.py +44 -2
  121. xp/services/homekit/homekit_service.py +113 -19
  122. xp/services/log_file_service.py +37 -41
  123. xp/services/module_type_service.py +26 -5
  124. xp/services/protocol/__init__.py +1 -1
  125. xp/services/protocol/conbus_protocol.py +110 -16
  126. xp/services/protocol/protocol_factory.py +40 -0
  127. xp/services/protocol/telegram_protocol.py +38 -7
  128. xp/services/reverse_proxy_service.py +79 -14
  129. xp/services/server/__init__.py +1 -0
  130. xp/services/server/base_server_service.py +102 -14
  131. xp/services/server/cp20_server_service.py +12 -4
  132. xp/services/server/server_service.py +26 -11
  133. xp/services/server/xp130_server_service.py +11 -3
  134. xp/services/server/xp20_server_service.py +11 -3
  135. xp/services/server/xp230_server_service.py +11 -3
  136. xp/services/server/xp24_server_service.py +33 -6
  137. xp/services/server/xp33_server_service.py +41 -8
  138. xp/services/telegram/__init__.py +1 -0
  139. xp/services/telegram/telegram_blink_service.py +19 -31
  140. xp/services/telegram/telegram_checksum_service.py +10 -10
  141. xp/services/telegram/telegram_datapoint_service.py +70 -0
  142. xp/services/telegram/telegram_discover_service.py +58 -29
  143. xp/services/telegram/telegram_link_number_service.py +27 -40
  144. xp/services/telegram/telegram_output_service.py +46 -49
  145. xp/services/telegram/telegram_service.py +41 -41
  146. xp/services/telegram/telegram_version_service.py +4 -2
  147. xp/utils/__init__.py +1 -1
  148. xp/utils/dependencies.py +4 -47
  149. xp/utils/serialization.py +6 -0
  150. xp/utils/time_utils.py +6 -11
  151. conson_xp-1.1.0.dist-info/RECORD +0 -181
  152. xp/api/__init__.py +0 -1
  153. xp/api/main.py +0 -110
  154. xp/api/models/__init__.py +0 -1
  155. xp/api/models/api.py +0 -20
  156. xp/api/models/discover.py +0 -21
  157. xp/api/routers/__init__.py +0 -17
  158. xp/api/routers/conbus.py +0 -5
  159. xp/api/routers/conbus_blink.py +0 -105
  160. xp/api/routers/conbus_custom.py +0 -63
  161. xp/api/routers/conbus_datapoint.py +0 -67
  162. xp/api/routers/conbus_output.py +0 -147
  163. xp/api/routers/errors.py +0 -37
  164. xp/cli/commands/api.py +0 -16
  165. xp/cli/commands/api_start_commands.py +0 -126
  166. xp/services/conbus/conbus_autoreport_get_service.py +0 -85
  167. xp/services/conbus/conbus_autoreport_set_service.py +0 -128
  168. xp/services/conbus/conbus_lightlevel_get_service.py +0 -101
  169. xp/services/conbus/conbus_lightlevel_set_service.py +0 -205
  170. xp/services/conbus/conbus_linknumber_get_service.py +0 -86
  171. xp/services/conbus/conbus_linknumber_set_service.py +0 -155
  172. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/WHEEL +0 -0
  173. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/entry_points.txt +0 -0
  174. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,101 +0,0 @@
1
- """Conbus Auto Report Service for getting and setting module auto report status.
2
-
3
- This service handles auto report status operations for modules through Conbus telegrams.
4
- """
5
-
6
- import logging
7
- from datetime import datetime
8
- from typing import Callable, Optional
9
-
10
- from twisted.internet.posixbase import PosixReactorBase
11
-
12
- from xp.models import ConbusClientConfig, ConbusDatapointResponse
13
- from xp.models.conbus.conbus_lightlevel import ConbusLightlevelResponse
14
- from xp.models.telegram.datapoint_type import DataPointType
15
- from xp.services.conbus.conbus_datapoint_service import ConbusDatapointService
16
- from xp.services.telegram.telegram_service import TelegramService
17
-
18
-
19
- class ConbusLightlevelGetService(ConbusDatapointService):
20
- """
21
- Service for receiving telegrams from Conbus servers.
22
-
23
- Uses composition with ConbusService to provide receive-only functionality
24
- for collecting waiting event telegrams from the server.
25
- """
26
-
27
- def __init__(
28
- self,
29
- telegram_service: TelegramService,
30
- cli_config: ConbusClientConfig,
31
- reactor: PosixReactorBase,
32
- ) -> None:
33
- """Initialize the Conbus client send service"""
34
- super().__init__(telegram_service, cli_config, reactor)
35
- self.output_number: int = 0
36
- self.service_callback: Optional[Callable[[ConbusLightlevelResponse], None]] = (
37
- None
38
- )
39
-
40
- # Set up logging
41
- self.logger = logging.getLogger(__name__)
42
-
43
- def finish_service_callback(
44
- self, datapoint_response: ConbusDatapointResponse
45
- ) -> None:
46
-
47
- self.logger.debug("Parsing datapoint response")
48
-
49
- level = 0
50
- if datapoint_response.success and datapoint_response.datapoint_telegram:
51
- for output_data in datapoint_response.datapoint_telegram.data_value.split(
52
- ","
53
- ):
54
- if ":" in output_data:
55
- output_str, level_str = output_data.split(":")
56
- if int(output_str) == self.output_number:
57
- level_str = level_str.replace("[%]", "")
58
- level = int(level_str)
59
- break
60
-
61
- service_response = ConbusLightlevelResponse(
62
- success=datapoint_response.success,
63
- serial_number=self.serial_number,
64
- output_number=self.output_number,
65
- level=level,
66
- error=datapoint_response.error,
67
- sent_telegram=datapoint_response.sent_telegram,
68
- received_telegrams=datapoint_response.received_telegrams,
69
- timestamp=datetime.now(),
70
- )
71
-
72
- if self.service_callback:
73
- self.service_callback(service_response)
74
-
75
- def get_light_level(
76
- self,
77
- serial_number: str,
78
- output_number: int,
79
- finish_callback: Callable[[ConbusLightlevelResponse], None],
80
- timeout_seconds: Optional[float] = None,
81
- ) -> None:
82
- """
83
- Get the current auto report status for a specific module.
84
-
85
- Args:
86
- :param serial_number: 10-digit module serial number
87
- :param output_number: output module number
88
- :param finish_callback: callback function to call when the lightlevel status is
89
- :param timeout_seconds: timeout in seconds
90
-
91
- """
92
- self.logger.info("Starting get_lightlevel_status")
93
- if timeout_seconds:
94
- self.timeout_seconds = timeout_seconds
95
- self.serial_number = serial_number
96
- self.output_number = output_number
97
- self.datapoint_type = DataPointType.MODULE_LIGHT_LEVEL
98
-
99
- self.finish_callback = self.finish_service_callback
100
- self.service_callback = finish_callback
101
- self.start_reactor()
@@ -1,205 +0,0 @@
1
- """Conbus Lightlevel Service for controlling light levels on Conbus modules.
2
-
3
- This service implements lightlevel control operations for XP modules,
4
- including setting specific light levels, turning lights on/off, and
5
- querying current light levels.
6
- """
7
-
8
- import logging
9
- from datetime import datetime
10
- from typing import Callable, Optional
11
-
12
- from twisted.internet.posixbase import PosixReactorBase
13
-
14
- from xp.models import ConbusClientConfig
15
- from xp.models.conbus.conbus_lightlevel import ConbusLightlevelResponse
16
- from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
17
- from xp.models.telegram.datapoint_type import DataPointType
18
- from xp.models.telegram.system_function import SystemFunction
19
- from xp.models.telegram.telegram_type import TelegramType
20
- from xp.services.protocol import ConbusProtocol
21
-
22
-
23
- class ConbusLightlevelError(Exception):
24
- """Raised when Conbus lightlevel operations fail"""
25
-
26
- pass
27
-
28
-
29
- class ConbusLightlevelSetService(ConbusProtocol):
30
- """
31
- Service for controlling light levels on Conbus modules.
32
-
33
- Manages lightlevel operations including setting specific levels,
34
- turning lights on/off, and querying current states.
35
- """
36
-
37
- def __init__(
38
- self,
39
- cli_config: ConbusClientConfig,
40
- reactor: PosixReactorBase,
41
- ):
42
- """Initialize the Conbus lightlevel service"""
43
- super().__init__(cli_config, reactor)
44
- self.serial_number: str = ""
45
- self.output_number: int = 0
46
- self.level: int = 0
47
- self.finish_callback: Optional[Callable[[ConbusLightlevelResponse], None]] = (
48
- None
49
- )
50
- self.service_response: ConbusLightlevelResponse = ConbusLightlevelResponse(
51
- success=False,
52
- serial_number=self.serial_number,
53
- output_number=self.output_number,
54
- level=None,
55
- timestamp=datetime.now(),
56
- )
57
-
58
- # Set up logging
59
- self.logger = logging.getLogger(__name__)
60
-
61
- def connection_established(self) -> None:
62
- self.logger.debug(
63
- f"Connection established, setting light level for output {self.output_number} to {self.level}%..."
64
- )
65
-
66
- # Format data as output_number:level (e.g., ""15" + "02:050")
67
- data_value = f"{DataPointType.MODULE_LIGHT_LEVEL.value}{self.output_number:02d}:{self.level:03d}"
68
-
69
- # Send telegram using WRITE_CONFIG function with MODULE_LIGHT_LEVEL datapoint
70
- self.send_telegram(
71
- telegram_type=TelegramType.SYSTEM,
72
- serial_number=self.serial_number,
73
- system_function=SystemFunction.WRITE_CONFIG, # "04"
74
- data_value=data_value,
75
- )
76
-
77
- def telegram_sent(self, telegram_sent: str) -> None:
78
- self.service_response.sent_telegram = telegram_sent
79
-
80
- def telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
81
- self.logger.debug(f"Telegram received: {telegram_received}")
82
- if not self.service_response.received_telegrams:
83
- self.service_response.received_telegrams = []
84
- self.service_response.received_telegrams.append(telegram_received.frame)
85
-
86
- if (
87
- not telegram_received.checksum_valid
88
- or telegram_received.telegram_type != TelegramType.REPLY
89
- or telegram_received.serial_number != self.serial_number
90
- ):
91
- self.logger.debug("Not a reply for our serial number")
92
- return
93
-
94
- # Any valid reply means success (ACK or NAK)
95
- if telegram_received.telegram_type == TelegramType.REPLY:
96
- self.logger.debug("Received lightlevel response")
97
- self.succeed()
98
-
99
- def succeed(self) -> None:
100
- self.logger.debug("Succeed")
101
- self.service_response.success = True
102
- self.service_response.serial_number = self.serial_number
103
- self.service_response.output_number = self.output_number
104
- self.service_response.level = self.level
105
- self.service_response.timestamp = datetime.now()
106
-
107
- if self.finish_callback:
108
- self.finish_callback(self.service_response)
109
-
110
- def failed(self, message: str) -> None:
111
- self.logger.debug(f"Failed with message: {message}")
112
- self.service_response.success = False
113
- self.service_response.serial_number = self.serial_number
114
- self.service_response.output_number = self.output_number
115
- self.service_response.level = self.level
116
- self.service_response.timestamp = datetime.now()
117
- self.service_response.error = message
118
-
119
- if self.finish_callback:
120
- self.finish_callback(self.service_response)
121
-
122
- def set_lightlevel(
123
- self,
124
- serial_number: str,
125
- output_number: int,
126
- level: int,
127
- finish_callback: Callable[[ConbusLightlevelResponse], None],
128
- timeout_seconds: Optional[float] = None,
129
- ) -> None:
130
- """Set light level for a specific output on a module.
131
-
132
- Args:
133
- serial_number: Module serial number
134
- output_number: Output number (0-based, 0-8)
135
- level: Light level percentage (0-100)
136
- finish_callback: Callback function to call when operation completes
137
- timeout_seconds: Optional timeout in seconds
138
-
139
- Examples:
140
- \b
141
- xp conbus lightlevel set 0012345008 2 50
142
- xp conbus lightlevel set 0012345008 0 100
143
- """
144
-
145
- self.logger.info(
146
- f"Setting light level for {serial_number} output {output_number} to {level}%"
147
- )
148
- if timeout_seconds:
149
- self.timeout_seconds = timeout_seconds
150
- self.finish_callback = finish_callback
151
- self.serial_number = serial_number
152
- self.output_number = output_number
153
- self.level = level
154
-
155
- # Validate output_number range (0-8)
156
- if not 0 <= self.output_number <= 8:
157
- self.failed(
158
- f"Output number must be between 0 and 8, got {self.output_number}"
159
- )
160
- return
161
-
162
- # Validate level range
163
- if not 0 <= self.level <= 100:
164
- self.failed(f"Light level must be between 0 and 100, got {self.level}")
165
- return
166
-
167
- self.start_reactor()
168
-
169
- def turn_off(
170
- self,
171
- serial_number: str,
172
- output_number: int,
173
- finish_callback: Callable[[ConbusLightlevelResponse], None],
174
- timeout_seconds: Optional[float] = None,
175
- ) -> None:
176
- """Turn off light (set level to 0) for a specific output.
177
-
178
- Args:
179
- serial_number: Module serial number
180
- output_number: Output number (0-8)
181
- finish_callback: Callback function to call when operation completes
182
- timeout_seconds: Optional timeout in seconds
183
- """
184
- self.set_lightlevel(
185
- serial_number, output_number, 0, finish_callback, timeout_seconds
186
- )
187
-
188
- def turn_on(
189
- self,
190
- serial_number: str,
191
- output_number: int,
192
- finish_callback: Callable[[ConbusLightlevelResponse], None],
193
- timeout_seconds: Optional[float] = None,
194
- ) -> None:
195
- """Turn on light (set level to 80%) for a specific output.
196
-
197
- Args:
198
- serial_number: Module serial number
199
- output_number: Output number (0-8)
200
- finish_callback: Callback function to call when operation completes
201
- timeout_seconds: Optional timeout in seconds
202
- """
203
- self.set_lightlevel(
204
- serial_number, output_number, 80, finish_callback, timeout_seconds
205
- )
@@ -1,86 +0,0 @@
1
- """Conbus Link Number Service for setting module link numbers.
2
-
3
- This service handles setting link numbers for modules through Conbus telegrams.
4
- """
5
-
6
- import logging
7
- from typing import Callable, Optional
8
-
9
- from twisted.internet.posixbase import PosixReactorBase
10
-
11
- from xp.models import ConbusClientConfig, ConbusDatapointResponse
12
- from xp.models.conbus.conbus_linknumber import ConbusLinknumberResponse
13
- from xp.models.telegram.datapoint_type import DataPointType
14
- from xp.services.conbus.conbus_datapoint_service import ConbusDatapointService
15
- from xp.services.telegram.telegram_service import TelegramService
16
-
17
-
18
- class ConbusLinknumberGetService(ConbusDatapointService):
19
- """
20
- Service for receiving telegrams from Conbus servers.
21
-
22
- Uses composition with ConbusService to provide receive-only functionality
23
- for collecting waiting event telegrams from the server.
24
- """
25
-
26
- def __init__(
27
- self,
28
- telegram_service: TelegramService,
29
- cli_config: ConbusClientConfig,
30
- reactor: PosixReactorBase,
31
- ) -> None:
32
- """Initialize the Conbus client send service"""
33
- super().__init__(telegram_service, cli_config, reactor)
34
- self.service_callback: Optional[Callable[[ConbusLinknumberResponse], None]] = (
35
- None
36
- )
37
-
38
- # Set up logging
39
- self.logger = logging.getLogger(__name__)
40
-
41
- def finish_service_callback(
42
- self, datapoint_response: ConbusDatapointResponse
43
- ) -> None:
44
-
45
- self.logger.debug("Parsing datapoint response")
46
- link_number_value = 0
47
- if datapoint_response.success and datapoint_response.datapoint_telegram:
48
- link_number_value = int(datapoint_response.datapoint_telegram.data_value)
49
-
50
- linknumber_response = ConbusLinknumberResponse(
51
- success=datapoint_response.success,
52
- result="SUCCESS" if datapoint_response.success else "FAILURE",
53
- link_number=link_number_value,
54
- serial_number=self.serial_number,
55
- error=datapoint_response.error,
56
- sent_telegram=datapoint_response.sent_telegram,
57
- received_telegrams=datapoint_response.received_telegrams,
58
- timestamp=datapoint_response.timestamp,
59
- )
60
-
61
- if self.service_callback:
62
- self.service_callback(linknumber_response)
63
-
64
- def get_linknumber(
65
- self,
66
- serial_number: str,
67
- finish_callback: Callable[[ConbusLinknumberResponse], None],
68
- timeout_seconds: Optional[float] = None,
69
- ) -> None:
70
- """
71
- Get the current auto report status for a specific module.
72
-
73
- Args:
74
- :param serial_number: 10-digit module serial number
75
- :param finish_callback: callback function to call when the linknumber status is
76
- :param timeout_seconds: timeout in seconds
77
-
78
- """
79
- self.logger.info("Starting get_linknumber")
80
- if timeout_seconds:
81
- self.timeout_seconds = timeout_seconds
82
- self.serial_number = serial_number
83
- self.datapoint_type = DataPointType.LINK_NUMBER
84
- self.finish_callback = self.finish_service_callback
85
- self.service_callback = finish_callback
86
- self.start_reactor()
@@ -1,155 +0,0 @@
1
- """Conbus Link Number Service for setting module link numbers.
2
-
3
- This service handles setting link numbers for modules through Conbus telegrams.
4
- """
5
-
6
- import logging
7
- from datetime import datetime
8
- from typing import Callable, Optional
9
-
10
- from twisted.internet.posixbase import PosixReactorBase
11
-
12
- from xp.models import ConbusClientConfig
13
- from xp.models.conbus.conbus_linknumber import ConbusLinknumberResponse
14
- from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
15
- from xp.models.telegram.datapoint_type import DataPointType
16
- from xp.models.telegram.system_function import SystemFunction
17
- from xp.models.telegram.telegram_type import TelegramType
18
- from xp.services.protocol import ConbusProtocol
19
- from xp.services.telegram.telegram_service import TelegramService
20
-
21
-
22
- class ConbusLinknumberSetService(ConbusProtocol):
23
- """
24
- Service for setting module link numbers via Conbus telegrams.
25
-
26
- Handles link number assignment by sending F04D04 telegrams and processing
27
- ACK/NAK responses from modules.
28
- """
29
-
30
- def __init__(
31
- self,
32
- telegram_service: TelegramService,
33
- cli_config: ConbusClientConfig,
34
- reactor: PosixReactorBase,
35
- ) -> None:
36
- """Initialize the Conbus link number set service"""
37
- super().__init__(cli_config, reactor)
38
- self.telegram_service = telegram_service
39
- self.serial_number: str = ""
40
- self.link_number: int = 0
41
- self.finish_callback: Optional[Callable[[ConbusLinknumberResponse], None]] = (
42
- None
43
- )
44
- self.service_response: ConbusLinknumberResponse = ConbusLinknumberResponse(
45
- success=False, serial_number=self.serial_number, result=""
46
- )
47
-
48
- # Set up logging
49
- self.logger = logging.getLogger(__name__)
50
-
51
- def connection_established(self) -> None:
52
- self.logger.debug(
53
- f"Connection established, setting link number {self.link_number}..."
54
- )
55
-
56
- # Validate parameters before sending
57
- if not self.serial_number or len(self.serial_number) != 10:
58
- self.failed(f"Serial number must be 10 digits, got: {self.serial_number}")
59
- return
60
-
61
- if not (0 <= self.link_number <= 99):
62
- self.failed(f"Link number must be between 0-99, got: {self.link_number}")
63
- return
64
-
65
- # Send F04D04{link_number} telegram
66
- # F04 = WRITE_CONFIG, D04 = LINK_NUMBER datapoint type
67
- self.send_telegram(
68
- telegram_type=TelegramType.SYSTEM,
69
- serial_number=self.serial_number,
70
- system_function=SystemFunction.WRITE_CONFIG,
71
- data_value=f"{DataPointType.LINK_NUMBER.value}{self.link_number:02d}",
72
- )
73
-
74
- def telegram_sent(self, telegram_sent: str) -> None:
75
- self.service_response.sent_telegram = telegram_sent
76
-
77
- def telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
78
- self.logger.debug(f"Telegram received: {telegram_received}")
79
-
80
- if not self.service_response.received_telegrams:
81
- self.service_response.received_telegrams = []
82
- self.service_response.received_telegrams.append(telegram_received.frame)
83
-
84
- if (
85
- not telegram_received.checksum_valid
86
- or telegram_received.telegram_type != TelegramType.REPLY
87
- or telegram_received.serial_number != self.serial_number
88
- ):
89
- self.logger.debug("Not a reply for our serial number")
90
- return
91
-
92
- # Parse the reply telegram
93
- reply_telegram = self.telegram_service.parse_reply_telegram(
94
- telegram_received.frame
95
- )
96
-
97
- if not reply_telegram:
98
- self.logger.debug("Failed to parse reply telegram")
99
- return
100
-
101
- # Check for ACK or NAK response
102
- if reply_telegram.system_function == SystemFunction.ACK:
103
- self.logger.debug("Received ACK response")
104
- self.succeed(SystemFunction.ACK)
105
- elif reply_telegram.system_function == SystemFunction.NAK:
106
- self.logger.debug("Received NAK response")
107
- self.failed("Module responded with NAK")
108
- else:
109
- self.logger.debug(
110
- f"Unexpected system function: {reply_telegram.system_function}"
111
- )
112
-
113
- def succeed(self, system_function: SystemFunction) -> None:
114
- self.logger.debug("Successfully set link number")
115
- self.service_response.success = True
116
- self.service_response.timestamp = datetime.now()
117
- self.service_response.serial_number = self.serial_number
118
- self.service_response.result = "ACK"
119
- self.service_response.link_number = self.link_number
120
- if self.finish_callback:
121
- self.finish_callback(self.service_response)
122
-
123
- def failed(self, message: str) -> None:
124
- self.logger.debug(f"Failed with message: {message}")
125
- self.service_response.success = False
126
- self.service_response.timestamp = datetime.now()
127
- self.service_response.serial_number = self.serial_number
128
- self.service_response.result = "NAK"
129
- self.service_response.error = message
130
- if self.finish_callback:
131
- self.finish_callback(self.service_response)
132
-
133
- def set_linknumber(
134
- self,
135
- serial_number: str,
136
- link_number: int,
137
- finish_callback: Callable[[ConbusLinknumberResponse], None],
138
- timeout_seconds: Optional[float] = None,
139
- ) -> None:
140
- """
141
- Set the link number for a specific module.
142
-
143
- Args:
144
- serial_number: 10-digit module serial number
145
- link_number: Link number to set (0-99)
146
- finish_callback: Callback function to call when operation completes
147
- timeout_seconds: Optional timeout in seconds
148
- """
149
- self.logger.info("Starting set_linknumber")
150
- if timeout_seconds:
151
- self.timeout_seconds = timeout_seconds
152
- self.serial_number = serial_number
153
- self.link_number = link_number
154
- self.finish_callback = finish_callback
155
- self.start_reactor()