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,64 @@
1
+ """Conbus discover response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional, TypedDict
6
+
7
+
8
+ class DiscoveredDevice(TypedDict):
9
+ """Discovered device information.
10
+
11
+ Attributes:
12
+ serial_number: Serial number of the device.
13
+ module_type: Module type name (e.g., "XP24", "XP230"), None if not yet retrieved.
14
+ module_type_code: Module type code (e.g., "13", "10"), None if not yet retrieved.
15
+ module_type_name: Module type name converted from module_type_code, None if not yet retrieved.
16
+ """
17
+
18
+ serial_number: str
19
+ module_type: Optional[str]
20
+ module_type_code: Optional[int]
21
+ module_type_name: Optional[str]
22
+
23
+
24
+ @dataclass
25
+ class ConbusDiscoverResponse:
26
+ """Represents a response from Conbus send operation.
27
+
28
+ Attributes:
29
+ success: Whether the operation was successful.
30
+ sent_telegram: Telegram sent to discover devices.
31
+ received_telegrams: List of telegrams received.
32
+ discovered_devices: List of discovered devices with their module types.
33
+ error: Error message if operation failed.
34
+ timestamp: Timestamp of the response.
35
+ """
36
+
37
+ success: bool
38
+ sent_telegram: Optional[str] = None
39
+ received_telegrams: Optional[list[str]] = None
40
+ discovered_devices: Optional[list[DiscoveredDevice]] = None
41
+ error: Optional[str] = None
42
+ timestamp: Optional[datetime] = None
43
+
44
+ def __post_init__(self) -> None:
45
+ """Initialize timestamp and received_telegrams if not provided."""
46
+ if self.timestamp is None:
47
+ self.timestamp = datetime.now()
48
+ if self.received_telegrams is None:
49
+ self.received_telegrams = []
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
+ return {
58
+ "success": self.success,
59
+ "sent_telegram": self.sent_telegram,
60
+ "received_telegrams": self.received_telegrams,
61
+ "discovered_devices": self.discovered_devices,
62
+ "error": self.error,
63
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
64
+ }
@@ -0,0 +1,47 @@
1
+ """Conbus event raw 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 ConbusEventRawResponse:
10
+ """Represents a response from Conbus event raw operation.
11
+
12
+ Attributes:
13
+ success: Whether the operation was successful.
14
+ sent_telegrams: List of event telegrams sent (MAKE and BREAK).
15
+ received_telegrams: List of all telegrams received.
16
+ error: Error message if operation failed.
17
+ timestamp: Timestamp of the response.
18
+ """
19
+
20
+ success: bool
21
+ sent_telegrams: Optional[list[str]] = None
22
+ received_telegrams: Optional[list[str]] = None
23
+ error: Optional[str] = None
24
+ timestamp: Optional[datetime] = None
25
+
26
+ def __post_init__(self) -> None:
27
+ """Initialize timestamp and telegram lists if not provided."""
28
+ if self.timestamp is None:
29
+ self.timestamp = datetime.now()
30
+ if self.sent_telegrams is None:
31
+ self.sent_telegrams = []
32
+ if self.received_telegrams is None:
33
+ self.received_telegrams = []
34
+
35
+ def to_dict(self) -> Dict[str, Any]:
36
+ """Convert to dictionary for JSON serialization.
37
+
38
+ Returns:
39
+ Dictionary representation of the response.
40
+ """
41
+ return {
42
+ "success": self.success,
43
+ "sent_telegrams": self.sent_telegrams,
44
+ "received_telegrams": self.received_telegrams,
45
+ "error": self.error,
46
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
47
+ }
@@ -0,0 +1,52 @@
1
+ """Conbus light level 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 ConbusLightlevelResponse:
10
+ """Represents a response from Conbus lightlevel operation.
11
+
12
+ Attributes:
13
+ success: Whether the operation was successful.
14
+ serial_number: Serial number of the device.
15
+ output_number: Output number queried.
16
+ level: Light level value (0-100).
17
+ timestamp: Timestamp of the response.
18
+ sent_telegram: Telegram sent to device.
19
+ received_telegrams: List of telegrams received.
20
+ error: Error message if operation failed.
21
+ """
22
+
23
+ success: bool
24
+ serial_number: str
25
+ output_number: int
26
+ level: Optional[int]
27
+ timestamp: datetime
28
+ sent_telegram: Optional[str] = None
29
+ received_telegrams: Optional[list[str]] = None
30
+ error: Optional[str] = None
31
+
32
+ def __post_init__(self) -> None:
33
+ """Initialize received_telegrams if not provided."""
34
+ if self.received_telegrams is None:
35
+ self.received_telegrams = []
36
+
37
+ def to_dict(self) -> Dict[str, Any]:
38
+ """Convert to dictionary for JSON serialization.
39
+
40
+ Returns:
41
+ Dictionary representation of the response.
42
+ """
43
+ return {
44
+ "success": self.success,
45
+ "serial_number": self.serial_number,
46
+ "output_number": self.output_number,
47
+ "level": self.level,
48
+ "sent_telegram": self.sent_telegram,
49
+ "received_telegrams": self.received_telegrams,
50
+ "error": self.error,
51
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
52
+ }
@@ -0,0 +1,54 @@
1
+ """Conbus link number 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 ConbusLinknumberResponse:
10
+ """Represents a response from Conbus link number operations (set/get).
11
+
12
+ Attributes:
13
+ success: Whether the operation was successful.
14
+ serial_number: Serial number of the device.
15
+ result: Result message from operation.
16
+ sent_telegram: Telegram sent to device.
17
+ received_telegrams: List of telegrams received.
18
+ link_number: Link number value.
19
+ error: Error message if operation failed.
20
+ timestamp: Timestamp of the response.
21
+ """
22
+
23
+ success: bool
24
+ serial_number: str
25
+ result: str
26
+ sent_telegram: Optional[str] = None
27
+ received_telegrams: Optional[list] = None
28
+ link_number: Optional[int] = 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
+ return {
46
+ "success": self.success,
47
+ "result": self.result,
48
+ "link_number": self.link_number,
49
+ "serial_number": self.serial_number,
50
+ "sent_telegram": self.sent_telegram,
51
+ "received_telegrams": self.received_telegrams,
52
+ "error": self.error,
53
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
54
+ }
@@ -0,0 +1,57 @@
1
+ """Conbus output 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.action_type import ActionType
8
+ from xp.models.telegram.output_telegram import OutputTelegram
9
+ from xp.models.telegram.reply_telegram import ReplyTelegram
10
+
11
+
12
+ @dataclass
13
+ class ConbusOutputResponse:
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
+ output_number: Output number controlled.
20
+ action_type: Type of action performed.
21
+ timestamp: Timestamp of the response.
22
+ output_telegram: Output telegram sent.
23
+ sent_telegram: Raw telegram sent to device.
24
+ received_telegrams: List of telegrams received.
25
+ datapoint_telegram: Datapoint telegram received.
26
+ error: Error message if operation failed.
27
+ """
28
+
29
+ success: bool
30
+ serial_number: str
31
+ output_number: int
32
+ action_type: ActionType
33
+ timestamp: datetime
34
+ output_telegram: Optional[OutputTelegram] = None
35
+ sent_telegram: Optional[str] = None
36
+ received_telegrams: Optional[list[str]] = None
37
+ datapoint_telegram: Optional[ReplyTelegram] = None
38
+ error: Optional[str] = None
39
+
40
+ def __post_init__(self) -> None:
41
+ """Initialize received_telegrams if not provided."""
42
+ if self.received_telegrams is None:
43
+ self.received_telegrams = []
44
+
45
+ def to_dict(self) -> Dict[str, Any]:
46
+ """Convert to dictionary for JSON serialization.
47
+
48
+ Returns:
49
+ Dictionary representation of the response.
50
+ """
51
+ return {
52
+ "success": self.success,
53
+ "sent_telegram": self.sent_telegram,
54
+ "received_telegrams": self.received_telegrams,
55
+ "error": self.error,
56
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
57
+ }
@@ -0,0 +1,45 @@
1
+ """Conbus raw response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, List, Optional
6
+
7
+
8
+ @dataclass
9
+ class ConbusRawResponse:
10
+ """Represents a response from Conbus raw telegram send operation.
11
+
12
+ Attributes:
13
+ success: Whether the operation was successful.
14
+ sent_telegrams: Raw telegrams sent.
15
+ received_telegrams: List of telegrams received.
16
+ error: Error message if operation failed.
17
+ timestamp: Timestamp of the response.
18
+ """
19
+
20
+ success: bool
21
+ sent_telegrams: Optional[str] = None
22
+ received_telegrams: Optional[List[str]] = None
23
+ error: Optional[str] = None
24
+ timestamp: Optional[datetime] = None
25
+
26
+ def __post_init__(self) -> None:
27
+ """Initialize timestamp and received_telegrams if not provided."""
28
+ if self.timestamp is None:
29
+ self.timestamp = datetime.now()
30
+ if self.received_telegrams is None:
31
+ self.received_telegrams = []
32
+
33
+ def to_dict(self) -> Dict[str, Any]:
34
+ """Convert to dictionary for JSON serialization.
35
+
36
+ Returns:
37
+ Dictionary representation of the response.
38
+ """
39
+ return {
40
+ "success": self.success,
41
+ "sent_telegrams": self.sent_telegrams,
42
+ "received_telegrams": self.received_telegrams,
43
+ "error": self.error,
44
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
45
+ }
@@ -0,0 +1,42 @@
1
+ """Conbus receive response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, List, Optional
6
+
7
+
8
+ @dataclass
9
+ class ConbusReceiveResponse:
10
+ """Represents a response from Conbus receive operation.
11
+
12
+ Attributes:
13
+ success: Whether the operation was successful.
14
+ received_telegrams: List of telegrams received.
15
+ error: Error message if operation failed.
16
+ timestamp: Timestamp of the response.
17
+ """
18
+
19
+ success: bool
20
+ received_telegrams: Optional[List[str]] = None
21
+ error: Optional[str] = None
22
+ timestamp: Optional[datetime] = None
23
+
24
+ def __post_init__(self) -> None:
25
+ """Initialize timestamp and received_telegrams if not provided."""
26
+ if self.timestamp is None:
27
+ self.timestamp = datetime.now()
28
+ if self.received_telegrams is None:
29
+ self.received_telegrams = []
30
+
31
+ def to_dict(self) -> Dict[str, Any]:
32
+ """Convert to dictionary for JSON serialization.
33
+
34
+ Returns:
35
+ Dictionary representation of the response.
36
+ """
37
+ return {
38
+ "success": self.success,
39
+ "received_telegrams": self.received_telegrams,
40
+ "error": self.error,
41
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
42
+ }
@@ -0,0 +1,60 @@
1
+ """Conbus link number 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.datapoint_type import DataPointType
8
+ from xp.models.telegram.system_function import SystemFunction
9
+
10
+
11
+ @dataclass
12
+ class ConbusWriteConfigResponse:
13
+ """Represents a response from Conbus write config operations (set/get).
14
+
15
+ Attributes:
16
+ success: Whether the operation was successful.
17
+ serial_number: Serial number of the device.
18
+ datapoint_type: the datapoint to write.
19
+ system_function: ACK or NAK received.
20
+ sent_telegram: Telegram sent to device.
21
+ received_telegrams: List of telegrams received.
22
+ data_value: written value.
23
+ error: Error message if operation failed.
24
+ timestamp: Timestamp of the response.
25
+ """
26
+
27
+ success: bool
28
+ serial_number: str
29
+ datapoint_type: Optional[DataPointType] = None
30
+ system_function: Optional[SystemFunction] = None
31
+ sent_telegram: Optional[str] = None
32
+ received_telegrams: Optional[list] = None
33
+ data_value: Optional[str] = None
34
+ error: Optional[str] = None
35
+ timestamp: Optional[datetime] = None
36
+
37
+ def __post_init__(self) -> None:
38
+ """Initialize timestamp and received_telegrams if not provided."""
39
+ if self.timestamp is None:
40
+ self.timestamp = datetime.now()
41
+ if self.received_telegrams is None:
42
+ self.received_telegrams = []
43
+
44
+ def to_dict(self) -> Dict[str, Any]:
45
+ """Convert to dictionary for JSON serialization.
46
+
47
+ Returns:
48
+ Dictionary representation of the response.
49
+ """
50
+ return {
51
+ "success": self.success,
52
+ "system_function": self.system_function,
53
+ "datapoint_type": self.datapoint_type,
54
+ "data_value": self.data_value,
55
+ "serial_number": self.serial_number,
56
+ "sent_telegram": self.sent_telegram,
57
+ "received_telegrams": self.received_telegrams,
58
+ "error": self.error,
59
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
60
+ }
@@ -0,0 +1 @@
1
+ """HomeKit integration models."""
@@ -0,0 +1,35 @@
1
+ """HomeKit configuration models."""
2
+
3
+ import random
4
+ from typing import Any
5
+
6
+ from pyhap.accessory import Accessory
7
+ from pyhap.const import CATEGORY_SENSOR
8
+
9
+
10
+ class TemperatureSensor(Accessory):
11
+ """Fake Temperature sensor, measuring every 3 seconds.
12
+
13
+ Attributes:
14
+ category: HomeKit category for sensor.
15
+ char_temp: Temperature characteristic.
16
+ """
17
+
18
+ category = CATEGORY_SENSOR
19
+
20
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
21
+ """Initialize temperature sensor accessory.
22
+
23
+ Args:
24
+ args: Positional arguments passed to parent Accessory.
25
+ kwargs: Keyword arguments passed to parent Accessory.
26
+ """
27
+ super().__init__(*args, **kwargs)
28
+
29
+ serv_temp = self.add_preload_service("TemperatureSensor")
30
+ self.char_temp = serv_temp.configure_char("CurrentTemperature")
31
+
32
+ @Accessory.run_at_interval(30)
33
+ async def run(self) -> None:
34
+ """Update temperature value every 30 seconds."""
35
+ self.char_temp.set_value(random.randint(-25, 25))
@@ -0,0 +1,106 @@
1
+ """HomeKit configuration models."""
2
+
3
+ import logging
4
+ from ipaddress import IPv4Address, IPv6Address
5
+ from pathlib import Path
6
+ from typing import List, Optional, Union
7
+
8
+ import yaml
9
+ from pydantic import BaseModel, Field, IPvAnyAddress
10
+
11
+
12
+ class NetworkConfig(BaseModel):
13
+ """Network configuration settings.
14
+
15
+ Attributes:
16
+ ip: IP address for the network connection.
17
+ port: Port number for the network connection.
18
+ """
19
+
20
+ ip: Union[IPvAnyAddress, IPv4Address, IPv6Address, str] = "127.0.0.1"
21
+ port: int = 51826
22
+
23
+
24
+ class RoomConfig(BaseModel):
25
+ """Room configuration settings.
26
+
27
+ Attributes:
28
+ name: Name of the room.
29
+ accessories: List of accessory identifiers in the room.
30
+ """
31
+
32
+ name: str
33
+ accessories: List[str]
34
+
35
+
36
+ class BridgeConfig(BaseModel):
37
+ """HomeKit bridge settings.
38
+
39
+ Attributes:
40
+ name: Name of the HomeKit bridge.
41
+ rooms: List of room configurations.
42
+ """
43
+
44
+ name: str = "Conson Bridge"
45
+ rooms: List[RoomConfig] = []
46
+
47
+
48
+ class HomekitAccessoryConfig(BaseModel):
49
+ """HomeKit accessory configuration.
50
+
51
+ Attributes:
52
+ name: Name of the accessory.
53
+ id: Unique identifier for the accessory.
54
+ serial_number: Serial number of the accessory.
55
+ output_number: Output number for the accessory.
56
+ description: Description of the accessory.
57
+ service: Service type for the accessory.
58
+ on_action: on code for the accessory.
59
+ off_action: off code for the accessory.
60
+ hap_accessory: Optional HAP accessory identifier.
61
+ """
62
+
63
+ name: str
64
+ id: str
65
+ serial_number: str
66
+ output_number: int
67
+ description: str
68
+ service: str
69
+ on_action: str
70
+ off_action: str
71
+ hap_accessory: Optional[int] = None
72
+
73
+
74
+ class HomekitConfig(BaseModel):
75
+ """HomeKit bridge configuration.
76
+
77
+ Attributes:
78
+ homekit: Network configuration for HomeKit.
79
+ conson: Network configuration for Conson.
80
+ bridge: Bridge configuration settings.
81
+ accessories: List of accessory configurations.
82
+ """
83
+
84
+ homekit: NetworkConfig = Field(default_factory=NetworkConfig)
85
+ conson: NetworkConfig = Field(default_factory=NetworkConfig)
86
+ bridge: BridgeConfig = Field(default_factory=BridgeConfig)
87
+ accessories: List[HomekitAccessoryConfig] = []
88
+
89
+ @classmethod
90
+ def from_yaml(cls, file_path: str) -> "HomekitConfig":
91
+ """Load configuration from YAML file.
92
+
93
+ Args:
94
+ file_path: Path to the YAML configuration file.
95
+
96
+ Returns:
97
+ HomekitConfig instance loaded from file or default config.
98
+ """
99
+ if not Path(file_path).exists():
100
+ logger = logging.getLogger(__name__)
101
+ logger.error(f"File {file_path} does not exist, loading default")
102
+ return cls()
103
+
104
+ with Path(file_path).open("r") as file:
105
+ data = yaml.safe_load(file)
106
+ return cls(**data)
@@ -0,0 +1,86 @@
1
+ """HomeKit configuration models."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+ from typing import List, Optional
6
+
7
+ from pydantic import BaseModel, IPvAnyAddress
8
+
9
+
10
+ class ConsonModuleConfig(BaseModel):
11
+ """Configuration for a Conson module.
12
+
13
+ Attributes:
14
+ name: Name of the module.
15
+ serial_number: Serial number of the module.
16
+ module_type: Type of the module.
17
+ module_type_code: Numeric code for the module type.
18
+ link_number: Link number for the module.
19
+ enabled: Whether the module is enabled.
20
+ module_number: Optional module number.
21
+ conbus_ip: Optional Conbus IP address.
22
+ conbus_port: Optional Conbus port number.
23
+ sw_version: Optional software version.
24
+ hw_version: Optional hardware version.
25
+ action_table: Optional action table configuration.
26
+ auto_report_status: Optional auto report status.
27
+ """
28
+
29
+ name: str
30
+ serial_number: str
31
+ module_type: str
32
+ module_type_code: int
33
+ link_number: int
34
+ enabled: bool = True
35
+ module_number: Optional[int] = None
36
+ conbus_ip: Optional[IPvAnyAddress] = None
37
+ conbus_port: Optional[int] = None
38
+ sw_version: Optional[str] = None
39
+ hw_version: Optional[str] = None
40
+ action_table: Optional[List[str]] = None
41
+ auto_report_status: Optional[str] = None
42
+
43
+
44
+ class ConsonModuleListConfig(BaseModel):
45
+ """Configuration list for Conson modules.
46
+
47
+ Attributes:
48
+ root: List of Conson module configurations.
49
+ """
50
+
51
+ root: List[ConsonModuleConfig] = []
52
+
53
+ @classmethod
54
+ def from_yaml(cls, file_path: str) -> "ConsonModuleListConfig":
55
+ """Load configuration from YAML file.
56
+
57
+ Args:
58
+ file_path: Path to the YAML configuration file.
59
+
60
+ Returns:
61
+ ConsonModuleListConfig instance loaded from file or default config.
62
+ """
63
+ import yaml
64
+
65
+ if not Path(file_path).exists():
66
+ logger = logging.getLogger(__name__)
67
+ logger.error(f"File {file_path} does not exist, loading default")
68
+ return cls()
69
+
70
+ with Path(file_path).open("r") as file:
71
+ data = yaml.safe_load(file)
72
+ return cls(root=data)
73
+
74
+ def find_module(self, serial_number: str) -> Optional[ConsonModuleConfig]:
75
+ """Find a module by serial number.
76
+
77
+ Args:
78
+ serial_number: Module serial number to search for.
79
+
80
+ Returns:
81
+ ConsonModuleConfig if found, None otherwise.
82
+ """
83
+ for module in self.root:
84
+ if module.serial_number == serial_number:
85
+ return module
86
+ return None