conson-xp 1.3.0__py3-none-any.whl → 1.5.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.3.0.dist-info → conson_xp-1.5.0.dist-info}/METADATA +1 -1
- {conson_xp-1.3.0.dist-info → conson_xp-1.5.0.dist-info}/RECORD +19 -19
- xp/__init__.py +1 -1
- xp/models/conbus/conbus_discover.py +19 -3
- xp/models/telegram/system_telegram.py +4 -4
- xp/services/conbus/conbus_discover_service.py +120 -2
- xp/services/conbus/conbus_scan_service.py +1 -1
- xp/services/protocol/telegram_protocol.py +4 -4
- xp/services/server/base_server_service.py +38 -4
- xp/services/server/cp20_server_service.py +2 -1
- xp/services/server/server_service.py +162 -10
- xp/services/server/xp130_server_service.py +2 -1
- xp/services/server/xp20_server_service.py +2 -1
- xp/services/server/xp230_server_service.py +2 -1
- xp/services/server/xp24_server_service.py +123 -50
- xp/services/server/xp33_server_service.py +338 -20
- {conson_xp-1.3.0.dist-info → conson_xp-1.5.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.3.0.dist-info → conson_xp-1.5.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.3.0.dist-info → conson_xp-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
conson_xp-1.
|
|
2
|
-
conson_xp-1.
|
|
3
|
-
conson_xp-1.
|
|
4
|
-
conson_xp-1.
|
|
5
|
-
xp/__init__.py,sha256=
|
|
1
|
+
conson_xp-1.5.0.dist-info/METADATA,sha256=to2xeqnuavfCJCA0S4VC3trJaxL02i7c-4RQuU-1qjE,9274
|
|
2
|
+
conson_xp-1.5.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
conson_xp-1.5.0.dist-info/entry_points.txt,sha256=1OcdIcDM1hz3ljCXgybaPUh1IOFEwkaTgLIW9u9zGeg,50
|
|
4
|
+
conson_xp-1.5.0.dist-info/licenses/LICENSE,sha256=rxj6woMM-r3YCyGq_UHFtbh7kHTAJgrccH6O-33IDE4,1419
|
|
5
|
+
xp/__init__.py,sha256=UqV_T6LhENt9Tn3-NIiQjKGRaHZSmX5DPf-StL2UAO0,180
|
|
6
6
|
xp/cli/__init__.py,sha256=QjnKB1KaI2aIyKlzrnvCwfbBuUj8HNgwNMvNJVQofbI,81
|
|
7
7
|
xp/cli/__main__.py,sha256=l2iKwMdat5rTGd3JWs-uGksnYYDDffp_Npz05QdKEeU,117
|
|
8
8
|
xp/cli/commands/__init__.py,sha256=02CbZoKmNX-fn5etX4Hdgg2lUt1MsLFPYx2VkXZyFJ8,4394
|
|
@@ -64,7 +64,7 @@ xp/models/conbus/conbus_client_config.py,sha256=fWPmHM-OVUzSASKq667JzP7e9_Qp9ZUy
|
|
|
64
64
|
xp/models/conbus/conbus_connection_status.py,sha256=iGbmtBaAMwV6UD7XG3H3tnB0fl2MR8rJhpjrLH2KjsE,1097
|
|
65
65
|
xp/models/conbus/conbus_custom.py,sha256=8H2sPR6_LIlksuOvL7-8bPkzAJLR0rpYiiwfYYFVjEo,1965
|
|
66
66
|
xp/models/conbus/conbus_datapoint.py,sha256=4ncR-vB2lRzRBAA30rYn8eguyTxsZoOKrrXtjGmPpWg,3396
|
|
67
|
-
xp/models/conbus/conbus_discover.py,sha256=
|
|
67
|
+
xp/models/conbus/conbus_discover.py,sha256=nxxUEKfEsH1kd0BF8ovMs7zLujRhrq1oL9ZJtysPr5o,2238
|
|
68
68
|
xp/models/conbus/conbus_lightlevel.py,sha256=GQGhzrCBEJROosNHInXIzBy6MD2AskEIMoFEGgZ60-0,1695
|
|
69
69
|
xp/models/conbus/conbus_linknumber.py,sha256=uFzKzfB06oIzZEKCb5X2JEI80JjMPFuYglsT1W1k8j4,1815
|
|
70
70
|
xp/models/conbus/conbus_output.py,sha256=q7QKsD_CWT7YOk-V3otKWD1VM7qThrSLIUOunntMrMc,1953
|
|
@@ -91,7 +91,7 @@ xp/models/telegram/module_type_code.py,sha256=bg8Zi58yKs5DDnEF0bGnZ9vvpqzmIZzd1k
|
|
|
91
91
|
xp/models/telegram/output_telegram.py,sha256=vTSdeAGk7va89pZ8-oh0cna98N3T6if-6UcrstWsN6s,3473
|
|
92
92
|
xp/models/telegram/reply_telegram.py,sha256=oqNwDvaOhFTPuXL0fP9Ca3rbcKepDhRz9kIneKCk6n0,10376
|
|
93
93
|
xp/models/telegram/system_function.py,sha256=Iv9u4sYCPnMcvlpbBrNNxu0NpUOFsi5kPgT2vrelbVw,3266
|
|
94
|
-
xp/models/telegram/system_telegram.py,sha256=
|
|
94
|
+
xp/models/telegram/system_telegram.py,sha256=9FNQ4Mf47mRK7wGrTg2GzziVsrEWCE5ZkZp5kA7K3w0,3218
|
|
95
95
|
xp/models/telegram/telegram.py,sha256=IJUxHX6ftLcET9C1pjvLhUO5Db5JO6W7rUItzdEW30I,842
|
|
96
96
|
xp/models/telegram/telegram_type.py,sha256=GhqKP63oNMyh2tIvCPcsC5RFp4s4JjhmEqCLCC-8XMk,423
|
|
97
97
|
xp/models/telegram/timeparam_type.py,sha256=Ar8xvSfPmOAgR2g2Je0FgvP01SL7bPvZn5_HrVDpmJM,1137
|
|
@@ -110,11 +110,11 @@ xp/services/conbus/conbus_blink_service.py,sha256=x9uM-sLnIEV8wSNsvJgo08E042g-Hh
|
|
|
110
110
|
xp/services/conbus/conbus_custom_service.py,sha256=4aneYdPObiZOGxPFYg5Wr70cl_xFxlQIdJBPQSa0enI,5826
|
|
111
111
|
xp/services/conbus/conbus_datapoint_queryall_service.py,sha256=p9R02cVimhdJILHQ6BoeZj8Hog4oRpqBnMo3t4R8ecY,6816
|
|
112
112
|
xp/services/conbus/conbus_datapoint_service.py,sha256=NsqRQfNsZ4_Pbe7kcMQpUqfhVPH7H148JDWH49ExQ1E,6392
|
|
113
|
-
xp/services/conbus/conbus_discover_service.py,sha256=
|
|
113
|
+
xp/services/conbus/conbus_discover_service.py,sha256=lH6I8YcN7Beo_f-M8XkNZ_5UuNB-x2R9U5xJNTK-QXE,10110
|
|
114
114
|
xp/services/conbus/conbus_output_service.py,sha256=mHFOAPx2zo0TStZ3pokp6v94AQjIamcwZDeg5YH_-eo,7240
|
|
115
115
|
xp/services/conbus/conbus_raw_service.py,sha256=4yZLLTIAOxpgByUTWZXw1ihGa6Xtl98ckj9T7VfprDI,4335
|
|
116
116
|
xp/services/conbus/conbus_receive_service.py,sha256=frXrS0OyKKvYYQTWdma21Kd0BKw5aSuHn3ZXTTqOaj0,3953
|
|
117
|
-
xp/services/conbus/conbus_scan_service.py,sha256=
|
|
117
|
+
xp/services/conbus/conbus_scan_service.py,sha256=tHJ5qaxcNXxAZb2D2F1v6IrzydfxjJOYllM6Txt1eBE,5176
|
|
118
118
|
xp/services/conbus/write_config_service.py,sha256=qe5TwQdVnMCcJ4lCeZLADdUeoDpbEaV3XoZ19a3F_qk,7128
|
|
119
119
|
xp/services/homekit/__init__.py,sha256=xAMKmln_AmEFdOOJGKWYi96seRlKDQpKx3-hm7XbdIo,36
|
|
120
120
|
xp/services/homekit/homekit_cache_service.py,sha256=NdijyH5_iyhsTHBb-OyT8Y2xnNDj8F5MP8neoVQ26hY,11010
|
|
@@ -135,17 +135,17 @@ xp/services/module_type_service.py,sha256=xWhr1EAZMykL5uNWHWdpa5T8yNruGKH43XRTOS
|
|
|
135
135
|
xp/services/protocol/__init__.py,sha256=WuYn2iEcvsOIXnn5HCrU9kD3PjuMX1sIh0ljKISDoJw,720
|
|
136
136
|
xp/services/protocol/conbus_protocol.py,sha256=G39YPMpwhvvhFPYrzNxx6y2Is6DSP2UyCLm4T7RLPVc,10404
|
|
137
137
|
xp/services/protocol/protocol_factory.py,sha256=PmjN9AtW9sxNo3voqUiNgQA-pTvX1RW4XXFlHKfFr5Q,2470
|
|
138
|
-
xp/services/protocol/telegram_protocol.py,sha256=
|
|
138
|
+
xp/services/protocol/telegram_protocol.py,sha256=Ki5DrXsKxiaqLcdP9WWUuhUI7cPu2DfwyZkh-Gv9Lb8,9496
|
|
139
139
|
xp/services/reverse_proxy_service.py,sha256=BUOlcLlTU-R5iuC_96rasug21xo19wK9_4fMQXxc0QM,15061
|
|
140
140
|
xp/services/server/__init__.py,sha256=QEcCj-jK0goAukJCe15TKYFQfSAzWsduPT_wW0HxZU8,48
|
|
141
|
-
xp/services/server/base_server_service.py,sha256=
|
|
142
|
-
xp/services/server/cp20_server_service.py,sha256=
|
|
143
|
-
xp/services/server/server_service.py,sha256=
|
|
144
|
-
xp/services/server/xp130_server_service.py,sha256=
|
|
145
|
-
xp/services/server/xp20_server_service.py,sha256=
|
|
146
|
-
xp/services/server/xp230_server_service.py,sha256=
|
|
147
|
-
xp/services/server/xp24_server_service.py,sha256=
|
|
148
|
-
xp/services/server/xp33_server_service.py,sha256=
|
|
141
|
+
xp/services/server/base_server_service.py,sha256=AkeLWMOTasIIiBBGM_uTCXJ31yG1ciF98b9xKyq8VSs,9997
|
|
142
|
+
xp/services/server/cp20_server_service.py,sha256=PkdkORQ-aIHtQb-wuAgkRxKcdpNWpvys_p1sXJg0yoI,1679
|
|
143
|
+
xp/services/server/server_service.py,sha256=pRE_hdAlQfQBj10Y15IiBOz2wQL9LghoigZvcywbnKI,17899
|
|
144
|
+
xp/services/server/xp130_server_service.py,sha256=mD3vE-JDR9s_o7zjVCu4cibM8hUbwJ1oxgb_JwtQ2WU,1819
|
|
145
|
+
xp/services/server/xp20_server_service.py,sha256=s9RrqhCZ8xtgEzc8GXTlG81b4LtZLCFy79DhzBLTPjA,1428
|
|
146
|
+
xp/services/server/xp230_server_service.py,sha256=c3kzkA-fEOglrjLISQLbyk_rUdKzwN20hc0qtF9MEAQ,1443
|
|
147
|
+
xp/services/server/xp24_server_service.py,sha256=_QMHe0UgxVlyB0DZmP1KPdjheT1qE8V8-EW55FM58DY,6606
|
|
148
|
+
xp/services/server/xp33_server_service.py,sha256=BhZaphtb1hgedTmB1bTuLlWTIZp3AOuec2gffDvKmRM,18329
|
|
149
149
|
xp/services/telegram/__init__.py,sha256=kv0JgMg13Fp18WgGQpalNRAWwiWbrz18X4kZAP9xpSQ,48
|
|
150
150
|
xp/services/telegram/telegram_blink_service.py,sha256=Xctc9mCSZiiW1YTh8cA-4jlc8fTioS5OxT6ymhSqiYI,4487
|
|
151
151
|
xp/services/telegram/telegram_checksum_service.py,sha256=rp_C5PlraOOIyqZDp9XjBBNZLUeBLdQNNHVpN6D-1v8,4729
|
|
@@ -161,4 +161,4 @@ xp/utils/dependencies.py,sha256=4G7r0m1HY9UV4E0zLS8L-axcNiX2mM-N6OOAU8dVHVM,1774
|
|
|
161
161
|
xp/utils/event_helper.py,sha256=W-A_xmoXlpWZBbJH6qdaN50o3-XrwFsDgvAGMJDiAgo,1001
|
|
162
162
|
xp/utils/serialization.py,sha256=RWHHk86feaB4ZP7rjE4qOWK0900yg2joUBDkP76gfOY,4618
|
|
163
163
|
xp/utils/time_utils.py,sha256=dEyViDlAG9GWU-J3D_YVa-sGma6yiyyMTgN4h2x3PY4,3781
|
|
164
|
-
conson_xp-1.
|
|
164
|
+
conson_xp-1.5.0.dist-info/RECORD,,
|
xp/__init__.py
CHANGED
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from datetime import datetime
|
|
5
|
-
from typing import Any, Dict, Optional
|
|
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]
|
|
6
22
|
|
|
7
23
|
|
|
8
24
|
@dataclass
|
|
@@ -13,7 +29,7 @@ class ConbusDiscoverResponse:
|
|
|
13
29
|
success: Whether the operation was successful.
|
|
14
30
|
sent_telegram: Telegram sent to discover devices.
|
|
15
31
|
received_telegrams: List of telegrams received.
|
|
16
|
-
discovered_devices: List of discovered
|
|
32
|
+
discovered_devices: List of discovered devices with their module types.
|
|
17
33
|
error: Error message if operation failed.
|
|
18
34
|
timestamp: Timestamp of the response.
|
|
19
35
|
"""
|
|
@@ -21,7 +37,7 @@ class ConbusDiscoverResponse:
|
|
|
21
37
|
success: bool
|
|
22
38
|
sent_telegram: Optional[str] = None
|
|
23
39
|
received_telegrams: Optional[list[str]] = None
|
|
24
|
-
discovered_devices: Optional[list[
|
|
40
|
+
discovered_devices: Optional[list[DiscoveredDevice]] = None
|
|
25
41
|
error: Optional[str] = None
|
|
26
42
|
timestamp: Optional[datetime] = None
|
|
27
43
|
|
|
@@ -22,10 +22,10 @@ class SystemTelegram(Telegram):
|
|
|
22
22
|
Examples: <S0020012521F02D18FN>
|
|
23
23
|
|
|
24
24
|
Attributes:
|
|
25
|
-
serial_number: Serial number of the device
|
|
26
|
-
system_function: System function code.
|
|
27
|
-
data: Data payload
|
|
28
|
-
datapoint_type: Type of datapoint.
|
|
25
|
+
serial_number: Serial number of the device (0020012521)
|
|
26
|
+
system_function: System function code (02).
|
|
27
|
+
data: Data payload (18)
|
|
28
|
+
datapoint_type: Type of datapoint (18).
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
serial_number: str = ""
|
|
@@ -10,7 +10,10 @@ from typing import Callable, Optional
|
|
|
10
10
|
from twisted.internet.posixbase import PosixReactorBase
|
|
11
11
|
|
|
12
12
|
from xp.models import ConbusClientConfig, ConbusDiscoverResponse
|
|
13
|
+
from xp.models.conbus.conbus_discover import DiscoveredDevice
|
|
13
14
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
15
|
+
from xp.models.telegram.datapoint_type import DataPointType
|
|
16
|
+
from xp.models.telegram.module_type_code import MODULE_TYPE_REGISTRY
|
|
14
17
|
from xp.models.telegram.system_function import SystemFunction
|
|
15
18
|
from xp.models.telegram.telegram_type import TelegramType
|
|
16
19
|
from xp.services.protocol.conbus_protocol import ConbusProtocol
|
|
@@ -73,6 +76,7 @@ class ConbusDiscoverService(ConbusProtocol):
|
|
|
73
76
|
self.discovered_device_result.received_telegrams = []
|
|
74
77
|
self.discovered_device_result.received_telegrams.append(telegram_received.frame)
|
|
75
78
|
|
|
79
|
+
# Check for discovery response
|
|
76
80
|
if (
|
|
77
81
|
telegram_received.checksum_valid
|
|
78
82
|
and telegram_received.telegram_type == TelegramType.REPLY.value
|
|
@@ -80,8 +84,30 @@ class ConbusDiscoverService(ConbusProtocol):
|
|
|
80
84
|
and len(telegram_received.payload) == 15
|
|
81
85
|
):
|
|
82
86
|
self.discovered_device(telegram_received.serial_number)
|
|
87
|
+
|
|
88
|
+
# Check for module type response (F02D07)
|
|
89
|
+
elif (
|
|
90
|
+
telegram_received.checksum_valid
|
|
91
|
+
and telegram_received.telegram_type == TelegramType.REPLY.value
|
|
92
|
+
and telegram_received.payload[11:17] == "F02D07"
|
|
93
|
+
and len(telegram_received.payload) >= 19
|
|
94
|
+
):
|
|
95
|
+
self.handle_module_type_code_response(
|
|
96
|
+
telegram_received.serial_number, telegram_received.payload[17:19]
|
|
97
|
+
)
|
|
98
|
+
# Check for module type response (F02D00)
|
|
99
|
+
elif (
|
|
100
|
+
telegram_received.checksum_valid
|
|
101
|
+
and telegram_received.telegram_type == TelegramType.REPLY.value
|
|
102
|
+
and telegram_received.payload[11:17] == "F02D00"
|
|
103
|
+
and len(telegram_received.payload) >= 19
|
|
104
|
+
):
|
|
105
|
+
self.handle_module_type_response(
|
|
106
|
+
telegram_received.serial_number, telegram_received.payload[17:19]
|
|
107
|
+
)
|
|
108
|
+
|
|
83
109
|
else:
|
|
84
|
-
self.logger.debug("Not a discover response")
|
|
110
|
+
self.logger.debug("Not a discover or module type response")
|
|
85
111
|
|
|
86
112
|
def discovered_device(self, serial_number: str) -> None:
|
|
87
113
|
"""Handle discovered device event.
|
|
@@ -92,10 +118,102 @@ class ConbusDiscoverService(ConbusProtocol):
|
|
|
92
118
|
self.logger.info("discovered_device: %s", serial_number)
|
|
93
119
|
if not self.discovered_device_result.discovered_devices:
|
|
94
120
|
self.discovered_device_result.discovered_devices = []
|
|
95
|
-
|
|
121
|
+
|
|
122
|
+
# Add device with module_type as None initially
|
|
123
|
+
device: DiscoveredDevice = {
|
|
124
|
+
"serial_number": serial_number,
|
|
125
|
+
"module_type": None,
|
|
126
|
+
"module_type_code": None,
|
|
127
|
+
"module_type_name": None,
|
|
128
|
+
}
|
|
129
|
+
self.discovered_device_result.discovered_devices.append(device)
|
|
130
|
+
|
|
131
|
+
# Send READ_DATAPOINT telegram to query module type
|
|
132
|
+
self.logger.debug(f"Sending module type query for {serial_number}")
|
|
133
|
+
self.send_telegram(
|
|
134
|
+
telegram_type=TelegramType.SYSTEM,
|
|
135
|
+
serial_number=serial_number,
|
|
136
|
+
system_function=SystemFunction.READ_DATAPOINT,
|
|
137
|
+
data_value=DataPointType.MODULE_TYPE.value,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
self.send_telegram(
|
|
141
|
+
telegram_type=TelegramType.SYSTEM,
|
|
142
|
+
serial_number=serial_number,
|
|
143
|
+
system_function=SystemFunction.READ_DATAPOINT,
|
|
144
|
+
data_value=DataPointType.MODULE_TYPE_CODE.value,
|
|
145
|
+
)
|
|
146
|
+
|
|
96
147
|
if self.progress_callback:
|
|
97
148
|
self.progress_callback(serial_number)
|
|
98
149
|
|
|
150
|
+
def handle_module_type_code_response(
|
|
151
|
+
self, serial_number: str, module_type_code: str
|
|
152
|
+
) -> None:
|
|
153
|
+
"""Handle module type code response and update discovered device.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
serial_number: Serial number of the device.
|
|
157
|
+
module_type_code: Module type code from telegram (e.g., "07", "24").
|
|
158
|
+
"""
|
|
159
|
+
self.logger.info(
|
|
160
|
+
f"Received module type code {module_type_code} for {serial_number}"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Convert module type code to name
|
|
164
|
+
code = 0
|
|
165
|
+
try:
|
|
166
|
+
# The telegram format uses decimal values represented as strings
|
|
167
|
+
code = int(module_type_code)
|
|
168
|
+
module_info = MODULE_TYPE_REGISTRY.get(code)
|
|
169
|
+
|
|
170
|
+
if module_info:
|
|
171
|
+
module_type_name = module_info["name"]
|
|
172
|
+
self.logger.debug(
|
|
173
|
+
f"Module type code {module_type_code} ({code}) = {module_type_name}"
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
module_type_name = f"UNKNOWN_{module_type_code}"
|
|
177
|
+
self.logger.warning(
|
|
178
|
+
f"Unknown module type code {module_type_code} ({code})"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
except ValueError:
|
|
182
|
+
self.logger.error(
|
|
183
|
+
f"Invalid module type code format: {module_type_code} for {serial_number}"
|
|
184
|
+
)
|
|
185
|
+
module_type_name = f"INVALID_{module_type_code}"
|
|
186
|
+
|
|
187
|
+
# Find and update the device in discovered_devices
|
|
188
|
+
if self.discovered_device_result.discovered_devices:
|
|
189
|
+
for device in self.discovered_device_result.discovered_devices:
|
|
190
|
+
if device["serial_number"] == serial_number:
|
|
191
|
+
device["module_type_code"] = code
|
|
192
|
+
device["module_type_name"] = module_type_name
|
|
193
|
+
self.logger.debug(
|
|
194
|
+
f"Updated device {serial_number} with module_type {module_type_name}"
|
|
195
|
+
)
|
|
196
|
+
break
|
|
197
|
+
|
|
198
|
+
def handle_module_type_response(self, serial_number: str, module_type: str) -> None:
|
|
199
|
+
"""Handle module type response and update discovered device.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
serial_number: Serial number of the device.
|
|
203
|
+
module_type: Module type code from telegram (e.g., "XP33", "XP24").
|
|
204
|
+
"""
|
|
205
|
+
self.logger.info(f"Received module type {module_type} for {serial_number}")
|
|
206
|
+
|
|
207
|
+
# Find and update the device in discovered_devices
|
|
208
|
+
if self.discovered_device_result.discovered_devices:
|
|
209
|
+
for device in self.discovered_device_result.discovered_devices:
|
|
210
|
+
if device["serial_number"] == serial_number:
|
|
211
|
+
device["module_type"] = module_type
|
|
212
|
+
self.logger.debug(
|
|
213
|
+
f"Updated device {serial_number} with module_type {module_type}"
|
|
214
|
+
)
|
|
215
|
+
break
|
|
216
|
+
|
|
99
217
|
def timeout(self) -> bool:
|
|
100
218
|
"""Handle timeout event to stop discovery.
|
|
101
219
|
|
|
@@ -128,7 +128,7 @@ class ConbusScanService(ConbusProtocol):
|
|
|
128
128
|
function_code: str,
|
|
129
129
|
progress_callback: Callable[[str], None],
|
|
130
130
|
finish_callback: Callable[[ConbusResponse], None],
|
|
131
|
-
timeout_seconds:
|
|
131
|
+
timeout_seconds: float = 0.25,
|
|
132
132
|
) -> None:
|
|
133
133
|
"""Scan a module for all datapoints by function code.
|
|
134
134
|
|
|
@@ -124,7 +124,7 @@ class TelegramProtocol(protocol.Protocol):
|
|
|
124
124
|
payload = telegram[:-2] # S0123450001F02D12
|
|
125
125
|
checksum = telegram[-2:].decode() # FK
|
|
126
126
|
serial_number = (
|
|
127
|
-
telegram[1:11] if telegram_type in "S" else b""
|
|
127
|
+
telegram[1:11] if telegram_type in ("S", "R") else b""
|
|
128
128
|
) # 0123450001
|
|
129
129
|
calculated_checksum = calculate_checksum(payload.decode(encoding="latin-1"))
|
|
130
130
|
|
|
@@ -151,9 +151,9 @@ class TelegramProtocol(protocol.Protocol):
|
|
|
151
151
|
await self.event_bus.dispatch(
|
|
152
152
|
TelegramReceivedEvent(
|
|
153
153
|
protocol=self,
|
|
154
|
-
frame=frame.decode(),
|
|
155
|
-
telegram=telegram.decode(),
|
|
156
|
-
payload=payload.decode(),
|
|
154
|
+
frame=frame.decode("latin-1"),
|
|
155
|
+
telegram=telegram.decode("latin-1"),
|
|
156
|
+
payload=payload.decode("latin-1"),
|
|
157
157
|
telegram_type=telegram_type,
|
|
158
158
|
serial_number=serial_number,
|
|
159
159
|
checksum=checksum,
|
|
@@ -5,9 +5,11 @@ containing common functionality like module type response generation.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
+
import threading
|
|
8
9
|
from abc import ABC
|
|
9
10
|
from typing import Optional
|
|
10
11
|
|
|
12
|
+
from xp.models import ModuleTypeCode
|
|
11
13
|
from xp.models.telegram.datapoint_type import DataPointType
|
|
12
14
|
from xp.models.telegram.system_function import SystemFunction
|
|
13
15
|
from xp.models.telegram.system_telegram import SystemTelegram
|
|
@@ -33,7 +35,7 @@ class BaseServerService(ABC):
|
|
|
33
35
|
|
|
34
36
|
# Must be set by subclasses
|
|
35
37
|
self.device_type: str = ""
|
|
36
|
-
self.module_type_code:
|
|
38
|
+
self.module_type_code: ModuleTypeCode = ModuleTypeCode.NOMOD
|
|
37
39
|
self.hardware_version: str = ""
|
|
38
40
|
self.software_version: str = ""
|
|
39
41
|
self.device_status: str = "OK"
|
|
@@ -41,6 +43,9 @@ class BaseServerService(ABC):
|
|
|
41
43
|
self.temperature: str = "+23,5§C"
|
|
42
44
|
self.voltage: str = "+12,5§V"
|
|
43
45
|
|
|
46
|
+
self.telegram_buffer: list[str] = []
|
|
47
|
+
self.telegram_buffer_lock = threading.Lock() # Lock for socket set
|
|
48
|
+
|
|
44
49
|
def generate_datapoint_type_response(
|
|
45
50
|
self, datapoint_type: DataPointType
|
|
46
51
|
) -> Optional[str]:
|
|
@@ -54,11 +59,11 @@ class BaseServerService(ABC):
|
|
|
54
59
|
"""
|
|
55
60
|
datapoint_values = {
|
|
56
61
|
DataPointType.TEMPERATURE: self.temperature,
|
|
57
|
-
DataPointType.MODULE_TYPE_CODE: f"{self.module_type_code:
|
|
62
|
+
DataPointType.MODULE_TYPE_CODE: f"{self.module_type_code.value:02}",
|
|
58
63
|
DataPointType.SW_VERSION: self.software_version,
|
|
59
64
|
DataPointType.MODULE_STATE: self.device_status,
|
|
60
65
|
DataPointType.MODULE_TYPE: self.device_type,
|
|
61
|
-
DataPointType.LINK_NUMBER: f"{self.link_number:
|
|
66
|
+
DataPointType.LINK_NUMBER: f"{self.link_number:02}",
|
|
62
67
|
DataPointType.VOLTAGE: self.voltage,
|
|
63
68
|
DataPointType.HW_VERSION: self.hardware_version,
|
|
64
69
|
DataPointType.MODULE_ERROR_CODE: "00",
|
|
@@ -187,11 +192,15 @@ class BaseServerService(ABC):
|
|
|
187
192
|
self.logger.debug(
|
|
188
193
|
f"_handle_return_data_request {self.device_type} request: {request}"
|
|
189
194
|
)
|
|
195
|
+
module_specific = self._handle_device_specific_data_request(request)
|
|
196
|
+
if module_specific:
|
|
197
|
+
return module_specific
|
|
198
|
+
|
|
190
199
|
if request.datapoint_type:
|
|
191
200
|
return self.generate_datapoint_type_response(request.datapoint_type)
|
|
192
201
|
|
|
193
202
|
# Allow device-specific handlers
|
|
194
|
-
return
|
|
203
|
+
return None
|
|
195
204
|
|
|
196
205
|
def _handle_device_specific_data_request(
|
|
197
206
|
self, request: SystemTelegram
|
|
@@ -252,3 +261,28 @@ class BaseServerService(ABC):
|
|
|
252
261
|
The response telegram string, or None if request cannot be handled.
|
|
253
262
|
"""
|
|
254
263
|
return None
|
|
264
|
+
|
|
265
|
+
def add_telegram_buffer(self, telegram: str) -> None:
|
|
266
|
+
"""Add telegram to the buffer.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
telegram: The telegram string to add to the buffer.
|
|
270
|
+
"""
|
|
271
|
+
self.logger.debug(f"Add telegram to the buffer: {telegram}")
|
|
272
|
+
with self.telegram_buffer_lock:
|
|
273
|
+
self.telegram_buffer.append(telegram)
|
|
274
|
+
|
|
275
|
+
def collect_telegram_buffer(self) -> list[str]:
|
|
276
|
+
"""Collecting telegrams from the buffer.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
List of telegram strings from the buffer. The buffer is cleared after collection.
|
|
280
|
+
"""
|
|
281
|
+
self.logger.debug(
|
|
282
|
+
f"Collecting {self.serial_number} telegrams from buffer: {len(self.telegram_buffer)}"
|
|
283
|
+
)
|
|
284
|
+
with self.telegram_buffer_lock:
|
|
285
|
+
result = self.telegram_buffer.copy()
|
|
286
|
+
self.logger.debug(f"Resetting {self.serial_number} buffer")
|
|
287
|
+
self.telegram_buffer.clear()
|
|
288
|
+
return result
|
|
@@ -6,6 +6,7 @@ including response generation and device configuration handling.
|
|
|
6
6
|
|
|
7
7
|
from typing import Dict, Optional
|
|
8
8
|
|
|
9
|
+
from xp.models import ModuleTypeCode
|
|
9
10
|
from xp.models.telegram.system_telegram import SystemTelegram
|
|
10
11
|
from xp.services.server.base_server_service import BaseServerService
|
|
11
12
|
|
|
@@ -32,7 +33,7 @@ class CP20ServerService(BaseServerService):
|
|
|
32
33
|
"""
|
|
33
34
|
super().__init__(serial_number)
|
|
34
35
|
self.device_type = "CP20"
|
|
35
|
-
self.module_type_code =
|
|
36
|
+
self.module_type_code = ModuleTypeCode.CP20 # CP20 module type from registry
|
|
36
37
|
self.firmware_version = "CP20_V0.01.05"
|
|
37
38
|
|
|
38
39
|
def _handle_device_specific_data_request(
|