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.
- conson_xp-1.18.0.dist-info/METADATA +412 -0
- conson_xp-1.18.0.dist-info/RECORD +176 -0
- conson_xp-1.18.0.dist-info/WHEEL +4 -0
- conson_xp-1.18.0.dist-info/entry_points.txt +5 -0
- conson_xp-1.18.0.dist-info/licenses/LICENSE +29 -0
- xp/__init__.py +9 -0
- xp/cli/__init__.py +5 -0
- xp/cli/__main__.py +6 -0
- xp/cli/commands/__init__.py +153 -0
- xp/cli/commands/conbus/__init__.py +25 -0
- xp/cli/commands/conbus/conbus.py +128 -0
- xp/cli/commands/conbus/conbus_actiontable_commands.py +233 -0
- xp/cli/commands/conbus/conbus_autoreport_commands.py +108 -0
- xp/cli/commands/conbus/conbus_blink_commands.py +163 -0
- xp/cli/commands/conbus/conbus_config_commands.py +29 -0
- xp/cli/commands/conbus/conbus_custom_commands.py +57 -0
- xp/cli/commands/conbus/conbus_datapoint_commands.py +113 -0
- xp/cli/commands/conbus/conbus_discover_commands.py +61 -0
- xp/cli/commands/conbus/conbus_event_commands.py +81 -0
- xp/cli/commands/conbus/conbus_lightlevel_commands.py +207 -0
- xp/cli/commands/conbus/conbus_linknumber_commands.py +102 -0
- xp/cli/commands/conbus/conbus_modulenumber_commands.py +104 -0
- xp/cli/commands/conbus/conbus_msactiontable_commands.py +94 -0
- xp/cli/commands/conbus/conbus_output_commands.py +163 -0
- xp/cli/commands/conbus/conbus_raw_commands.py +62 -0
- xp/cli/commands/conbus/conbus_receive_commands.py +59 -0
- xp/cli/commands/conbus/conbus_scan_commands.py +58 -0
- xp/cli/commands/file_commands.py +186 -0
- xp/cli/commands/homekit/__init__.py +3 -0
- xp/cli/commands/homekit/homekit.py +118 -0
- xp/cli/commands/homekit/homekit_start_commands.py +43 -0
- xp/cli/commands/module_commands.py +187 -0
- xp/cli/commands/reverse_proxy_commands.py +178 -0
- xp/cli/commands/server/__init__.py +3 -0
- xp/cli/commands/server/server_commands.py +135 -0
- xp/cli/commands/telegram/__init__.py +5 -0
- xp/cli/commands/telegram/telegram.py +41 -0
- xp/cli/commands/telegram/telegram_blink_commands.py +79 -0
- xp/cli/commands/telegram/telegram_checksum_commands.py +112 -0
- xp/cli/commands/telegram/telegram_discover_commands.py +41 -0
- xp/cli/commands/telegram/telegram_linknumber_commands.py +86 -0
- xp/cli/commands/telegram/telegram_parse_commands.py +75 -0
- xp/cli/commands/telegram/telegram_version_commands.py +52 -0
- xp/cli/main.py +87 -0
- xp/cli/utils/__init__.py +1 -0
- xp/cli/utils/click_tree.py +57 -0
- xp/cli/utils/datapoint_type_choice.py +57 -0
- xp/cli/utils/decorators.py +351 -0
- xp/cli/utils/error_handlers.py +201 -0
- xp/cli/utils/formatters.py +312 -0
- xp/cli/utils/module_type_choice.py +56 -0
- xp/cli/utils/serial_number_type.py +52 -0
- xp/cli/utils/system_function_choice.py +57 -0
- xp/cli/utils/xp_module_type.py +53 -0
- xp/connection/__init__.py +13 -0
- xp/connection/exceptions.py +22 -0
- xp/models/__init__.py +36 -0
- xp/models/actiontable/__init__.py +1 -0
- xp/models/actiontable/actiontable.py +43 -0
- xp/models/actiontable/msactiontable_xp20.py +53 -0
- xp/models/actiontable/msactiontable_xp24.py +58 -0
- xp/models/actiontable/msactiontable_xp33.py +65 -0
- xp/models/conbus/__init__.py +1 -0
- xp/models/conbus/conbus.py +87 -0
- xp/models/conbus/conbus_autoreport.py +67 -0
- xp/models/conbus/conbus_blink.py +80 -0
- xp/models/conbus/conbus_client_config.py +55 -0
- xp/models/conbus/conbus_connection_status.py +40 -0
- xp/models/conbus/conbus_custom.py +58 -0
- xp/models/conbus/conbus_datapoint.py +89 -0
- xp/models/conbus/conbus_discover.py +64 -0
- xp/models/conbus/conbus_event_raw.py +47 -0
- xp/models/conbus/conbus_lightlevel.py +52 -0
- xp/models/conbus/conbus_linknumber.py +54 -0
- xp/models/conbus/conbus_output.py +57 -0
- xp/models/conbus/conbus_raw.py +45 -0
- xp/models/conbus/conbus_receive.py +42 -0
- xp/models/conbus/conbus_writeconfig.py +60 -0
- xp/models/homekit/__init__.py +1 -0
- xp/models/homekit/homekit_accessory.py +35 -0
- xp/models/homekit/homekit_config.py +106 -0
- xp/models/homekit/homekit_conson_config.py +86 -0
- xp/models/log_entry.py +130 -0
- xp/models/protocol/__init__.py +1 -0
- xp/models/protocol/conbus_protocol.py +312 -0
- xp/models/response.py +42 -0
- xp/models/telegram/__init__.py +1 -0
- xp/models/telegram/action_type.py +31 -0
- xp/models/telegram/datapoint_type.py +82 -0
- xp/models/telegram/event_telegram.py +140 -0
- xp/models/telegram/event_type.py +15 -0
- xp/models/telegram/input_action_type.py +69 -0
- xp/models/telegram/input_type.py +17 -0
- xp/models/telegram/module_type.py +188 -0
- xp/models/telegram/module_type_code.py +205 -0
- xp/models/telegram/output_telegram.py +103 -0
- xp/models/telegram/reply_telegram.py +297 -0
- xp/models/telegram/system_function.py +116 -0
- xp/models/telegram/system_telegram.py +94 -0
- xp/models/telegram/telegram.py +28 -0
- xp/models/telegram/telegram_type.py +19 -0
- xp/models/telegram/timeparam_type.py +51 -0
- xp/models/write_config_type.py +33 -0
- xp/services/__init__.py +26 -0
- xp/services/actiontable/__init__.py +1 -0
- xp/services/actiontable/actiontable_serializer.py +273 -0
- xp/services/actiontable/msactiontable_serializer.py +7 -0
- xp/services/actiontable/msactiontable_xp20_serializer.py +169 -0
- xp/services/actiontable/msactiontable_xp24_serializer.py +120 -0
- xp/services/actiontable/msactiontable_xp33_serializer.py +239 -0
- xp/services/conbus/__init__.py +1 -0
- xp/services/conbus/actiontable/__init__.py +1 -0
- xp/services/conbus/actiontable/actiontable_download_service.py +158 -0
- xp/services/conbus/actiontable/actiontable_list_service.py +91 -0
- xp/services/conbus/actiontable/actiontable_show_service.py +89 -0
- xp/services/conbus/actiontable/actiontable_upload_service.py +211 -0
- xp/services/conbus/actiontable/msactiontable_service.py +232 -0
- xp/services/conbus/conbus_blink_all_service.py +181 -0
- xp/services/conbus/conbus_blink_service.py +158 -0
- xp/services/conbus/conbus_custom_service.py +156 -0
- xp/services/conbus/conbus_datapoint_queryall_service.py +182 -0
- xp/services/conbus/conbus_datapoint_service.py +170 -0
- xp/services/conbus/conbus_discover_service.py +312 -0
- xp/services/conbus/conbus_event_raw_service.py +181 -0
- xp/services/conbus/conbus_output_service.py +194 -0
- xp/services/conbus/conbus_raw_service.py +122 -0
- xp/services/conbus/conbus_receive_service.py +115 -0
- xp/services/conbus/conbus_scan_service.py +150 -0
- xp/services/conbus/write_config_service.py +194 -0
- xp/services/homekit/__init__.py +1 -0
- xp/services/homekit/homekit_cache_service.py +307 -0
- xp/services/homekit/homekit_conbus_service.py +93 -0
- xp/services/homekit/homekit_config_validator.py +310 -0
- xp/services/homekit/homekit_conson_validator.py +121 -0
- xp/services/homekit/homekit_dimminglight.py +182 -0
- xp/services/homekit/homekit_dimminglight_service.py +148 -0
- xp/services/homekit/homekit_hap_service.py +342 -0
- xp/services/homekit/homekit_lightbulb.py +120 -0
- xp/services/homekit/homekit_lightbulb_service.py +86 -0
- xp/services/homekit/homekit_module_service.py +56 -0
- xp/services/homekit/homekit_outlet.py +168 -0
- xp/services/homekit/homekit_outlet_service.py +121 -0
- xp/services/homekit/homekit_service.py +359 -0
- xp/services/log_file_service.py +309 -0
- xp/services/module_type_service.py +257 -0
- xp/services/protocol/__init__.py +21 -0
- xp/services/protocol/conbus_event_protocol.py +360 -0
- xp/services/protocol/conbus_protocol.py +318 -0
- xp/services/protocol/protocol_factory.py +78 -0
- xp/services/protocol/telegram_protocol.py +264 -0
- xp/services/reverse_proxy_service.py +435 -0
- xp/services/server/__init__.py +1 -0
- xp/services/server/base_server_service.py +366 -0
- xp/services/server/cp20_server_service.py +65 -0
- xp/services/server/device_service_factory.py +94 -0
- xp/services/server/server_service.py +428 -0
- xp/services/server/xp130_server_service.py +67 -0
- xp/services/server/xp20_server_service.py +92 -0
- xp/services/server/xp230_server_service.py +58 -0
- xp/services/server/xp24_server_service.py +245 -0
- xp/services/server/xp33_server_service.py +535 -0
- xp/services/telegram/__init__.py +1 -0
- xp/services/telegram/telegram_blink_service.py +138 -0
- xp/services/telegram/telegram_checksum_service.py +149 -0
- xp/services/telegram/telegram_datapoint_service.py +82 -0
- xp/services/telegram/telegram_discover_service.py +277 -0
- xp/services/telegram/telegram_link_number_service.py +216 -0
- xp/services/telegram/telegram_output_service.py +322 -0
- xp/services/telegram/telegram_service.py +380 -0
- xp/services/telegram/telegram_version_service.py +288 -0
- xp/utils/__init__.py +12 -0
- xp/utils/checksum.py +61 -0
- xp/utils/dependencies.py +531 -0
- xp/utils/event_helper.py +31 -0
- xp/utils/serialization.py +205 -0
- 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
|