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
xp/models/log_entry.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Log entry model for console bus communication logs."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Optional, Union
|
|
6
|
+
|
|
7
|
+
from xp.models.telegram.event_telegram import EventTelegram
|
|
8
|
+
from xp.models.telegram.reply_telegram import ReplyTelegram
|
|
9
|
+
from xp.models.telegram.system_telegram import SystemTelegram
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class LogEntry:
|
|
14
|
+
"""Represents a single entry in a console bus log file.
|
|
15
|
+
|
|
16
|
+
Format: HH:MM:SS,mmm [TX/RX] <telegram>
|
|
17
|
+
Examples: 22:44:20,352 [TX] <S0012345008F27D00AAFN>
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
timestamp: Timestamp of the log entry.
|
|
21
|
+
direction: Direction of telegram ("TX" or "RX").
|
|
22
|
+
raw_telegram: Raw telegram string.
|
|
23
|
+
parsed_telegram: Parsed telegram object if successfully parsed.
|
|
24
|
+
parse_error: Error message if parsing failed.
|
|
25
|
+
line_number: Line number in the log file.
|
|
26
|
+
is_transmitted: True if this is a transmitted telegram.
|
|
27
|
+
is_received: True if this is a received telegram.
|
|
28
|
+
telegram_type: Telegram type (event, system, reply, unknown).
|
|
29
|
+
is_valid_parse: True if the telegram was successfully parsed.
|
|
30
|
+
checksum_validated: Checksum validation status if available.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
timestamp: datetime
|
|
34
|
+
direction: str # "TX" or "RX"
|
|
35
|
+
raw_telegram: str
|
|
36
|
+
parsed_telegram: Optional[Union[EventTelegram, SystemTelegram, ReplyTelegram]] = (
|
|
37
|
+
None
|
|
38
|
+
)
|
|
39
|
+
parse_error: Optional[str] = None
|
|
40
|
+
line_number: int = 0
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def is_transmitted(self) -> bool:
|
|
44
|
+
"""True if this is a transmitted telegram.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
True if direction is TX, False otherwise.
|
|
48
|
+
"""
|
|
49
|
+
return self.direction == "TX"
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def is_received(self) -> bool:
|
|
53
|
+
"""True if this is a received telegram.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
True if direction is RX, False otherwise.
|
|
57
|
+
"""
|
|
58
|
+
return self.direction == "RX"
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def telegram_type(self) -> str:
|
|
62
|
+
"""Get the telegram type (event, system, reply, unknown).
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Telegram type string.
|
|
66
|
+
"""
|
|
67
|
+
if self.parsed_telegram is None:
|
|
68
|
+
return "unknown"
|
|
69
|
+
|
|
70
|
+
return self.parsed_telegram.telegram_type.value.lower()
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def is_valid_parse(self) -> bool:
|
|
74
|
+
"""True if the telegram was successfully parsed.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
True if parsed without errors, False otherwise.
|
|
78
|
+
"""
|
|
79
|
+
return self.parsed_telegram is not None and self.parse_error is None
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def checksum_validated(self) -> Optional[bool]:
|
|
83
|
+
"""Get checksum validation status if available.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Checksum validation status or None if not available.
|
|
87
|
+
"""
|
|
88
|
+
if self.parsed_telegram and hasattr(self.parsed_telegram, "checksum_validated"):
|
|
89
|
+
return self.parsed_telegram.checksum_validated
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
def to_dict(self) -> dict[str, Any]:
|
|
93
|
+
"""Convert to dictionary for JSON serialization.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Dictionary representation of the log entry.
|
|
97
|
+
"""
|
|
98
|
+
result: dict[str, Any] = {
|
|
99
|
+
"line_number": self.line_number,
|
|
100
|
+
"timestamp": self.timestamp.strftime("%H:%M:%S.%f")[
|
|
101
|
+
:-3
|
|
102
|
+
], # HH:MM:SS,mmm format
|
|
103
|
+
"direction": self.direction,
|
|
104
|
+
"raw_telegram": self.raw_telegram,
|
|
105
|
+
"telegram_type": self.telegram_type,
|
|
106
|
+
"is_valid_parse": self.is_valid_parse,
|
|
107
|
+
"parse_error": self.parse_error,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Add parsed telegram data if available
|
|
111
|
+
if self.parsed_telegram:
|
|
112
|
+
result["parsed"] = self.parsed_telegram.to_dict()
|
|
113
|
+
result["checksum_validated"] = self.checksum_validated
|
|
114
|
+
|
|
115
|
+
return result
|
|
116
|
+
|
|
117
|
+
def __str__(self) -> str:
|
|
118
|
+
"""Human-readable string representation.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Formatted string representation of the log entry.
|
|
122
|
+
"""
|
|
123
|
+
timestamp_str = self.timestamp.strftime("%H:%M:%S,%f")[:-3] # HH:MM:SS,mmm
|
|
124
|
+
status = "✓" if self.is_valid_parse else "✗"
|
|
125
|
+
checksum_status = ""
|
|
126
|
+
|
|
127
|
+
if self.checksum_validated is not None:
|
|
128
|
+
checksum_status = f" ({('✓' if self.checksum_validated else '✗')})"
|
|
129
|
+
|
|
130
|
+
return f"[{self.line_number:3d}] {timestamp_str} [{self.direction}] {self.raw_telegram} {status}{checksum_status}"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Protocol models and interfaces."""
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"""Conbus protocol event models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Union
|
|
6
|
+
|
|
7
|
+
from bubus import BaseEvent
|
|
8
|
+
from pydantic import Field
|
|
9
|
+
|
|
10
|
+
from xp.models.homekit.homekit_config import HomekitAccessoryConfig
|
|
11
|
+
from xp.models.homekit.homekit_conson_config import ConsonModuleConfig
|
|
12
|
+
from xp.models.telegram.datapoint_type import DataPointType
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
16
|
+
from xp.services.protocol.conbus_protocol import ConbusProtocol
|
|
17
|
+
from xp.services.protocol.telegram_protocol import TelegramProtocol
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConnectionMadeEvent(BaseEvent):
|
|
21
|
+
"""Event dispatched when TCP connection is established.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
protocol: Reference to the TelegramProtocol instance.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
protocol: TelegramProtocol = Field(
|
|
28
|
+
description="Reference to the TelegramProtocol instance"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ConnectionFailedEvent(BaseEvent):
|
|
33
|
+
"""Event dispatched when TCP connection fails.
|
|
34
|
+
|
|
35
|
+
Attributes:
|
|
36
|
+
reason: Failure reason.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
reason: str = Field(description="Failure reason")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class SendWriteConfigEvent(BaseEvent):
|
|
43
|
+
"""Event for sending write config commands.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
serial_number: Serial number.
|
|
47
|
+
output_number: Output number.
|
|
48
|
+
datapoint_type: Datapoint type.
|
|
49
|
+
value: Set brightness value.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
serial_number: str = Field(description="Serial number")
|
|
53
|
+
output_number: int = Field(description="Output number")
|
|
54
|
+
datapoint_type: DataPointType = Field(description="Datapoint type")
|
|
55
|
+
value: int = Field(description="Set brightness value")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class SendActionEvent(BaseEvent):
|
|
59
|
+
"""Event for sending action commands.
|
|
60
|
+
|
|
61
|
+
Attributes:
|
|
62
|
+
serial_number: Serial number of the light bulb set.
|
|
63
|
+
output_number: Output number of the light bulb set.
|
|
64
|
+
value: Set light bulb On or Off (True/False).
|
|
65
|
+
on_action: On action E00L00I00.
|
|
66
|
+
off_action: On action E00L00I04.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
serial_number: str = Field(description="Serial number of the light bulb set")
|
|
70
|
+
output_number: int = Field(description="Output number of the light bulb set")
|
|
71
|
+
value: bool = Field(description="Set light bulb On or Off (True/False)")
|
|
72
|
+
on_action: str = Field(description="on action")
|
|
73
|
+
off_action: str = Field(description="off action")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class DatapointEvent(BaseEvent):
|
|
77
|
+
"""Base event for datapoint operations.
|
|
78
|
+
|
|
79
|
+
Attributes:
|
|
80
|
+
serial_number: Serial number of the light bulb set.
|
|
81
|
+
datapoint_type: Datapoint type.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
serial_number: str = Field(description="Serial number of the light bulb set")
|
|
85
|
+
datapoint_type: DataPointType = Field(description="Datapoint type")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class OutputStateReceivedEvent(DatapointEvent):
|
|
89
|
+
"""Event when output state is received.
|
|
90
|
+
|
|
91
|
+
Attributes:
|
|
92
|
+
data_value: Data value.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
data_value: str = Field(description="Data value")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class LightLevelReceivedEvent(DatapointEvent):
|
|
99
|
+
"""Event when light level is received.
|
|
100
|
+
|
|
101
|
+
Attributes:
|
|
102
|
+
data_value: Data value.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
data_value: str = Field(description="Data value")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ReadDatapointEvent(DatapointEvent):
|
|
109
|
+
"""Event to read datapoint.
|
|
110
|
+
|
|
111
|
+
Attributes:
|
|
112
|
+
refresh_cache: If True, force cache invalidation and fresh protocol query.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
refresh_cache: bool = Field(
|
|
116
|
+
default=False,
|
|
117
|
+
description="If True, force cache invalidation and fresh protocol query",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class ReadDatapointFromProtocolEvent(DatapointEvent):
|
|
122
|
+
"""Internal event for cache service to forward to protocol when cache misses."""
|
|
123
|
+
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class ModuleEvent(BaseEvent):
|
|
128
|
+
"""Event dispatched when light bulb set is on.
|
|
129
|
+
|
|
130
|
+
Attributes:
|
|
131
|
+
serial_number: Serial number of the light bulb set.
|
|
132
|
+
output_number: Output number of the light bulb set.
|
|
133
|
+
module: ConsonModuleConfig of the light bulb set.
|
|
134
|
+
accessory: HomekitAccessoryConfig of the light bulb set.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
serial_number: str = Field(description="Serial number of the light bulb set")
|
|
138
|
+
output_number: int = Field(description="Output number of the light bulb set")
|
|
139
|
+
module: ConsonModuleConfig = Field(
|
|
140
|
+
description="ConsonModuleConfig of the light bulb set"
|
|
141
|
+
)
|
|
142
|
+
accessory: HomekitAccessoryConfig = Field(
|
|
143
|
+
description="HomekitAccessoryConfig of the light bulb set"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class LightBulbSetOnEvent(ModuleEvent):
|
|
148
|
+
"""Event dispatched when light bulb set is on.
|
|
149
|
+
|
|
150
|
+
Attributes:
|
|
151
|
+
value: On or Off the light bulb set.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
value: bool = Field(description="On or Off the light bulb set")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class LightBulbGetOnEvent(ModuleEvent, BaseEvent[bool]):
|
|
158
|
+
"""Event dispatched when getting light bulb on state."""
|
|
159
|
+
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class OutletSetOnEvent(ModuleEvent):
|
|
164
|
+
"""Event dispatched when outlet set is on.
|
|
165
|
+
|
|
166
|
+
Attributes:
|
|
167
|
+
value: On or Off the light bulb set.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
value: bool = Field(description="On or Off the light bulb set")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class OutletGetOnEvent(ModuleEvent):
|
|
174
|
+
"""Event dispatched when getting outlet on state."""
|
|
175
|
+
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class OutletGetInUseEvent(ModuleEvent):
|
|
180
|
+
"""Event dispatched when getting outlet in-use state."""
|
|
181
|
+
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class OutletSetInUseEvent(ModuleEvent, BaseEvent[bool]):
|
|
186
|
+
"""Event dispatched when outlet set is on.
|
|
187
|
+
|
|
188
|
+
Attributes:
|
|
189
|
+
value: On or Off the light bulb set.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
value: bool = Field(description="On or Off the light bulb set")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class DimmingLightSetOnEvent(ModuleEvent):
|
|
196
|
+
"""Event dispatched when dimming light set is on.
|
|
197
|
+
|
|
198
|
+
Attributes:
|
|
199
|
+
value: On or Off the light bulb set.
|
|
200
|
+
brightness: Brightness of the light bulb set.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
value: bool = Field(description="On or Off the light bulb set")
|
|
204
|
+
brightness: int = Field(description="Brightness of the light bulb set")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class DimmingLightGetOnEvent(ModuleEvent):
|
|
208
|
+
"""Event dispatched when getting dimming light on state."""
|
|
209
|
+
|
|
210
|
+
pass
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class DimmingLightSetBrightnessEvent(ModuleEvent):
|
|
214
|
+
"""Event dispatched when dimming light set is on.
|
|
215
|
+
|
|
216
|
+
Attributes:
|
|
217
|
+
brightness: Level of brightness of the dimming light.
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
brightness: int = Field(description="Level of brightness of the dimming light")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class DimmingLightGetBrightnessEvent(ModuleEvent):
|
|
224
|
+
"""Event dispatched when getting dimming light brightness."""
|
|
225
|
+
|
|
226
|
+
pass
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class ConnectionLostEvent(BaseEvent):
|
|
230
|
+
"""Event dispatched when TCP connection is lost.
|
|
231
|
+
|
|
232
|
+
Attributes:
|
|
233
|
+
reason: Disconnection reason.
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
reason: str = Field(description="Disconnection reason")
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class TelegramEvent(BaseEvent):
|
|
240
|
+
"""Event for telegram operations.
|
|
241
|
+
|
|
242
|
+
Attributes:
|
|
243
|
+
protocol: TelegramProtocol instance.
|
|
244
|
+
frame: Frame <S0123450001F02D12FK>.
|
|
245
|
+
telegram: Telegram S0123450001F02D12FK.
|
|
246
|
+
payload: Payload S0123450001F02D12.
|
|
247
|
+
telegram_type: Telegram type S.
|
|
248
|
+
serial_number: Serial number 0123450001 or empty.
|
|
249
|
+
checksum: Checksum FK.
|
|
250
|
+
checksum_valid: Checksum valid true or false.
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
protocol: Union[TelegramProtocol, ConbusProtocol, ConbusEventProtocol] = Field(
|
|
254
|
+
description="TelegramProtocol instance"
|
|
255
|
+
)
|
|
256
|
+
frame: str = Field(description="Frame <S0123450001F02D12FK>")
|
|
257
|
+
telegram: str = Field(description="Telegram: S0123450001F02D12FK")
|
|
258
|
+
payload: str = Field(description="Payload: S0123450001F02D12")
|
|
259
|
+
telegram_type: str = Field(description="Telegram type: S")
|
|
260
|
+
serial_number: str = Field(description="Serial number: 0123450001 or empty")
|
|
261
|
+
checksum: str = Field(description="Checksum: FK")
|
|
262
|
+
checksum_valid: bool = Field(
|
|
263
|
+
default=True, description="Checksum valid: true, or false"
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class ModuleStateChangedEvent(BaseEvent):
|
|
268
|
+
"""Event dispatched when a module's state changes (from event telegram).
|
|
269
|
+
|
|
270
|
+
Attributes:
|
|
271
|
+
module_type_code: Module type code from event telegram.
|
|
272
|
+
link_number: Link number from event telegram.
|
|
273
|
+
input_number: Input number that triggered the event.
|
|
274
|
+
telegram_event_type: Event type (M=press, B=release).
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
module_type_code: int = Field(description="Module type code from event telegram")
|
|
278
|
+
link_number: int = Field(description="Link number from event telegram")
|
|
279
|
+
input_number: int = Field(description="Input number that triggered the event")
|
|
280
|
+
telegram_event_type: str = Field(description="Event type (M=press, B=release)")
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class EventTelegramReceivedEvent(TelegramEvent):
|
|
284
|
+
"""Event telegram received."""
|
|
285
|
+
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class ModuleDiscoveredEvent(TelegramEvent):
|
|
290
|
+
"""Event dispatched when module is discovered."""
|
|
291
|
+
|
|
292
|
+
pass
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class TelegramReceivedEvent(TelegramEvent):
|
|
296
|
+
"""Event dispatched when a telegram frame is received."""
|
|
297
|
+
|
|
298
|
+
pass
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class InvalidTelegramReceivedEvent(BaseEvent):
|
|
302
|
+
"""Event dispatched when an invalid telegram frame is received.
|
|
303
|
+
|
|
304
|
+
Attributes:
|
|
305
|
+
protocol: TelegramProtocol instance.
|
|
306
|
+
frame: Frame <S0123450001F02D12FK>.
|
|
307
|
+
error: Error with the received telegram.
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
protocol: TelegramProtocol = Field(description="TelegramProtocol instance")
|
|
311
|
+
frame: str = Field(description="Frame <S0123450001F02D12FK>")
|
|
312
|
+
error: str = Field(description="Error with the received telegram")
|
xp/models/response.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Response model for structured service responses.
|
|
2
|
+
|
|
3
|
+
This module provides the Response class used throughout the application
|
|
4
|
+
for consistent service response formatting.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Any, Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Response:
|
|
12
|
+
"""Standard response model for service operations.
|
|
13
|
+
|
|
14
|
+
Provides consistent structure for all service responses including
|
|
15
|
+
success status, data payload, error messages, and timestamp.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, success: bool, data: Any, error: Optional[str] = None):
|
|
19
|
+
"""Initialize response.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
success: Whether the operation was successful
|
|
23
|
+
data: Response data payload
|
|
24
|
+
error: Error message if operation failed
|
|
25
|
+
"""
|
|
26
|
+
self.success = success
|
|
27
|
+
self.data = data
|
|
28
|
+
self.error = error
|
|
29
|
+
self.timestamp = datetime.now()
|
|
30
|
+
|
|
31
|
+
def to_dict(self) -> dict:
|
|
32
|
+
"""Convert response to dictionary for JSON serialization.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Dictionary representation of the response
|
|
36
|
+
"""
|
|
37
|
+
return {
|
|
38
|
+
"success": self.success,
|
|
39
|
+
"data": self.data,
|
|
40
|
+
"error": self.error,
|
|
41
|
+
"timestamp": self.timestamp.isoformat(),
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Telegram models for console bus communication."""
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Action type enumeration for XP24 telegrams."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ActionType(Enum):
|
|
8
|
+
"""Action types for XP24 telegrams.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
OFF_PRESS: Make action (activate relay).
|
|
12
|
+
ON_RELEASE: Break action (deactivate relay).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
OFF_PRESS = "AA" # Make action (activate relay)
|
|
16
|
+
ON_RELEASE = "AB" # Break action (deactivate relay)
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def from_code(cls, code: str) -> Optional["ActionType"]:
|
|
20
|
+
"""Get ActionType from code string.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
code: Action code string.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
ActionType instance if found, None otherwise.
|
|
27
|
+
"""
|
|
28
|
+
for action in cls:
|
|
29
|
+
if action.value == code:
|
|
30
|
+
return action
|
|
31
|
+
return None
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Datapoint type enumeration for system telegrams."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DataPointType(str, Enum):
|
|
8
|
+
"""Data point types for system telegrams.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
MODULE_TYPE: Module type (XP24, XP33, etc).
|
|
12
|
+
HW_VERSION: Hardware version information.
|
|
13
|
+
SW_VERSION: Software version information.
|
|
14
|
+
SERIAL_NUMBER: Serial number.
|
|
15
|
+
LINK_NUMBER: Link number.
|
|
16
|
+
MODULE_NUMBER: Module number.
|
|
17
|
+
SYSTEM_TYPE: System type.
|
|
18
|
+
MODULE_TYPE_CODE: Module type code.
|
|
19
|
+
MODULE_TYPE_ID: Module type ID.
|
|
20
|
+
MODULE_STATE: Module state.
|
|
21
|
+
MODULE_ERROR_CODE: Status query data point.
|
|
22
|
+
MODULE_INPUT_STATE: Module input state.
|
|
23
|
+
MODULE_OUTPUT_STATE: Channel states (XP33).
|
|
24
|
+
MODULE_FW_CRC: Module firmware CRC.
|
|
25
|
+
MODULE_ACTION_TABLE_CRC: Module action table CRC.
|
|
26
|
+
MODULE_LIGHT_LEVEL: Module light level.
|
|
27
|
+
MODULE_OPERATING_HOURS: Module operating hours.
|
|
28
|
+
MODULE_ENERGY_LEVEL: Current data point.
|
|
29
|
+
TEMPERATURE: Temperature data point.
|
|
30
|
+
SW_TOP_VERSION: Software top version.
|
|
31
|
+
VOLTAGE: Voltage data point.
|
|
32
|
+
AUTO_REPORT_STATUS: Auto report status.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
MODULE_TYPE = "00" # Module type (XP24, XP33, ..)
|
|
36
|
+
HW_VERSION = "01" # Hardware version information
|
|
37
|
+
SW_VERSION = "02" # Software version information
|
|
38
|
+
SERIAL_NUMBER = "03" # Serial number
|
|
39
|
+
LINK_NUMBER = "04" # Link number
|
|
40
|
+
MODULE_NUMBER = "05" # Module number
|
|
41
|
+
SYSTEM_TYPE = "06" # System type
|
|
42
|
+
MODULE_TYPE_CODE = "07" # Module type code
|
|
43
|
+
MODULE_TYPE_ID = "08" # Module type id
|
|
44
|
+
MODULE_STATE = "09" # Module state
|
|
45
|
+
MODULE_ERROR_CODE = "10" # Status query data point
|
|
46
|
+
MODULE_INPUT_STATE = "11" # Module input state
|
|
47
|
+
MODULE_OUTPUT_STATE = "12" # Channel states (XP33)
|
|
48
|
+
MODULE_FW_CRC = "13" # Module Firmware CRC
|
|
49
|
+
MODULE_ACTION_TABLE_CRC = "14" # Module Action Table CRC
|
|
50
|
+
|
|
51
|
+
# XP24 00:000[%],01:000[%],02:000[%],03:000[%]
|
|
52
|
+
# XP33 00:000[%],01:000[%],02:000[%]
|
|
53
|
+
MODULE_LIGHT_LEVEL = "15" # Module Light Level
|
|
54
|
+
|
|
55
|
+
# XP24 00:000[H],01:000[H],02:000[H],03:000[H]
|
|
56
|
+
MODULE_OPERATING_HOURS = "16" # Module Operating Hours
|
|
57
|
+
|
|
58
|
+
# XP24 00:00000[NA],01:00000[NA],02:00000[NA],03:00000[NA]
|
|
59
|
+
MODULE_ENERGY_LEVEL = "17" # Current data point
|
|
60
|
+
|
|
61
|
+
# XP24 +34,0C
|
|
62
|
+
# XP33 -20,0C
|
|
63
|
+
TEMPERATURE = "18" # Temperature data point
|
|
64
|
+
|
|
65
|
+
SW_TOP_VERSION = "19" # Software Top Version
|
|
66
|
+
VOLTAGE = "20" # VOLTAGE data point
|
|
67
|
+
AUTO_REPORT_STATUS = "21" # Auto Report Status
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def from_code(cls, code: str) -> Optional["DataPointType"]:
|
|
71
|
+
"""Get DataPointType from code string.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
code: Datapoint type code string.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
DataPointType instance if found, None otherwise.
|
|
78
|
+
"""
|
|
79
|
+
for dp_type in cls:
|
|
80
|
+
if dp_type.value == code:
|
|
81
|
+
return dp_type
|
|
82
|
+
return None
|