conson-xp 1.18.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 (176) hide show
  1. conson_xp-1.18.0.dist-info/METADATA +412 -0
  2. conson_xp-1.18.0.dist-info/RECORD +176 -0
  3. conson_xp-1.18.0.dist-info/WHEEL +4 -0
  4. conson_xp-1.18.0.dist-info/entry_points.txt +5 -0
  5. conson_xp-1.18.0.dist-info/licenses/LICENSE +29 -0
  6. xp/__init__.py +9 -0
  7. xp/cli/__init__.py +5 -0
  8. xp/cli/__main__.py +6 -0
  9. xp/cli/commands/__init__.py +153 -0
  10. xp/cli/commands/conbus/__init__.py +25 -0
  11. xp/cli/commands/conbus/conbus.py +128 -0
  12. xp/cli/commands/conbus/conbus_actiontable_commands.py +233 -0
  13. xp/cli/commands/conbus/conbus_autoreport_commands.py +108 -0
  14. xp/cli/commands/conbus/conbus_blink_commands.py +163 -0
  15. xp/cli/commands/conbus/conbus_config_commands.py +29 -0
  16. xp/cli/commands/conbus/conbus_custom_commands.py +57 -0
  17. xp/cli/commands/conbus/conbus_datapoint_commands.py +113 -0
  18. xp/cli/commands/conbus/conbus_discover_commands.py +61 -0
  19. xp/cli/commands/conbus/conbus_event_commands.py +81 -0
  20. xp/cli/commands/conbus/conbus_lightlevel_commands.py +207 -0
  21. xp/cli/commands/conbus/conbus_linknumber_commands.py +102 -0
  22. xp/cli/commands/conbus/conbus_modulenumber_commands.py +104 -0
  23. xp/cli/commands/conbus/conbus_msactiontable_commands.py +94 -0
  24. xp/cli/commands/conbus/conbus_output_commands.py +163 -0
  25. xp/cli/commands/conbus/conbus_raw_commands.py +62 -0
  26. xp/cli/commands/conbus/conbus_receive_commands.py +59 -0
  27. xp/cli/commands/conbus/conbus_scan_commands.py +58 -0
  28. xp/cli/commands/file_commands.py +186 -0
  29. xp/cli/commands/homekit/__init__.py +3 -0
  30. xp/cli/commands/homekit/homekit.py +118 -0
  31. xp/cli/commands/homekit/homekit_start_commands.py +43 -0
  32. xp/cli/commands/module_commands.py +187 -0
  33. xp/cli/commands/reverse_proxy_commands.py +178 -0
  34. xp/cli/commands/server/__init__.py +3 -0
  35. xp/cli/commands/server/server_commands.py +135 -0
  36. xp/cli/commands/telegram/__init__.py +5 -0
  37. xp/cli/commands/telegram/telegram.py +41 -0
  38. xp/cli/commands/telegram/telegram_blink_commands.py +79 -0
  39. xp/cli/commands/telegram/telegram_checksum_commands.py +112 -0
  40. xp/cli/commands/telegram/telegram_discover_commands.py +41 -0
  41. xp/cli/commands/telegram/telegram_linknumber_commands.py +86 -0
  42. xp/cli/commands/telegram/telegram_parse_commands.py +75 -0
  43. xp/cli/commands/telegram/telegram_version_commands.py +52 -0
  44. xp/cli/main.py +87 -0
  45. xp/cli/utils/__init__.py +1 -0
  46. xp/cli/utils/click_tree.py +57 -0
  47. xp/cli/utils/datapoint_type_choice.py +57 -0
  48. xp/cli/utils/decorators.py +351 -0
  49. xp/cli/utils/error_handlers.py +201 -0
  50. xp/cli/utils/formatters.py +312 -0
  51. xp/cli/utils/module_type_choice.py +56 -0
  52. xp/cli/utils/serial_number_type.py +52 -0
  53. xp/cli/utils/system_function_choice.py +57 -0
  54. xp/cli/utils/xp_module_type.py +53 -0
  55. xp/connection/__init__.py +13 -0
  56. xp/connection/exceptions.py +22 -0
  57. xp/models/__init__.py +36 -0
  58. xp/models/actiontable/__init__.py +1 -0
  59. xp/models/actiontable/actiontable.py +43 -0
  60. xp/models/actiontable/msactiontable_xp20.py +53 -0
  61. xp/models/actiontable/msactiontable_xp24.py +58 -0
  62. xp/models/actiontable/msactiontable_xp33.py +65 -0
  63. xp/models/conbus/__init__.py +1 -0
  64. xp/models/conbus/conbus.py +87 -0
  65. xp/models/conbus/conbus_autoreport.py +67 -0
  66. xp/models/conbus/conbus_blink.py +80 -0
  67. xp/models/conbus/conbus_client_config.py +55 -0
  68. xp/models/conbus/conbus_connection_status.py +40 -0
  69. xp/models/conbus/conbus_custom.py +58 -0
  70. xp/models/conbus/conbus_datapoint.py +89 -0
  71. xp/models/conbus/conbus_discover.py +64 -0
  72. xp/models/conbus/conbus_event_raw.py +47 -0
  73. xp/models/conbus/conbus_lightlevel.py +52 -0
  74. xp/models/conbus/conbus_linknumber.py +54 -0
  75. xp/models/conbus/conbus_output.py +57 -0
  76. xp/models/conbus/conbus_raw.py +45 -0
  77. xp/models/conbus/conbus_receive.py +42 -0
  78. xp/models/conbus/conbus_writeconfig.py +60 -0
  79. xp/models/homekit/__init__.py +1 -0
  80. xp/models/homekit/homekit_accessory.py +35 -0
  81. xp/models/homekit/homekit_config.py +106 -0
  82. xp/models/homekit/homekit_conson_config.py +86 -0
  83. xp/models/log_entry.py +130 -0
  84. xp/models/protocol/__init__.py +1 -0
  85. xp/models/protocol/conbus_protocol.py +312 -0
  86. xp/models/response.py +42 -0
  87. xp/models/telegram/__init__.py +1 -0
  88. xp/models/telegram/action_type.py +31 -0
  89. xp/models/telegram/datapoint_type.py +82 -0
  90. xp/models/telegram/event_telegram.py +140 -0
  91. xp/models/telegram/event_type.py +15 -0
  92. xp/models/telegram/input_action_type.py +69 -0
  93. xp/models/telegram/input_type.py +17 -0
  94. xp/models/telegram/module_type.py +188 -0
  95. xp/models/telegram/module_type_code.py +205 -0
  96. xp/models/telegram/output_telegram.py +103 -0
  97. xp/models/telegram/reply_telegram.py +297 -0
  98. xp/models/telegram/system_function.py +116 -0
  99. xp/models/telegram/system_telegram.py +94 -0
  100. xp/models/telegram/telegram.py +28 -0
  101. xp/models/telegram/telegram_type.py +19 -0
  102. xp/models/telegram/timeparam_type.py +51 -0
  103. xp/models/write_config_type.py +33 -0
  104. xp/services/__init__.py +26 -0
  105. xp/services/actiontable/__init__.py +1 -0
  106. xp/services/actiontable/actiontable_serializer.py +273 -0
  107. xp/services/actiontable/msactiontable_serializer.py +7 -0
  108. xp/services/actiontable/msactiontable_xp20_serializer.py +169 -0
  109. xp/services/actiontable/msactiontable_xp24_serializer.py +120 -0
  110. xp/services/actiontable/msactiontable_xp33_serializer.py +239 -0
  111. xp/services/conbus/__init__.py +1 -0
  112. xp/services/conbus/actiontable/__init__.py +1 -0
  113. xp/services/conbus/actiontable/actiontable_download_service.py +158 -0
  114. xp/services/conbus/actiontable/actiontable_list_service.py +91 -0
  115. xp/services/conbus/actiontable/actiontable_show_service.py +89 -0
  116. xp/services/conbus/actiontable/actiontable_upload_service.py +211 -0
  117. xp/services/conbus/actiontable/msactiontable_service.py +232 -0
  118. xp/services/conbus/conbus_blink_all_service.py +181 -0
  119. xp/services/conbus/conbus_blink_service.py +158 -0
  120. xp/services/conbus/conbus_custom_service.py +156 -0
  121. xp/services/conbus/conbus_datapoint_queryall_service.py +182 -0
  122. xp/services/conbus/conbus_datapoint_service.py +170 -0
  123. xp/services/conbus/conbus_discover_service.py +312 -0
  124. xp/services/conbus/conbus_event_raw_service.py +181 -0
  125. xp/services/conbus/conbus_output_service.py +194 -0
  126. xp/services/conbus/conbus_raw_service.py +122 -0
  127. xp/services/conbus/conbus_receive_service.py +115 -0
  128. xp/services/conbus/conbus_scan_service.py +150 -0
  129. xp/services/conbus/write_config_service.py +194 -0
  130. xp/services/homekit/__init__.py +1 -0
  131. xp/services/homekit/homekit_cache_service.py +307 -0
  132. xp/services/homekit/homekit_conbus_service.py +93 -0
  133. xp/services/homekit/homekit_config_validator.py +310 -0
  134. xp/services/homekit/homekit_conson_validator.py +121 -0
  135. xp/services/homekit/homekit_dimminglight.py +182 -0
  136. xp/services/homekit/homekit_dimminglight_service.py +148 -0
  137. xp/services/homekit/homekit_hap_service.py +342 -0
  138. xp/services/homekit/homekit_lightbulb.py +120 -0
  139. xp/services/homekit/homekit_lightbulb_service.py +86 -0
  140. xp/services/homekit/homekit_module_service.py +56 -0
  141. xp/services/homekit/homekit_outlet.py +168 -0
  142. xp/services/homekit/homekit_outlet_service.py +121 -0
  143. xp/services/homekit/homekit_service.py +359 -0
  144. xp/services/log_file_service.py +309 -0
  145. xp/services/module_type_service.py +257 -0
  146. xp/services/protocol/__init__.py +21 -0
  147. xp/services/protocol/conbus_event_protocol.py +360 -0
  148. xp/services/protocol/conbus_protocol.py +318 -0
  149. xp/services/protocol/protocol_factory.py +78 -0
  150. xp/services/protocol/telegram_protocol.py +264 -0
  151. xp/services/reverse_proxy_service.py +435 -0
  152. xp/services/server/__init__.py +1 -0
  153. xp/services/server/base_server_service.py +366 -0
  154. xp/services/server/cp20_server_service.py +65 -0
  155. xp/services/server/device_service_factory.py +94 -0
  156. xp/services/server/server_service.py +428 -0
  157. xp/services/server/xp130_server_service.py +67 -0
  158. xp/services/server/xp20_server_service.py +92 -0
  159. xp/services/server/xp230_server_service.py +58 -0
  160. xp/services/server/xp24_server_service.py +245 -0
  161. xp/services/server/xp33_server_service.py +535 -0
  162. xp/services/telegram/__init__.py +1 -0
  163. xp/services/telegram/telegram_blink_service.py +138 -0
  164. xp/services/telegram/telegram_checksum_service.py +149 -0
  165. xp/services/telegram/telegram_datapoint_service.py +82 -0
  166. xp/services/telegram/telegram_discover_service.py +277 -0
  167. xp/services/telegram/telegram_link_number_service.py +216 -0
  168. xp/services/telegram/telegram_output_service.py +322 -0
  169. xp/services/telegram/telegram_service.py +380 -0
  170. xp/services/telegram/telegram_version_service.py +288 -0
  171. xp/utils/__init__.py +12 -0
  172. xp/utils/checksum.py +61 -0
  173. xp/utils/dependencies.py +531 -0
  174. xp/utils/event_helper.py +31 -0
  175. xp/utils/serialization.py +205 -0
  176. xp/utils/time_utils.py +134 -0
@@ -0,0 +1,53 @@
1
+ """XP20 Action Table models for input actions and settings."""
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+
6
+ @dataclass
7
+ class InputChannel:
8
+ """Configuration for a single input channel in XP20 action table.
9
+
10
+ Attributes:
11
+ invert: Input inversion flag
12
+ short_long: Short/long press detection flag
13
+ group_on_off: Group on/off function flag
14
+ and_functions: 8-bit AND function configuration array
15
+ sa_function: SA function flag
16
+ ta_function: TA function flag
17
+ """
18
+
19
+ invert: bool = False
20
+ short_long: bool = False
21
+ group_on_off: bool = False
22
+ and_functions: list[bool] = field(default_factory=lambda: [False] * 8)
23
+ sa_function: bool = False
24
+ ta_function: bool = False
25
+
26
+
27
+ @dataclass
28
+ class Xp20MsActionTable:
29
+ """XP20 Action Table for managing 8 input channels.
30
+
31
+ Contains configuration for 8 input channels (input1 through input8),
32
+ each with flags for inversion, short/long press detection, group functions,
33
+ AND functions, SA functions, and TA functions.
34
+
35
+ Attributes:
36
+ input1: Configuration for input channel 1.
37
+ input2: Configuration for input channel 2.
38
+ input3: Configuration for input channel 3.
39
+ input4: Configuration for input channel 4.
40
+ input5: Configuration for input channel 5.
41
+ input6: Configuration for input channel 6.
42
+ input7: Configuration for input channel 7.
43
+ input8: Configuration for input channel 8.
44
+ """
45
+
46
+ input1: InputChannel = field(default_factory=InputChannel)
47
+ input2: InputChannel = field(default_factory=InputChannel)
48
+ input3: InputChannel = field(default_factory=InputChannel)
49
+ input4: InputChannel = field(default_factory=InputChannel)
50
+ input5: InputChannel = field(default_factory=InputChannel)
51
+ input6: InputChannel = field(default_factory=InputChannel)
52
+ input7: InputChannel = field(default_factory=InputChannel)
53
+ input8: InputChannel = field(default_factory=InputChannel)
@@ -0,0 +1,58 @@
1
+ """XP24 Action Table models for input actions and settings."""
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+ from xp.models.telegram.input_action_type import InputActionType
6
+ from xp.models.telegram.timeparam_type import TimeParam
7
+
8
+
9
+ @dataclass
10
+ class InputAction:
11
+ """Represents an input action with type and parameter.
12
+
13
+ Attributes:
14
+ type: The input action type.
15
+ param: Time parameter for the action.
16
+ """
17
+
18
+ type: InputActionType = InputActionType.TOGGLE
19
+ param: TimeParam = TimeParam.NONE
20
+
21
+
22
+ @dataclass
23
+ class Xp24MsActionTable:
24
+ """XP24 Action Table for managing input actions and settings.
25
+
26
+ Each input has an action type (TOGGLE, ON, LEVELSET, etc.)
27
+ with an optional parameter string.
28
+
29
+ Attributes:
30
+ MS300: Timing constant for 300ms.
31
+ MS500: Timing constant for 500ms.
32
+ input1_action: Action configuration for input 1.
33
+ input2_action: Action configuration for input 2.
34
+ input3_action: Action configuration for input 3.
35
+ input4_action: Action configuration for input 4.
36
+ mutex12: Mutual exclusion between inputs 1-2.
37
+ mutex34: Mutual exclusion between inputs 3-4.
38
+ curtain12: Curtain setting for inputs 1-2.
39
+ curtain34: Curtain setting for inputs 3-4.
40
+ mutual_deadtime: Master timing (MS300=12 or MS500=20).
41
+ """
42
+
43
+ # MS timing constants
44
+ MS300 = 12
45
+ MS500 = 20
46
+
47
+ # Input actions for each input (default to TOGGLE with None parameter)
48
+ input1_action: InputAction = field(default_factory=InputAction)
49
+ input2_action: InputAction = field(default_factory=InputAction)
50
+ input3_action: InputAction = field(default_factory=InputAction)
51
+ input4_action: InputAction = field(default_factory=InputAction)
52
+
53
+ # Boolean settings
54
+ mutex12: bool = False # Mutual exclusion between inputs 1-2
55
+ mutex34: bool = False # Mutual exclusion between inputs 3-4
56
+ curtain12: bool = False # Curtain setting for inputs 1-2
57
+ curtain34: bool = False # Curtain setting for inputs 3-4
58
+ mutual_deadtime: int = MS300 # Master timing (MS300=12 or MS500=20)
@@ -0,0 +1,65 @@
1
+ """XP33 Action Table models for output and scene configuration."""
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+ from xp.models.telegram.timeparam_type import TimeParam
6
+
7
+
8
+ @dataclass
9
+ class Xp33Output:
10
+ """Represents an XP33 output configuration.
11
+
12
+ Attributes:
13
+ min_level: Minimum output level (0-100).
14
+ max_level: Maximum output level (0-100).
15
+ scene_outputs: Enable scene outputs.
16
+ start_at_full: Start at full brightness.
17
+ leading_edge: Use leading edge dimming.
18
+ """
19
+
20
+ min_level: int = 0
21
+ max_level: int = 100
22
+ scene_outputs: bool = False
23
+ start_at_full: bool = False
24
+ leading_edge: bool = False
25
+
26
+
27
+ @dataclass
28
+ class Xp33Scene:
29
+ """Represents a scene configuration.
30
+
31
+ Attributes:
32
+ output1_level: Output level for output 1 (0-100).
33
+ output2_level: Output level for output 2 (0-100).
34
+ output3_level: Output level for output 3 (0-100).
35
+ time: Time parameter for scene transition.
36
+ """
37
+
38
+ output1_level: int = 0
39
+ output2_level: int = 0
40
+ output3_level: int = 0
41
+ time: TimeParam = TimeParam.NONE
42
+
43
+
44
+ @dataclass
45
+ class Xp33MsActionTable:
46
+ """XP33 Action Table for managing outputs and scenes.
47
+
48
+ Attributes:
49
+ output1: Configuration for output 1.
50
+ output2: Configuration for output 2.
51
+ output3: Configuration for output 3.
52
+ scene1: Configuration for scene 1.
53
+ scene2: Configuration for scene 2.
54
+ scene3: Configuration for scene 3.
55
+ scene4: Configuration for scene 4.
56
+ """
57
+
58
+ output1: Xp33Output = field(default_factory=Xp33Output)
59
+ output2: Xp33Output = field(default_factory=Xp33Output)
60
+ output3: Xp33Output = field(default_factory=Xp33Output)
61
+
62
+ scene1: Xp33Scene = field(default_factory=Xp33Scene)
63
+ scene2: Xp33Scene = field(default_factory=Xp33Scene)
64
+ scene3: Xp33Scene = field(default_factory=Xp33Scene)
65
+ scene4: Xp33Scene = field(default_factory=Xp33Scene)
@@ -0,0 +1 @@
1
+ """Conbus communication models."""
@@ -0,0 +1,87 @@
1
+ """Conbus request and response models."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional
6
+
7
+
8
+ @dataclass
9
+ class ConbusRequest:
10
+ """Represents a Conbus send request.
11
+
12
+ Attributes:
13
+ serial_number: Serial number of the target device.
14
+ function_code: Function code for the operation.
15
+ data: Data payload for the request.
16
+ telegram: Raw telegram string.
17
+ timestamp: Timestamp of the request.
18
+ """
19
+
20
+ serial_number: Optional[str] = None
21
+ function_code: Optional[str] = None
22
+ data: Optional[str] = None
23
+ telegram: Optional[str] = None
24
+ timestamp: Optional[datetime] = None
25
+
26
+ def __post_init__(self) -> None:
27
+ """Initialize timestamp if not provided."""
28
+ if self.timestamp is None:
29
+ self.timestamp = datetime.now()
30
+
31
+ def to_dict(self) -> Dict[str, Any]:
32
+ """Convert to dictionary for JSON serialization.
33
+
34
+ Returns:
35
+ Dictionary representation of the request.
36
+ """
37
+ return {
38
+ "serial_number": self.serial_number,
39
+ "function_code": self.function_code,
40
+ "data": self.data,
41
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
42
+ }
43
+
44
+
45
+ @dataclass
46
+ class ConbusResponse:
47
+ """Represents a response from Conbus send operation.
48
+
49
+ Attributes:
50
+ success: Whether the operation was successful.
51
+ sent_telegrams: List of telegrams sent.
52
+ received_telegrams: List of telegrams received.
53
+ timestamp: Timestamp of the response.
54
+ error: Error message if operation failed.
55
+ serial_number: Serial number of the device.
56
+ function_code: Function code used.
57
+ """
58
+
59
+ success: bool
60
+ sent_telegrams: list[str]
61
+ received_telegrams: list[str]
62
+ timestamp: datetime
63
+ error: str = ""
64
+ serial_number: str = ""
65
+ function_code: str = ""
66
+
67
+ def __post_init__(self) -> None:
68
+ """Initialize timestamp and telegram lists."""
69
+ self.timestamp = datetime.now()
70
+ self.sent_telegrams = []
71
+ self.received_telegrams = []
72
+
73
+ def to_dict(self) -> Dict[str, Any]:
74
+ """Convert to dictionary for JSON serialization.
75
+
76
+ Returns:
77
+ Dictionary representation of the response.
78
+ """
79
+ return {
80
+ "success": self.success,
81
+ "serial_number": self.serial_number,
82
+ "function_code": self.function_code,
83
+ "sent_telegrams": self.sent_telegrams,
84
+ "received_telegrams": self.received_telegrams,
85
+ "error": self.error,
86
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
87
+ }
@@ -0,0 +1,67 @@
1
+ """Conbus auto report response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional
6
+
7
+
8
+ @dataclass
9
+ class ConbusAutoreportResponse:
10
+ """Represents a response from Conbus auto report operations (get/set).
11
+
12
+ Attributes:
13
+ success: Whether the operation was successful.
14
+ serial_number: Serial number of the device.
15
+ auto_report_status: Current auto report status.
16
+ result: Result message from set operation.
17
+ sent_telegram: Telegram sent to device.
18
+ received_telegrams: List of telegrams received.
19
+ error: Error message if operation failed.
20
+ timestamp: Timestamp of the response.
21
+ """
22
+
23
+ success: bool
24
+ serial_number: str
25
+ auto_report_status: Optional[str] = None
26
+ result: Optional[str] = None
27
+ sent_telegram: Optional[str] = None
28
+ received_telegrams: Optional[list[str]] = None
29
+ error: Optional[str] = None
30
+ timestamp: Optional[datetime] = None
31
+
32
+ def __post_init__(self) -> None:
33
+ """Initialize timestamp and received_telegrams if not provided."""
34
+ if self.timestamp is None:
35
+ self.timestamp = datetime.now()
36
+ if self.received_telegrams is None:
37
+ self.received_telegrams = []
38
+
39
+ def to_dict(self) -> Dict[str, Any]:
40
+ """Convert to dictionary for JSON serialization.
41
+
42
+ Returns:
43
+ Dictionary representation of the response.
44
+ """
45
+ result_dict: Dict[str, Any] = {
46
+ "success": self.success,
47
+ "serial_number": self.serial_number,
48
+ "error": self.error,
49
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
50
+ }
51
+
52
+ # Include auto_report_status if available
53
+ if self.auto_report_status is not None:
54
+ result_dict["auto_report_status"] = self.auto_report_status
55
+
56
+ # Include result for set operations
57
+ if self.result is not None:
58
+ result_dict["result"] = self.result
59
+
60
+ # Include telegram details
61
+ if self.sent_telegram is not None:
62
+ result_dict["sent_telegram"] = self.sent_telegram
63
+
64
+ if self.received_telegrams is not None:
65
+ result_dict["received_telegrams"] = self.received_telegrams
66
+
67
+ return result_dict
@@ -0,0 +1,80 @@
1
+ """Conbus blink response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional
6
+
7
+ from xp.models import ConbusResponse
8
+ from xp.models.telegram.reply_telegram import ReplyTelegram
9
+ from xp.models.telegram.system_function import SystemFunction
10
+ from xp.models.telegram.system_telegram import SystemTelegram
11
+
12
+
13
+ @dataclass
14
+ class ConbusBlinkResponse:
15
+ """Represents a response from Conbus send operation.
16
+
17
+ Attributes:
18
+ success: Whether the operation was successful.
19
+ serial_number: Serial number of the device.
20
+ operation: Operation type (get or set).
21
+ system_function: System function used.
22
+ response: Response from Conbus operation.
23
+ reply_telegram: Reply telegram received.
24
+ sent_telegram: System telegram sent.
25
+ received_telegrams: List of telegrams received.
26
+ error: Error message if operation failed.
27
+ timestamp: Timestamp of the response.
28
+ """
29
+
30
+ success: bool
31
+ serial_number: str
32
+ operation: str
33
+ system_function: SystemFunction
34
+ response: Optional[ConbusResponse] = None
35
+ reply_telegram: Optional[ReplyTelegram] = None
36
+ sent_telegram: Optional[SystemTelegram] = None
37
+ received_telegrams: Optional[list] = None
38
+ error: Optional[str] = None
39
+ timestamp: Optional[datetime] = None
40
+
41
+ def __post_init__(self) -> None:
42
+ """Initialize timestamp and received_telegrams if not provided."""
43
+ if self.timestamp is None:
44
+ self.timestamp = datetime.now()
45
+ if self.received_telegrams is None:
46
+ self.received_telegrams = []
47
+
48
+ def to_dict(self) -> Dict[str, Any]:
49
+ """Convert to dictionary for JSON serialization.
50
+
51
+ Returns:
52
+ Dictionary representation of the response.
53
+ """
54
+ result = {
55
+ "success": self.success,
56
+ "serial_number": self.serial_number,
57
+ "operation": self.operation,
58
+ "system_function": (
59
+ self.system_function.name if self.system_function else None
60
+ ),
61
+ "sent_telegram": (
62
+ self.sent_telegram.to_dict()
63
+ if self.sent_telegram and hasattr(self.sent_telegram, "to_dict")
64
+ else str(self.sent_telegram) if self.sent_telegram else None
65
+ ),
66
+ "reply_telegram": (
67
+ self.reply_telegram.to_dict()
68
+ if self.reply_telegram and hasattr(self.reply_telegram, "to_dict")
69
+ else str(self.reply_telegram) if self.reply_telegram else None
70
+ ),
71
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
72
+ }
73
+
74
+ # Only include these if they have values
75
+ if self.received_telegrams:
76
+ result["received_telegrams"] = self.received_telegrams
77
+ if self.error:
78
+ result["error"] = self.error
79
+
80
+ return result
@@ -0,0 +1,55 @@
1
+ """Conbus client configuration models."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import yaml
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class ClientConfig(BaseModel):
11
+ """Client connection configuration.
12
+
13
+ Attributes:
14
+ ip: IP address of the Conbus server.
15
+ port: Port number for the connection.
16
+ timeout: Connection timeout in seconds.
17
+ """
18
+
19
+ ip: str = "192.168.1.100"
20
+ port: int = 10001
21
+ timeout: float = 0.1
22
+
23
+
24
+ class ConbusClientConfig(BaseModel):
25
+ """Configuration for Conbus client connection.
26
+
27
+ Attributes:
28
+ conbus: Client configuration settings.
29
+ """
30
+
31
+ conbus: ClientConfig = Field(default_factory=ClientConfig)
32
+
33
+ @classmethod
34
+ def from_yaml(cls, file_path: str) -> "ConbusClientConfig":
35
+ """Load configuration from YAML file.
36
+
37
+ Args:
38
+ file_path: Path to the YAML configuration file.
39
+
40
+ Returns:
41
+ ConbusClientConfig instance loaded from file or default config.
42
+ """
43
+ logger = logging.getLogger(__name__)
44
+ try:
45
+ with Path(file_path).open("r") as file:
46
+ data = yaml.safe_load(file)
47
+ return cls(**data)
48
+
49
+ except FileNotFoundError:
50
+ logger.error(f"File {file_path} does not exist, loading default")
51
+ return cls()
52
+ except yaml.YAMLError:
53
+ logger.error(f"File {file_path} is not valid")
54
+ # Return default config if YAML parsing fails
55
+ return cls()
@@ -0,0 +1,40 @@
1
+ """Conbus connection status model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional
6
+
7
+
8
+ @dataclass
9
+ class ConbusConnectionStatus:
10
+ """Represents the current connection status.
11
+
12
+ Attributes:
13
+ connected: Whether currently connected.
14
+ ip: IP address of the connection.
15
+ port: Port number of the connection.
16
+ last_activity: Timestamp of last activity.
17
+ error: Error message if connection failed.
18
+ """
19
+
20
+ connected: bool
21
+ ip: str
22
+ port: int
23
+ last_activity: Optional[datetime] = None
24
+ error: Optional[str] = None
25
+
26
+ def to_dict(self) -> Dict[str, Any]:
27
+ """Convert to dictionary for JSON serialization.
28
+
29
+ Returns:
30
+ Dictionary representation of the connection status.
31
+ """
32
+ return {
33
+ "connected": self.connected,
34
+ "ip": self.ip,
35
+ "port": self.port,
36
+ "last_activity": (
37
+ self.last_activity.isoformat() if self.last_activity else None
38
+ ),
39
+ "error": self.error,
40
+ }
@@ -0,0 +1,58 @@
1
+ """Conbus custom response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional
6
+
7
+ from xp.models.telegram.reply_telegram import ReplyTelegram
8
+
9
+
10
+ @dataclass
11
+ class ConbusCustomResponse:
12
+ """Represents a response from Conbus send operation.
13
+
14
+ Attributes:
15
+ success: Whether the operation was successful.
16
+ serial_number: Serial number of the device.
17
+ function_code: Function code used.
18
+ data: Data payload.
19
+ sent_telegram: Telegram sent to device.
20
+ received_telegrams: List of telegrams received.
21
+ reply_telegram: Parsed reply telegram.
22
+ error: Error message if operation failed.
23
+ timestamp: Timestamp of the response.
24
+ """
25
+
26
+ success: bool
27
+ serial_number: Optional[str] = None
28
+ function_code: Optional[str] = None
29
+ data: Optional[str] = None
30
+ sent_telegram: Optional[str] = None
31
+ received_telegrams: Optional[list] = None
32
+ reply_telegram: Optional[ReplyTelegram] = None
33
+ error: Optional[str] = None
34
+ timestamp: Optional[datetime] = None
35
+
36
+ def __post_init__(self) -> None:
37
+ """Initialize timestamp and received_telegrams if not provided."""
38
+ if self.timestamp is None:
39
+ self.timestamp = datetime.now()
40
+ if self.received_telegrams is None:
41
+ self.received_telegrams = []
42
+
43
+ def to_dict(self) -> Dict[str, Any]:
44
+ """Convert to dictionary for JSON serialization.
45
+
46
+ Returns:
47
+ Dictionary representation of the response.
48
+ """
49
+ return {
50
+ "success": self.success,
51
+ "serial_number": self.serial_number,
52
+ "function_code": self.function_code,
53
+ "data": self.data,
54
+ "sent_telegram": self.sent_telegram,
55
+ "received_telegrams": self.received_telegrams,
56
+ "error": self.error,
57
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
58
+ }
@@ -0,0 +1,89 @@
1
+ """Conbus datapoint response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from xp.models.telegram.datapoint_type import DataPointType
8
+ from xp.models.telegram.reply_telegram import ReplyTelegram
9
+ from xp.models.telegram.system_function import SystemFunction
10
+
11
+
12
+ @dataclass
13
+ class ConbusDatapointResponse:
14
+ """Represents a response from Conbus send operation.
15
+
16
+ Attributes:
17
+ success: Whether the operation was successful.
18
+ serial_number: Serial number of the device.
19
+ system_function: System function used for query.
20
+ datapoint_type: Type of datapoint queried.
21
+ sent_telegram: Telegram sent to device.
22
+ received_telegrams: List of telegrams received.
23
+ datapoint_telegram: Parsed datapoint telegram.
24
+ data_value: Value of the datapoint telegram.
25
+ datapoints: List of datapoint values.
26
+ error: Error message if operation failed.
27
+ timestamp: Timestamp of the response.
28
+ """
29
+
30
+ success: bool
31
+ serial_number: Optional[str] = None
32
+ system_function: Optional[SystemFunction] = None
33
+ datapoint_type: Optional[DataPointType] = None
34
+ sent_telegram: Optional[str] = None
35
+ received_telegrams: Optional[list] = None
36
+ datapoint_telegram: Optional[ReplyTelegram] = None
37
+ data_value: str = ""
38
+ datapoints: Optional[List[Dict[str, str]]] = None
39
+ error: Optional[str] = None
40
+ timestamp: Optional[datetime] = None
41
+
42
+ def __post_init__(self) -> None:
43
+ """Initialize timestamp, received_telegrams, and datapoints if not provided."""
44
+ if self.timestamp is None:
45
+ self.timestamp = datetime.now()
46
+ if self.received_telegrams is None:
47
+ self.received_telegrams = []
48
+ if self.datapoints is None:
49
+ self.datapoints = []
50
+
51
+ def to_dict(self) -> Dict[str, Any]:
52
+ """Convert to dictionary for JSON serialization.
53
+
54
+ Returns:
55
+ Dictionary representation of the response.
56
+ """
57
+ result: Dict[str, Any] = {
58
+ "success": self.success,
59
+ "serial_number": self.serial_number,
60
+ "data_value": self.data_value,
61
+ "error": self.error,
62
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
63
+ }
64
+
65
+ # Include system_function for single datapoint queries
66
+ if self.system_function is not None:
67
+ result["system_function"] = str(self.system_function)
68
+
69
+ # Include datapoint_type for single datapoint queries
70
+ if self.datapoint_type is not None:
71
+ result["datapoint_type"] = str(self.datapoint_type)
72
+
73
+ # Include sent_telegram for single datapoint queries
74
+ if self.sent_telegram is not None:
75
+ result["sent_telegram"] = self.sent_telegram
76
+
77
+ # Include received_telegrams for single datapoint queries
78
+ if self.received_telegrams is not None:
79
+ result["received_telegrams"] = self.received_telegrams
80
+
81
+ # Include datapoint_telegram for single datapoint queries
82
+ if self.datapoint_telegram is not None:
83
+ result["datapoint_telegram"] = self.datapoint_telegram.to_dict()
84
+
85
+ # Include datapoints for all datapoints queries
86
+ if self.datapoints is not None and len(self.datapoints) > 0:
87
+ result["datapoints"] = self.datapoints
88
+
89
+ return result