conson-xp 1.49.0__py3-none-any.whl → 1.50.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.49.0.dist-info → conson_xp-1.50.0.dist-info}/METADATA +1 -1
- {conson_xp-1.49.0.dist-info → conson_xp-1.50.0.dist-info}/RECORD +11 -14
- xp/__init__.py +1 -1
- xp/cli/commands/conbus/conbus_actiontable_commands.py +4 -13
- xp/cli/commands/conbus/conbus_msactiontable_commands.py +56 -13
- xp/models/actiontable/actiontable_type.py +13 -0
- xp/services/conbus/actiontable/actiontable_upload_service.py +99 -19
- xp/utils/dependencies.py +3 -34
- xp/cli/utils/xp_module_type.py +0 -55
- xp/services/conbus/msactiontable/__init__.py +0 -1
- xp/services/conbus/msactiontable/msactiontable_upload_service.py +0 -332
- {conson_xp-1.49.0.dist-info → conson_xp-1.50.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.49.0.dist-info → conson_xp-1.50.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.49.0.dist-info → conson_xp-1.50.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
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.50.0.dist-info/METADATA,sha256=9CLWQiRR8QJj0Ne3zXyV2XzXqkmv3uL7NfVaGkaogHk,11403
|
|
2
|
+
conson_xp-1.50.0.dist-info/WHEEL,sha256=tsUv_t7BDeJeRHaSrczbGeuK-TtDpGsWi_JfpzD255I,90
|
|
3
|
+
conson_xp-1.50.0.dist-info/entry_points.txt,sha256=1OcdIcDM1hz3ljCXgybaPUh1IOFEwkaTgLIW9u9zGeg,50
|
|
4
|
+
conson_xp-1.50.0.dist-info/licenses/LICENSE,sha256=rxj6woMM-r3YCyGq_UHFtbh7kHTAJgrccH6O-33IDE4,1419
|
|
5
|
+
xp/__init__.py,sha256=W-aER6IUlDyRVKHOLg5oh4E-KxDbSmRYOT9XO1035Ac,182
|
|
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=G7A1KFRSV0CEeDTqr_khu-K9_sc01CTI2KSfkFcaBRM,4949
|
|
9
9
|
xp/cli/commands/conbus/__init__.py,sha256=HYaX2__XxwD3Xaw4CzflvL8CwoUa4yR6wOyH8wwyofM,535
|
|
10
10
|
xp/cli/commands/conbus/conbus.py,sha256=GpWq1QS3mKfQFG77nTED-_hsvcnXb3ZIrC6DhfyhzBE,3538
|
|
11
|
-
xp/cli/commands/conbus/conbus_actiontable_commands.py,sha256=
|
|
11
|
+
xp/cli/commands/conbus/conbus_actiontable_commands.py,sha256=EpyLG_6RxhIQY4BWxDXTyo8yzpBwbHfZDOgmRl--R5w,7378
|
|
12
12
|
xp/cli/commands/conbus/conbus_autoreport_commands.py,sha256=dO3rxgII_xZVhbkxlMqTJCarrUveQCs_7-qf4li0UkQ,3962
|
|
13
13
|
xp/cli/commands/conbus/conbus_blink_commands.py,sha256=1zLiXV8Nn4XSDI-z7F3f2RN2IO-yxeMkGQ1PCknAkWY,5398
|
|
14
14
|
xp/cli/commands/conbus/conbus_config_commands.py,sha256=jeZi7J973DrDCyP59Qrvk6tonduj97KnV4fq9zbei2k,721
|
|
@@ -20,7 +20,7 @@ xp/cli/commands/conbus/conbus_export_commands.py,sha256=-fA4vzQF3XsDvRD4BjbE7KRq
|
|
|
20
20
|
xp/cli/commands/conbus/conbus_lightlevel_commands.py,sha256=WH4ZQHxSbquPlAqd0uRxq8VR-sO4_AnfseMqaoPoGoA,7092
|
|
21
21
|
xp/cli/commands/conbus/conbus_linknumber_commands.py,sha256=3bkik8nHXY89XfzeUnKWmvKA70r4qJJ79j8FfLL4sL0,3556
|
|
22
22
|
xp/cli/commands/conbus/conbus_modulenumber_commands.py,sha256=fOIO0f85iDJBfGnRCEN8zK6j4i43uuF_9YKQc_nQ39A,3628
|
|
23
|
-
xp/cli/commands/conbus/conbus_msactiontable_commands.py,sha256=
|
|
23
|
+
xp/cli/commands/conbus/conbus_msactiontable_commands.py,sha256=oMHfrxDR9yj0Pvx92ZHnwYU3CZqwNNvfAfEoLuo_jhQ,11585
|
|
24
24
|
xp/cli/commands/conbus/conbus_output_commands.py,sha256=XMEMb5tM0ul7lwhwoo4QRgWprXZ31qswXBno8KCeFMo,5342
|
|
25
25
|
xp/cli/commands/conbus/conbus_raw_commands.py,sha256=o1dVZqiRw7J3_8Bge7DJucFyAqt7GNP-Azf-f3ir3SU,2019
|
|
26
26
|
xp/cli/commands/conbus/conbus_receive_commands.py,sha256=LdxoOUdM5atkC8fFlp-GK7HQ7oxTnjrSFDx-lQ3nme0,1925
|
|
@@ -54,11 +54,10 @@ xp/cli/utils/formatters.py,sha256=SN_kUkL4M7csay8eftnxoIPS_VvQDlqZueARNElyZZs,98
|
|
|
54
54
|
xp/cli/utils/module_type_choice.py,sha256=Hs0VFrssKWWGqfqBtSJPP7DDCzLyv-BfyeNIPC1WxyU,1672
|
|
55
55
|
xp/cli/utils/serial_number_type.py,sha256=-6MlAAPbpqaGx1Ds3vPPT3PU9hYJG4_C2SmytXV3VyI,1480
|
|
56
56
|
xp/cli/utils/system_function_choice.py,sha256=3YZrTtBHCw_f6KqqT41wJUiiPBVLAQufyPnrMkesdd0,1637
|
|
57
|
-
xp/cli/utils/xp_module_type.py,sha256=rCafAi8k0BNRqtQryoai2WW4zr51lCEY-VRS7asW7VA,1485
|
|
58
57
|
xp/models/__init__.py,sha256=lROqr559DGd8WpJJUtfPT95VERCwMZHpBDEc96QSxQ0,1312
|
|
59
58
|
xp/models/actiontable/__init__.py,sha256=6kVq1rTOlpc24sZxGGVWkY48tqR42YWHLQHqakWqlPc,43
|
|
60
59
|
xp/models/actiontable/actiontable.py,sha256=IAV3KhA5B4jNOHFvVQmhJQV3vbX7EOug2UNAJuTslvk,1258
|
|
61
|
-
xp/models/actiontable/actiontable_type.py,sha256=
|
|
60
|
+
xp/models/actiontable/actiontable_type.py,sha256=HjQ9Z-akdhMJaVx6fgyjqqFCAdFwQp0vO1YmSznlW1M,887
|
|
62
61
|
xp/models/actiontable/msactiontable_xp20.py,sha256=E2JQpZzWuAb_ZdFApzx80tqfF1qFjiO4zp-PtrRBYeQ,5034
|
|
63
62
|
xp/models/actiontable/msactiontable_xp24.py,sha256=WNtUmJVizyUs0RmG9EQW21tgiUB9ofqVQxrzEVpOjdk,9423
|
|
64
63
|
xp/models/actiontable/msactiontable_xp33.py,sha256=nM4v7jICY3woXV50ji02rBbMxAu6CNjydoh9QNAMsF4,11859
|
|
@@ -127,7 +126,7 @@ xp/services/conbus/actiontable/__init__.py,sha256=oD6vRk_Ye-eZ9s_hldAgtRJFu4mfAn
|
|
|
127
126
|
xp/services/conbus/actiontable/actiontable_download_service.py,sha256=ZTQCC1D9TLmyDu3b5GAO4VxUVGSr6HuqZI9fxHB1qW8,14992
|
|
128
127
|
xp/services/conbus/actiontable/actiontable_list_service.py,sha256=oTDSpBkp-MJeaF5bhRnwkSy3na55xqQ4e2ykJzbMCUo,3236
|
|
129
128
|
xp/services/conbus/actiontable/actiontable_show_service.py,sha256=WISY2VsmSlceGa5_9lpFO-gs5TnTjv6YidQksUjCapk,3058
|
|
130
|
-
xp/services/conbus/actiontable/actiontable_upload_service.py,sha256=
|
|
129
|
+
xp/services/conbus/actiontable/actiontable_upload_service.py,sha256=FaQzOSg8s2zUL5xz9qZY9fvzrdDosc3CoxkVDvNg2SU,13252
|
|
131
130
|
xp/services/conbus/conbus_blink_all_service.py,sha256=toDIZDXBGBYnEishcdnJrVzkmfPi7g5nCDXuyA_wFCs,8536
|
|
132
131
|
xp/services/conbus/conbus_blink_service.py,sha256=ggLuzeq_UsgCoxRxg2bsNs9p8Lw_shjsj-niRzb5dKk,7953
|
|
133
132
|
xp/services/conbus/conbus_custom_service.py,sha256=9OIRC2CG_rN96vbv_EZXf7BrX_abhqi5MZx0Se8fEhU,7826
|
|
@@ -141,8 +140,6 @@ xp/services/conbus/conbus_output_service.py,sha256=e57bRkLgPnJuB8hkllNh0kgGkjPt9
|
|
|
141
140
|
xp/services/conbus/conbus_raw_service.py,sha256=OQuV521VOQraf2PGF2B9868vh7sDgmfc19YebrkZnyw,5844
|
|
142
141
|
xp/services/conbus/conbus_receive_service.py,sha256=TFf3W65brGsy6QZICpIs0Xy9bgqyL1vgQuhS_eHuIZs,5416
|
|
143
142
|
xp/services/conbus/conbus_scan_service.py,sha256=_Ka0OUDNYhDgZIR49Q0P5GTxJq6RcAAX2DVqEDdtb5U,6888
|
|
144
|
-
xp/services/conbus/msactiontable/__init__.py,sha256=rDYzumPSfcTjDADHxjE7bXQoeWtZTDGaYzFTYdVl_9g,42
|
|
145
|
-
xp/services/conbus/msactiontable/msactiontable_upload_service.py,sha256=LB9pv0VOUDmyTHKUcY894fmBAqINO7qpM8mW1E3s8aU,12423
|
|
146
143
|
xp/services/conbus/write_config_service.py,sha256=BCfmLNPRDpwSwRMRYJvx2FXA8IZsdgmyeTXIYvmb4ys,9004
|
|
147
144
|
xp/services/homekit/__init__.py,sha256=xAMKmln_AmEFdOOJGKWYi96seRlKDQpKx3-hm7XbdIo,36
|
|
148
145
|
xp/services/homekit/homekit_cache_service.py,sha256=z1TB6icEqd1paoilVTewuFL0lXVCQbvrOJkJvvQECJY,11060
|
|
@@ -200,10 +197,10 @@ xp/term/widgets/protocol_log.py,sha256=E68QmSMpOFrvrPTo_gOQVfyiDqY5c_y8fkNKnQw6V
|
|
|
200
197
|
xp/term/widgets/status_footer.py,sha256=YYAT0431p6jmrzzpVgaPhu7yGkRroWGv4e99t2XlkHI,3297
|
|
201
198
|
xp/utils/__init__.py,sha256=_avMF_UOkfR3tNeDIPqQ5odmbq5raKkaq1rZ9Cn1CJs,332
|
|
202
199
|
xp/utils/checksum.py,sha256=Px1S3dFGA-_plavBxrq3IqmprNlgtNDunE3whg6Otwg,1722
|
|
203
|
-
xp/utils/dependencies.py,sha256=
|
|
200
|
+
xp/utils/dependencies.py,sha256=tmqgooFjkZ8W_CekzJdPlaQas3IJGnVXbfBZdUimwZU,23992
|
|
204
201
|
xp/utils/event_helper.py,sha256=zD0K3TPfGEThU9vUNlDtglTai3Cmm30727iwjDZy6Dk,1007
|
|
205
202
|
xp/utils/logging.py,sha256=wJ1d-yg97NiZUrt2F8iDMcmnHVwC-PErcI-7dpyiRDc,3777
|
|
206
203
|
xp/utils/serialization.py,sha256=TS1OwpTOemSvXsCGw3js4JkYYFEqkzrPe8V9QYQefdw,4684
|
|
207
204
|
xp/utils/state_machine.py,sha256=W9AY4ntRZnFeHAa5d43hm37j53uJPlqkRvWTPiBhJ_0,2464
|
|
208
205
|
xp/utils/time_utils.py,sha256=K17godWpL18VEypbTlvNOEDG6R3huYnf29yjkcnwRpU,3796
|
|
209
|
-
conson_xp-1.
|
|
206
|
+
conson_xp-1.50.0.dist-info/RECORD,,
|
xp/__init__.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"""ActionTable CLI commands."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from contextlib import suppress
|
|
5
|
-
from pathlib import Path
|
|
6
4
|
|
|
7
5
|
import click
|
|
8
6
|
from click import Context
|
|
@@ -13,10 +11,9 @@ from xp.cli.utils.decorators import (
|
|
|
13
11
|
)
|
|
14
12
|
from xp.cli.utils.serial_number_type import SERIAL
|
|
15
13
|
from xp.models.actiontable.actiontable import ActionTable
|
|
16
|
-
from xp.models.actiontable.actiontable_type import ActionTableType
|
|
14
|
+
from xp.models.actiontable.actiontable_type import ActionTableType, ActionTableType2
|
|
17
15
|
from xp.models.config.conson_module_config import (
|
|
18
16
|
ConsonModuleConfig,
|
|
19
|
-
ConsonModuleListConfig,
|
|
20
17
|
)
|
|
21
18
|
from xp.services.conbus.actiontable.actiontable_download_service import (
|
|
22
19
|
ActionTableDownloadService,
|
|
@@ -164,18 +161,12 @@ def conbus_upload_actiontable(ctx: Context, serial_number: str) -> None:
|
|
|
164
161
|
|
|
165
162
|
with service:
|
|
166
163
|
# Load config to get entry count for success message
|
|
167
|
-
config_path = Path.cwd() / "conson.yml"
|
|
168
|
-
if config_path.exists():
|
|
169
|
-
with suppress(Exception):
|
|
170
|
-
config = ConsonModuleListConfig.from_yaml(str(config_path))
|
|
171
|
-
module = config.find_module(serial_number)
|
|
172
|
-
if module and module.action_table:
|
|
173
|
-
entries_count = len(module.action_table)
|
|
174
|
-
|
|
175
164
|
service.on_progress.connect(progress_callback)
|
|
176
165
|
service.on_finish.connect(on_finish)
|
|
177
166
|
service.on_error.connect(on_error)
|
|
178
|
-
service.start(
|
|
167
|
+
service.start(
|
|
168
|
+
serial_number=serial_number, actiontable_type=ActionTableType2.ACTIONTABLE
|
|
169
|
+
)
|
|
179
170
|
service.start_reactor()
|
|
180
171
|
|
|
181
172
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""XP24 Action Table CLI commands."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from typing import Any, Union
|
|
4
|
+
from typing import Any, Optional, Union
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
from click import Context
|
|
@@ -11,8 +11,7 @@ from xp.cli.utils.decorators import (
|
|
|
11
11
|
connection_command,
|
|
12
12
|
)
|
|
13
13
|
from xp.cli.utils.serial_number_type import SERIAL
|
|
14
|
-
from xp.
|
|
15
|
-
from xp.models.actiontable.actiontable_type import ActionTableType
|
|
14
|
+
from xp.models.actiontable.actiontable_type import ActionTableType, ActionTableType2
|
|
16
15
|
from xp.models.config.conson_module_config import ConsonModuleConfig
|
|
17
16
|
from xp.services.conbus.actiontable.actiontable_download_service import (
|
|
18
17
|
ActionTableDownloadService,
|
|
@@ -23,11 +22,59 @@ from xp.services.conbus.actiontable.actiontable_list_service import (
|
|
|
23
22
|
from xp.services.conbus.actiontable.actiontable_show_service import (
|
|
24
23
|
ActionTableShowService,
|
|
25
24
|
)
|
|
26
|
-
from xp.services.conbus.
|
|
27
|
-
|
|
25
|
+
from xp.services.conbus.actiontable.actiontable_upload_service import (
|
|
26
|
+
ActionTableUploadService,
|
|
28
27
|
)
|
|
29
28
|
|
|
30
29
|
|
|
30
|
+
class XpModuleTypeChoice(click.ParamType):
|
|
31
|
+
"""
|
|
32
|
+
Click parameter type for validating XP module types.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
name: The parameter type name.
|
|
36
|
+
choices: List of valid module type strings.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
name = "xpmoduletype"
|
|
40
|
+
|
|
41
|
+
def __init__(self) -> None:
|
|
42
|
+
"""Initialize the XpModuleTypeChoice parameter type."""
|
|
43
|
+
self.choices = ["xp20", "xp24", "xp31", "xp33"]
|
|
44
|
+
|
|
45
|
+
def convert(
|
|
46
|
+
self,
|
|
47
|
+
value: Any,
|
|
48
|
+
param: Optional[click.Parameter],
|
|
49
|
+
ctx: Optional[click.Context],
|
|
50
|
+
) -> Any:
|
|
51
|
+
"""
|
|
52
|
+
Convert and validate XP module type input.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
value: The input value to convert.
|
|
56
|
+
param: The Click parameter.
|
|
57
|
+
ctx: The Click context.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Lowercase module type string if valid, None if input is None.
|
|
61
|
+
"""
|
|
62
|
+
if value is None:
|
|
63
|
+
return value
|
|
64
|
+
normalized_value = value.lower()
|
|
65
|
+
if normalized_value in self.choices:
|
|
66
|
+
return normalized_value
|
|
67
|
+
choices_list = "\n".join(f" - {choice}" for choice in sorted(self.choices))
|
|
68
|
+
self.fail(
|
|
69
|
+
f"{value!r} is not a valid choice. Choose from:\n{choices_list}",
|
|
70
|
+
param,
|
|
71
|
+
ctx,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
XP_MODULE_TYPE = XpModuleTypeChoice()
|
|
76
|
+
|
|
77
|
+
|
|
31
78
|
def _get_actiontable_type(xpmoduletype: str) -> ActionTableType:
|
|
32
79
|
"""
|
|
33
80
|
Map xpmoduletype string to ActionTableType enum.
|
|
@@ -244,22 +291,18 @@ def conbus_show_msactiontable(ctx: Context, serial_number: str) -> None:
|
|
|
244
291
|
|
|
245
292
|
@conbus_msactiontable.command("upload", short_help="Upload MSActionTable")
|
|
246
293
|
@click.argument("serial_number", type=SERIAL)
|
|
247
|
-
@click.argument("xpmoduletype", type=XP_MODULE_TYPE)
|
|
248
294
|
@click.pass_context
|
|
249
295
|
@connection_command()
|
|
250
|
-
def conbus_upload_msactiontable(
|
|
251
|
-
ctx: Context, serial_number: str, xpmoduletype: str
|
|
252
|
-
) -> None:
|
|
296
|
+
def conbus_upload_msactiontable(ctx: Context, serial_number: str) -> None:
|
|
253
297
|
"""
|
|
254
298
|
Upload MS action table from conson.yml to XP module.
|
|
255
299
|
|
|
256
300
|
Args:
|
|
257
301
|
ctx: Click context object.
|
|
258
302
|
serial_number: 10-digit module serial number.
|
|
259
|
-
xpmoduletype: XP module type.
|
|
260
303
|
"""
|
|
261
|
-
service:
|
|
262
|
-
ctx.obj.get("container").get_container().resolve(
|
|
304
|
+
service: ActionTableUploadService = (
|
|
305
|
+
ctx.obj.get("container").get_container().resolve(ActionTableUploadService)
|
|
263
306
|
)
|
|
264
307
|
|
|
265
308
|
def on_progress(progress: str) -> None:
|
|
@@ -300,7 +343,7 @@ def conbus_upload_msactiontable(
|
|
|
300
343
|
service.on_finish.connect(on_finish)
|
|
301
344
|
service.start(
|
|
302
345
|
serial_number=serial_number,
|
|
303
|
-
|
|
346
|
+
actiontable_type=ActionTableType2.MSACTIONTABLE,
|
|
304
347
|
)
|
|
305
348
|
service.start_reactor()
|
|
306
349
|
|
|
@@ -18,3 +18,16 @@ class ActionTableType(str, Enum):
|
|
|
18
18
|
MSACTIONTABLE_XP20 = "msactiontable_xp20"
|
|
19
19
|
MSACTIONTABLE_XP24 = "msactiontable_xp24"
|
|
20
20
|
MSACTIONTABLE_XP33 = "msactiontable_xp33"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ActionTableType2(str, Enum):
|
|
24
|
+
"""
|
|
25
|
+
ActionTable types for download/upload operations.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
ACTIONTABLE: Standard action table.
|
|
29
|
+
MSACTIONTABLE: MS action table.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
ACTIONTABLE = "actiontable"
|
|
33
|
+
MSACTIONTABLE = "msactiontable"
|
|
@@ -5,18 +5,32 @@ from typing import Any, Optional
|
|
|
5
5
|
|
|
6
6
|
from psygnal import Signal
|
|
7
7
|
|
|
8
|
-
from xp.models.
|
|
8
|
+
from xp.models.actiontable.actiontable_type import ActionTableType2
|
|
9
|
+
from xp.models.config.conson_module_config import (
|
|
10
|
+
ConsonModuleConfig,
|
|
11
|
+
ConsonModuleListConfig,
|
|
12
|
+
)
|
|
9
13
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
10
14
|
from xp.models.telegram.system_function import SystemFunction
|
|
11
15
|
from xp.models.telegram.telegram_type import TelegramType
|
|
12
16
|
from xp.services.actiontable.actiontable_serializer import ActionTableSerializer
|
|
17
|
+
from xp.services.actiontable.msactiontable_xp20_serializer import (
|
|
18
|
+
Xp20MsActionTableSerializer,
|
|
19
|
+
)
|
|
20
|
+
from xp.services.actiontable.msactiontable_xp24_serializer import (
|
|
21
|
+
Xp24MsActionTableSerializer,
|
|
22
|
+
)
|
|
23
|
+
from xp.services.actiontable.msactiontable_xp33_serializer import (
|
|
24
|
+
Xp33MsActionTableSerializer,
|
|
25
|
+
)
|
|
13
26
|
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
14
27
|
from xp.services.telegram.telegram_service import TelegramService
|
|
15
28
|
|
|
16
29
|
|
|
17
30
|
class ActionTableUploadService:
|
|
18
31
|
"""
|
|
19
|
-
TCP client service for uploading action tables to Conbus
|
|
32
|
+
TCP client service for uploading action tables and MS action tables to Conbus
|
|
33
|
+
modules.
|
|
20
34
|
|
|
21
35
|
Manages TCP socket connections, handles telegram generation and transmission,
|
|
22
36
|
and processes server responses for action table uploads.
|
|
@@ -35,6 +49,9 @@ class ActionTableUploadService:
|
|
|
35
49
|
self,
|
|
36
50
|
conbus_protocol: ConbusEventProtocol,
|
|
37
51
|
actiontable_serializer: ActionTableSerializer,
|
|
52
|
+
xp20ms_serializer: Xp20MsActionTableSerializer,
|
|
53
|
+
xp24ms_serializer: Xp24MsActionTableSerializer,
|
|
54
|
+
xp33ms_serializer: Xp33MsActionTableSerializer,
|
|
38
55
|
telegram_service: TelegramService,
|
|
39
56
|
conson_config: ConsonModuleListConfig,
|
|
40
57
|
) -> None:
|
|
@@ -44,14 +61,22 @@ class ActionTableUploadService:
|
|
|
44
61
|
Args:
|
|
45
62
|
conbus_protocol: ConbusEventProtocol for communication.
|
|
46
63
|
actiontable_serializer: Action table serializer.
|
|
64
|
+
xp20ms_serializer: XP20 MS action table serializer.
|
|
65
|
+
xp24ms_serializer: XP24 MS action table serializer.
|
|
66
|
+
xp33ms_serializer: XP33 MS action table serializer.
|
|
47
67
|
telegram_service: Telegram service for parsing.
|
|
48
68
|
conson_config: Conson module list configuration.
|
|
49
69
|
"""
|
|
50
70
|
self.conbus_protocol = conbus_protocol
|
|
51
|
-
self.
|
|
71
|
+
self.actiontable_serializer = actiontable_serializer
|
|
72
|
+
self.xp20ms_serializer = xp20ms_serializer
|
|
73
|
+
self.xp24ms_serializer = xp24ms_serializer
|
|
74
|
+
self.xp33ms_serializer = xp33ms_serializer
|
|
52
75
|
self.telegram_service = telegram_service
|
|
53
76
|
self.conson_config = conson_config
|
|
54
77
|
self.serial_number: str = ""
|
|
78
|
+
self.xpmoduletype: str = ""
|
|
79
|
+
self.actiontable_type: ActionTableType2 = ActionTableType2.ACTIONTABLE
|
|
55
80
|
|
|
56
81
|
# Upload state
|
|
57
82
|
self.upload_data_chunks: list[str] = []
|
|
@@ -70,10 +95,17 @@ class ActionTableUploadService:
|
|
|
70
95
|
def connection_made(self) -> None:
|
|
71
96
|
"""Handle connection established event."""
|
|
72
97
|
self.logger.debug("Connection established, sending upload actiontable telegram")
|
|
98
|
+
|
|
99
|
+
system_function = (
|
|
100
|
+
SystemFunction.UPLOAD_ACTIONTABLE
|
|
101
|
+
if self.actiontable_type == ActionTableType2.ACTIONTABLE
|
|
102
|
+
else SystemFunction.UPLOAD_MSACTIONTABLE
|
|
103
|
+
)
|
|
104
|
+
|
|
73
105
|
self.conbus_protocol.send_telegram(
|
|
74
106
|
telegram_type=TelegramType.SYSTEM,
|
|
75
107
|
serial_number=self.serial_number,
|
|
76
|
-
system_function=
|
|
108
|
+
system_function=system_function,
|
|
77
109
|
data_value="00",
|
|
78
110
|
)
|
|
79
111
|
|
|
@@ -127,10 +159,16 @@ class ActionTableUploadService:
|
|
|
127
159
|
# Second character: 'A' + chunk_index (sequential counter A-O for 15 chunks)
|
|
128
160
|
prefix_hex = f"AAA{ord('A') + self.current_chunk_index:c}"
|
|
129
161
|
|
|
162
|
+
system_function = (
|
|
163
|
+
SystemFunction.ACTIONTABLE
|
|
164
|
+
if self.actiontable_type == ActionTableType2.ACTIONTABLE
|
|
165
|
+
else SystemFunction.MSACTIONTABLE
|
|
166
|
+
)
|
|
167
|
+
|
|
130
168
|
self.conbus_protocol.send_telegram(
|
|
131
169
|
telegram_type=TelegramType.SYSTEM,
|
|
132
170
|
serial_number=self.serial_number,
|
|
133
|
-
system_function=
|
|
171
|
+
system_function=system_function,
|
|
134
172
|
data_value=f"{prefix_hex}{chunk}",
|
|
135
173
|
)
|
|
136
174
|
self.current_chunk_index += 1
|
|
@@ -169,19 +207,24 @@ class ActionTableUploadService:
|
|
|
169
207
|
def start(
|
|
170
208
|
self,
|
|
171
209
|
serial_number: str,
|
|
210
|
+
actiontable_type: ActionTableType2,
|
|
172
211
|
timeout_seconds: Optional[float] = None,
|
|
173
212
|
) -> None:
|
|
174
213
|
"""
|
|
175
|
-
Upload action table to module.
|
|
214
|
+
Upload action table or MS action table to module.
|
|
176
215
|
|
|
177
216
|
Uploads the action table configuration to the specified module.
|
|
217
|
+
Module type will decide which actiontable to use.
|
|
178
218
|
|
|
179
219
|
Args:
|
|
180
220
|
serial_number: Module serial number.
|
|
221
|
+
actiontable_type: True if actionTable false for MS action table.
|
|
181
222
|
timeout_seconds: Optional timeout in seconds.
|
|
182
223
|
"""
|
|
183
224
|
self.logger.info("Starting actiontable upload")
|
|
184
225
|
self.serial_number = serial_number
|
|
226
|
+
self.actiontable_type = actiontable_type
|
|
227
|
+
|
|
185
228
|
if timeout_seconds:
|
|
186
229
|
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
187
230
|
|
|
@@ -193,29 +236,65 @@ class ActionTableUploadService:
|
|
|
193
236
|
|
|
194
237
|
# Parse action table strings to ActionTable object
|
|
195
238
|
try:
|
|
196
|
-
|
|
197
|
-
|
|
239
|
+
encoded_data = self.get_encoded_action_table(module)
|
|
240
|
+
# Chunk the data into 64 byte chunks
|
|
241
|
+
chunk_size = 64
|
|
242
|
+
self.upload_data_chunks = [
|
|
243
|
+
encoded_data[i : i + chunk_size]
|
|
244
|
+
for i in range(0, len(encoded_data), chunk_size)
|
|
245
|
+
]
|
|
246
|
+
self.current_chunk_index = 0
|
|
247
|
+
|
|
198
248
|
except ValueError as e:
|
|
199
249
|
self.logger.error(f"Invalid action table format: {e}")
|
|
200
250
|
self.failed(f"Invalid action table format: {e}")
|
|
201
251
|
return
|
|
202
252
|
|
|
203
|
-
# Encode action table to hex string
|
|
204
|
-
encoded_data = self.serializer.to_encoded_string(action_table)
|
|
205
|
-
|
|
206
|
-
# Chunk the data into 64 byte chunks
|
|
207
|
-
chunk_size = 64
|
|
208
|
-
self.upload_data_chunks = [
|
|
209
|
-
encoded_data[i : i + chunk_size]
|
|
210
|
-
for i in range(0, len(encoded_data), chunk_size)
|
|
211
|
-
]
|
|
212
|
-
self.current_chunk_index = 0
|
|
213
|
-
|
|
214
253
|
self.logger.debug(
|
|
215
254
|
f"Upload data encoded: {len(encoded_data)} chars, "
|
|
216
255
|
f"{len(self.upload_data_chunks)} chunks"
|
|
217
256
|
)
|
|
218
257
|
|
|
258
|
+
def get_encoded_action_table(self, module: ConsonModuleConfig) -> str:
|
|
259
|
+
"""
|
|
260
|
+
Get encoded action table string for upload.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
module: Module configuration containing action table data.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Hex-encoded action table string ready for transmission.
|
|
267
|
+
"""
|
|
268
|
+
msactiontable = (
|
|
269
|
+
True if self.actiontable_type == ActionTableType2.MSACTIONTABLE else False
|
|
270
|
+
)
|
|
271
|
+
# Parse MS action table from short format (first element)
|
|
272
|
+
if msactiontable and module.module_type.lower() == "xp20":
|
|
273
|
+
xp20_short_table = module.xp20_msaction_table or []
|
|
274
|
+
xp20_actiontable = self.xp20ms_serializer.from_short_string(
|
|
275
|
+
xp20_short_table
|
|
276
|
+
)
|
|
277
|
+
encoded_string = self.xp20ms_serializer.to_encoded_string(xp20_actiontable)
|
|
278
|
+
elif msactiontable and module.module_type.lower() == "xp24":
|
|
279
|
+
xp24_short_table = module.xp24_msaction_table or []
|
|
280
|
+
xp24_actiontable = self.xp24ms_serializer.from_short_string(
|
|
281
|
+
xp24_short_table
|
|
282
|
+
)
|
|
283
|
+
encoded_string = self.xp24ms_serializer.to_encoded_string(xp24_actiontable)
|
|
284
|
+
elif msactiontable and module.module_type.lower() == "xp33":
|
|
285
|
+
xp33_short_table = module.xp33_msaction_table or []
|
|
286
|
+
xp33_actiontable = self.xp33ms_serializer.from_short_string(
|
|
287
|
+
xp33_short_table
|
|
288
|
+
)
|
|
289
|
+
encoded_string = self.xp33ms_serializer.to_encoded_string(xp33_actiontable)
|
|
290
|
+
else:
|
|
291
|
+
short_table = module.action_table or []
|
|
292
|
+
actiontable = self.actiontable_serializer.from_short_string(short_table)
|
|
293
|
+
encoded_string = self.actiontable_serializer.to_encoded_string(actiontable)
|
|
294
|
+
|
|
295
|
+
# Serialize to telegram data (64 characters: AAAA + 64 data chars)
|
|
296
|
+
return encoded_string
|
|
297
|
+
|
|
219
298
|
def set_timeout(self, timeout_seconds: float) -> None:
|
|
220
299
|
"""
|
|
221
300
|
Set operation timeout.
|
|
@@ -243,6 +322,7 @@ class ActionTableUploadService:
|
|
|
243
322
|
self.upload_data_chunks = []
|
|
244
323
|
self.current_chunk_index = 0
|
|
245
324
|
self.serial_number = ""
|
|
325
|
+
self.xpmoduletype = ""
|
|
246
326
|
return self
|
|
247
327
|
|
|
248
328
|
def __exit__(self, _exc_type: Any, _exc_val: Any, _exc_tb: Any) -> None:
|
xp/utils/dependencies.py
CHANGED
|
@@ -51,9 +51,6 @@ from xp.services.conbus.conbus_output_service import ConbusOutputService
|
|
|
51
51
|
from xp.services.conbus.conbus_raw_service import ConbusRawService
|
|
52
52
|
from xp.services.conbus.conbus_receive_service import ConbusReceiveService
|
|
53
53
|
from xp.services.conbus.conbus_scan_service import ConbusScanService
|
|
54
|
-
from xp.services.conbus.msactiontable.msactiontable_upload_service import (
|
|
55
|
-
MsActionTableUploadService,
|
|
56
|
-
)
|
|
57
54
|
from xp.services.conbus.write_config_service import WriteConfigService
|
|
58
55
|
from xp.services.homekit.homekit_cache_service import HomeKitCacheService
|
|
59
56
|
from xp.services.homekit.homekit_conbus_service import HomeKitConbusService
|
|
@@ -336,6 +333,9 @@ class ServiceContainer:
|
|
|
336
333
|
factory=lambda: ActionTableUploadService(
|
|
337
334
|
conbus_protocol=self.container.resolve(ConbusEventProtocol),
|
|
338
335
|
actiontable_serializer=self.container.resolve(ActionTableSerializer),
|
|
336
|
+
xp20ms_serializer=self.container.resolve(Xp20MsActionTableSerializer),
|
|
337
|
+
xp24ms_serializer=self.container.resolve(Xp24MsActionTableSerializer),
|
|
338
|
+
xp33ms_serializer=self.container.resolve(Xp33MsActionTableSerializer),
|
|
339
339
|
telegram_service=self.container.resolve(TelegramService),
|
|
340
340
|
conson_config=self.container.resolve(ConsonModuleListConfig),
|
|
341
341
|
),
|
|
@@ -372,37 +372,6 @@ class ServiceContainer:
|
|
|
372
372
|
scope=punq.Scope.singleton,
|
|
373
373
|
)
|
|
374
374
|
|
|
375
|
-
self.container.register(
|
|
376
|
-
ActionTableDownloadService,
|
|
377
|
-
factory=lambda: ActionTableDownloadService(
|
|
378
|
-
conbus_protocol=self.container.resolve(ConbusEventProtocol),
|
|
379
|
-
actiontable_serializer=self.container.resolve(ActionTableSerializer),
|
|
380
|
-
msactiontable_serializer_xp20=self.container.resolve(
|
|
381
|
-
Xp20MsActionTableSerializer
|
|
382
|
-
),
|
|
383
|
-
msactiontable_serializer_xp24=self.container.resolve(
|
|
384
|
-
Xp24MsActionTableSerializer
|
|
385
|
-
),
|
|
386
|
-
msactiontable_serializer_xp33=self.container.resolve(
|
|
387
|
-
Xp33MsActionTableSerializer
|
|
388
|
-
),
|
|
389
|
-
),
|
|
390
|
-
scope=punq.Scope.singleton,
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
self.container.register(
|
|
394
|
-
MsActionTableUploadService,
|
|
395
|
-
factory=lambda: MsActionTableUploadService(
|
|
396
|
-
conbus_protocol=self.container.resolve(ConbusEventProtocol),
|
|
397
|
-
xp20ms_serializer=self.container.resolve(Xp20MsActionTableSerializer),
|
|
398
|
-
xp24ms_serializer=self.container.resolve(Xp24MsActionTableSerializer),
|
|
399
|
-
xp33ms_serializer=self.container.resolve(Xp33MsActionTableSerializer),
|
|
400
|
-
telegram_service=self.container.resolve(TelegramService),
|
|
401
|
-
conson_config=self.container.resolve(ConsonModuleListConfig),
|
|
402
|
-
),
|
|
403
|
-
scope=punq.Scope.singleton,
|
|
404
|
-
)
|
|
405
|
-
|
|
406
375
|
self.container.register(
|
|
407
376
|
ConbusCustomService,
|
|
408
377
|
factory=lambda: ConbusCustomService(
|
xp/cli/utils/xp_module_type.py
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"""Click parameter type for XP module type validation."""
|
|
2
|
-
|
|
3
|
-
from typing import Any, Optional
|
|
4
|
-
|
|
5
|
-
import click
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class XpModuleTypeChoice(click.ParamType):
|
|
9
|
-
"""
|
|
10
|
-
Click parameter type for validating XP module types.
|
|
11
|
-
|
|
12
|
-
Attributes:
|
|
13
|
-
name: The parameter type name.
|
|
14
|
-
choices: List of valid module type strings.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
name = "xpmoduletype"
|
|
18
|
-
|
|
19
|
-
def __init__(self) -> None:
|
|
20
|
-
"""Initialize the XpModuleTypeChoice parameter type."""
|
|
21
|
-
self.choices = ["xp20", "xp24", "xp31", "xp33"]
|
|
22
|
-
|
|
23
|
-
def convert(
|
|
24
|
-
self, value: Any, param: Optional[click.Parameter], ctx: Optional[click.Context]
|
|
25
|
-
) -> Any:
|
|
26
|
-
"""
|
|
27
|
-
Convert and validate XP module type input.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
value: The input value to convert.
|
|
31
|
-
param: The Click parameter.
|
|
32
|
-
ctx: The Click context.
|
|
33
|
-
|
|
34
|
-
Returns:
|
|
35
|
-
Lowercase module type string if valid, None if input is None.
|
|
36
|
-
"""
|
|
37
|
-
if value is None:
|
|
38
|
-
return value
|
|
39
|
-
|
|
40
|
-
# Convert to lower for comparison
|
|
41
|
-
normalized_value = value.lower()
|
|
42
|
-
|
|
43
|
-
if normalized_value in self.choices:
|
|
44
|
-
return normalized_value
|
|
45
|
-
|
|
46
|
-
# If not found, show error with available choices
|
|
47
|
-
choices_list = "\n".join(f" - {choice}" for choice in sorted(self.choices))
|
|
48
|
-
self.fail(
|
|
49
|
-
f"{value!r} is not a valid choice. " f"Choose from:\n{choices_list}",
|
|
50
|
-
param,
|
|
51
|
-
ctx,
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
XP_MODULE_TYPE = XpModuleTypeChoice()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""MsAction table services for Conbus."""
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
"""Service for uploading MS action tables via Conbus protocol."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
from typing import Any, Optional, Union
|
|
5
|
-
|
|
6
|
-
from psygnal import Signal
|
|
7
|
-
|
|
8
|
-
from xp.models.config.conson_module_config import ConsonModuleListConfig
|
|
9
|
-
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
10
|
-
from xp.models.telegram.system_function import SystemFunction
|
|
11
|
-
from xp.models.telegram.telegram_type import TelegramType
|
|
12
|
-
from xp.services.actiontable.msactiontable_xp20_serializer import (
|
|
13
|
-
Xp20MsActionTableSerializer,
|
|
14
|
-
)
|
|
15
|
-
from xp.services.actiontable.msactiontable_xp24_serializer import (
|
|
16
|
-
Xp24MsActionTableSerializer,
|
|
17
|
-
)
|
|
18
|
-
from xp.services.actiontable.msactiontable_xp33_serializer import (
|
|
19
|
-
Xp33MsActionTableSerializer,
|
|
20
|
-
)
|
|
21
|
-
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
22
|
-
from xp.services.telegram.telegram_service import TelegramService
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class MsActionTableUploadError(Exception):
|
|
26
|
-
"""Raised when MS action table upload operations fail."""
|
|
27
|
-
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class MsActionTableUploadService:
|
|
32
|
-
"""
|
|
33
|
-
TCP client service for uploading MS action tables to Conbus modules.
|
|
34
|
-
|
|
35
|
-
Manages TCP socket connections, handles telegram generation and transmission,
|
|
36
|
-
and processes server responses for MS action table uploads.
|
|
37
|
-
|
|
38
|
-
Attributes:
|
|
39
|
-
on_progress: Signal emitted with telegram frame when progress is made.
|
|
40
|
-
on_error: Signal emitted with error message string when an error occurs.
|
|
41
|
-
on_finish: Signal emitted with bool (True on success) when upload completes.
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
on_progress: Signal = Signal(str)
|
|
45
|
-
on_error: Signal = Signal(str)
|
|
46
|
-
on_finish: Signal = Signal(bool) # True on success
|
|
47
|
-
|
|
48
|
-
def __init__(
|
|
49
|
-
self,
|
|
50
|
-
conbus_protocol: ConbusEventProtocol,
|
|
51
|
-
xp20ms_serializer: Xp20MsActionTableSerializer,
|
|
52
|
-
xp24ms_serializer: Xp24MsActionTableSerializer,
|
|
53
|
-
xp33ms_serializer: Xp33MsActionTableSerializer,
|
|
54
|
-
telegram_service: TelegramService,
|
|
55
|
-
conson_config: ConsonModuleListConfig,
|
|
56
|
-
) -> None:
|
|
57
|
-
"""
|
|
58
|
-
Initialize the MS action table upload service.
|
|
59
|
-
|
|
60
|
-
Args:
|
|
61
|
-
conbus_protocol: ConbusEventProtocol for communication.
|
|
62
|
-
xp20ms_serializer: XP20 MS action table serializer.
|
|
63
|
-
xp24ms_serializer: XP24 MS action table serializer.
|
|
64
|
-
xp33ms_serializer: XP33 MS action table serializer.
|
|
65
|
-
telegram_service: Telegram service for parsing.
|
|
66
|
-
conson_config: Conson module list configuration.
|
|
67
|
-
"""
|
|
68
|
-
self.conbus_protocol = conbus_protocol
|
|
69
|
-
self.xp20ms_serializer = xp20ms_serializer
|
|
70
|
-
self.xp24ms_serializer = xp24ms_serializer
|
|
71
|
-
self.xp33ms_serializer = xp33ms_serializer
|
|
72
|
-
self.serializer: Union[
|
|
73
|
-
Xp20MsActionTableSerializer,
|
|
74
|
-
Xp24MsActionTableSerializer,
|
|
75
|
-
Xp33MsActionTableSerializer,
|
|
76
|
-
] = xp20ms_serializer
|
|
77
|
-
self.telegram_service = telegram_service
|
|
78
|
-
self.conson_config = conson_config
|
|
79
|
-
self.serial_number: str = ""
|
|
80
|
-
self.xpmoduletype: str = ""
|
|
81
|
-
|
|
82
|
-
# Upload state
|
|
83
|
-
self.upload_data: str = ""
|
|
84
|
-
self.upload_initiated: bool = False
|
|
85
|
-
|
|
86
|
-
# Set up logging
|
|
87
|
-
self.logger = logging.getLogger(__name__)
|
|
88
|
-
|
|
89
|
-
# Connect protocol signals
|
|
90
|
-
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
91
|
-
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
92
|
-
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
93
|
-
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
94
|
-
self.conbus_protocol.on_failed.connect(self.failed)
|
|
95
|
-
|
|
96
|
-
def connection_made(self) -> None:
|
|
97
|
-
"""Handle connection established event."""
|
|
98
|
-
self.logger.debug(
|
|
99
|
-
"Connection established, sending upload msactiontable telegram"
|
|
100
|
-
)
|
|
101
|
-
self.conbus_protocol.send_telegram(
|
|
102
|
-
telegram_type=TelegramType.SYSTEM,
|
|
103
|
-
serial_number=self.serial_number,
|
|
104
|
-
system_function=SystemFunction.UPLOAD_MSACTIONTABLE,
|
|
105
|
-
data_value="00",
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
def telegram_sent(self, telegram_sent: str) -> None:
|
|
109
|
-
"""
|
|
110
|
-
Handle telegram sent event.
|
|
111
|
-
|
|
112
|
-
Args:
|
|
113
|
-
telegram_sent: The telegram that was sent.
|
|
114
|
-
"""
|
|
115
|
-
self.logger.debug(f"Telegram sent: {telegram_sent}")
|
|
116
|
-
|
|
117
|
-
def telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
|
|
118
|
-
"""
|
|
119
|
-
Handle telegram received event.
|
|
120
|
-
|
|
121
|
-
Args:
|
|
122
|
-
telegram_received: The telegram received event.
|
|
123
|
-
"""
|
|
124
|
-
self.logger.debug(f"Telegram received: {telegram_received}")
|
|
125
|
-
if (
|
|
126
|
-
not telegram_received.checksum_valid
|
|
127
|
-
or telegram_received.telegram_type != TelegramType.REPLY.value
|
|
128
|
-
or telegram_received.serial_number != self.serial_number
|
|
129
|
-
):
|
|
130
|
-
self.logger.debug("Not a reply response")
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
reply_telegram = self.telegram_service.parse_reply_telegram(
|
|
134
|
-
telegram_received.frame
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
self._handle_upload_response(reply_telegram)
|
|
138
|
-
|
|
139
|
-
def _handle_upload_response(self, reply_telegram: Any) -> None:
|
|
140
|
-
"""
|
|
141
|
-
Handle telegram responses during upload.
|
|
142
|
-
|
|
143
|
-
Args:
|
|
144
|
-
reply_telegram: Parsed reply telegram.
|
|
145
|
-
"""
|
|
146
|
-
if reply_telegram.system_function == SystemFunction.ACK:
|
|
147
|
-
self.logger.debug("Received ACK for upload")
|
|
148
|
-
|
|
149
|
-
if not self.upload_initiated:
|
|
150
|
-
# First ACK - send data chunk
|
|
151
|
-
self.logger.debug("Sending msactiontable data")
|
|
152
|
-
self.conbus_protocol.send_telegram(
|
|
153
|
-
telegram_type=TelegramType.SYSTEM,
|
|
154
|
-
serial_number=self.serial_number,
|
|
155
|
-
system_function=SystemFunction.MSACTIONTABLE,
|
|
156
|
-
data_value=self.upload_data,
|
|
157
|
-
)
|
|
158
|
-
self.upload_initiated = True
|
|
159
|
-
self.on_progress.emit(".")
|
|
160
|
-
else:
|
|
161
|
-
# Second ACK - send EOF
|
|
162
|
-
self.logger.debug("Data sent, sending EOF")
|
|
163
|
-
self.conbus_protocol.send_telegram(
|
|
164
|
-
telegram_type=TelegramType.SYSTEM,
|
|
165
|
-
serial_number=self.serial_number,
|
|
166
|
-
system_function=SystemFunction.EOF,
|
|
167
|
-
data_value="00",
|
|
168
|
-
)
|
|
169
|
-
self.on_finish.emit(True)
|
|
170
|
-
elif reply_telegram.system_function == SystemFunction.NAK:
|
|
171
|
-
self.logger.debug("Received NAK during upload")
|
|
172
|
-
self.failed("Upload failed: NAK received")
|
|
173
|
-
else:
|
|
174
|
-
self.logger.debug(f"Unexpected response during upload: {reply_telegram}")
|
|
175
|
-
|
|
176
|
-
def timeout(self) -> None:
|
|
177
|
-
"""Handle timeout event."""
|
|
178
|
-
self.logger.debug("Upload timeout")
|
|
179
|
-
self.failed("Upload timeout")
|
|
180
|
-
|
|
181
|
-
def failed(self, message: str) -> None:
|
|
182
|
-
"""
|
|
183
|
-
Handle failed connection event.
|
|
184
|
-
|
|
185
|
-
Args:
|
|
186
|
-
message: Failure message.
|
|
187
|
-
"""
|
|
188
|
-
self.logger.debug(f"Failed: {message}")
|
|
189
|
-
self.on_error.emit(message)
|
|
190
|
-
|
|
191
|
-
def start(
|
|
192
|
-
self,
|
|
193
|
-
serial_number: str,
|
|
194
|
-
xpmoduletype: str,
|
|
195
|
-
timeout_seconds: Optional[float] = None,
|
|
196
|
-
) -> None:
|
|
197
|
-
"""
|
|
198
|
-
Upload MS action table to module.
|
|
199
|
-
|
|
200
|
-
Uploads the MS action table configuration to the specified module.
|
|
201
|
-
|
|
202
|
-
Args:
|
|
203
|
-
serial_number: Module serial number.
|
|
204
|
-
xpmoduletype: XP module type (xp20, xp24, xp33).
|
|
205
|
-
timeout_seconds: Optional timeout in seconds.
|
|
206
|
-
|
|
207
|
-
Raises:
|
|
208
|
-
MsActionTableUploadError: If configuration or validation errors occur.
|
|
209
|
-
"""
|
|
210
|
-
self.logger.info("Starting msactiontable upload")
|
|
211
|
-
self.serial_number = serial_number
|
|
212
|
-
self.xpmoduletype = xpmoduletype
|
|
213
|
-
|
|
214
|
-
# Select serializer based on module type
|
|
215
|
-
if xpmoduletype == "xp20":
|
|
216
|
-
self.serializer = self.xp20ms_serializer
|
|
217
|
-
config_field = "xp20_msaction_table"
|
|
218
|
-
elif xpmoduletype == "xp24":
|
|
219
|
-
self.serializer = self.xp24ms_serializer
|
|
220
|
-
config_field = "xp24_msaction_table"
|
|
221
|
-
elif xpmoduletype == "xp33":
|
|
222
|
-
self.serializer = self.xp33ms_serializer
|
|
223
|
-
config_field = "xp33_msaction_table"
|
|
224
|
-
else:
|
|
225
|
-
raise MsActionTableUploadError(f"Unsupported module type: {xpmoduletype}")
|
|
226
|
-
|
|
227
|
-
if timeout_seconds:
|
|
228
|
-
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
229
|
-
|
|
230
|
-
# Find module
|
|
231
|
-
module = self.conson_config.find_module(serial_number)
|
|
232
|
-
if not module:
|
|
233
|
-
self.failed(f"Module {serial_number} not found in conson.yml")
|
|
234
|
-
return
|
|
235
|
-
|
|
236
|
-
# Validate module type matches
|
|
237
|
-
if module.module_type.lower() != xpmoduletype.lower():
|
|
238
|
-
self.failed(
|
|
239
|
-
f"Module type mismatch: module has type {module.module_type}, "
|
|
240
|
-
f"but {xpmoduletype} was specified"
|
|
241
|
-
)
|
|
242
|
-
return
|
|
243
|
-
|
|
244
|
-
# Get msactiontable config for the module type
|
|
245
|
-
msactiontable_config = getattr(module, config_field, None)
|
|
246
|
-
|
|
247
|
-
if not msactiontable_config:
|
|
248
|
-
self.failed(
|
|
249
|
-
f"Module {serial_number} does not have {config_field} configured in conson.yml"
|
|
250
|
-
)
|
|
251
|
-
return
|
|
252
|
-
|
|
253
|
-
if not isinstance(msactiontable_config, list) or len(msactiontable_config) == 0:
|
|
254
|
-
self.failed(
|
|
255
|
-
f"Module {serial_number} has empty {config_field} list in conson.yml"
|
|
256
|
-
)
|
|
257
|
-
return
|
|
258
|
-
|
|
259
|
-
# Parse MS action table from short format (first element)
|
|
260
|
-
try:
|
|
261
|
-
short_format = msactiontable_config
|
|
262
|
-
msactiontable: Union[
|
|
263
|
-
"Xp20MsActionTable", "Xp24MsActionTable", "Xp33MsActionTable"
|
|
264
|
-
]
|
|
265
|
-
if xpmoduletype == "xp20":
|
|
266
|
-
from xp.models.actiontable.msactiontable_xp20 import Xp20MsActionTable
|
|
267
|
-
|
|
268
|
-
msactiontable = Xp20MsActionTable.from_short_format(short_format)
|
|
269
|
-
elif xpmoduletype == "xp24":
|
|
270
|
-
from xp.models.actiontable.msactiontable_xp24 import Xp24MsActionTable
|
|
271
|
-
|
|
272
|
-
msactiontable = Xp24MsActionTable.from_short_format(short_format)
|
|
273
|
-
elif xpmoduletype == "xp33":
|
|
274
|
-
from xp.models.actiontable.msactiontable_xp33 import Xp33MsActionTable
|
|
275
|
-
|
|
276
|
-
msactiontable = Xp33MsActionTable.from_short_format(short_format)
|
|
277
|
-
except (ValueError, AttributeError) as e:
|
|
278
|
-
self.logger.error(f"Invalid msactiontable format: {e}")
|
|
279
|
-
self.failed(f"Invalid msactiontable format: {e}")
|
|
280
|
-
return
|
|
281
|
-
|
|
282
|
-
# Serialize to telegram data (64 characters: AAAA + 64 data chars)
|
|
283
|
-
self.upload_data = "AAAA" + self.serializer.to_encoded_string(msactiontable) # type: ignore[arg-type]
|
|
284
|
-
|
|
285
|
-
self.logger.debug(
|
|
286
|
-
f"Upload data encoded: {len(self.upload_data)} chars (single chunk)"
|
|
287
|
-
)
|
|
288
|
-
|
|
289
|
-
def set_timeout(self, timeout_seconds: float) -> None:
|
|
290
|
-
"""
|
|
291
|
-
Set operation timeout.
|
|
292
|
-
|
|
293
|
-
Args:
|
|
294
|
-
timeout_seconds: Timeout in seconds.
|
|
295
|
-
"""
|
|
296
|
-
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
297
|
-
|
|
298
|
-
def start_reactor(self) -> None:
|
|
299
|
-
"""Start the reactor."""
|
|
300
|
-
self.conbus_protocol.start_reactor()
|
|
301
|
-
|
|
302
|
-
def stop_reactor(self) -> None:
|
|
303
|
-
"""Stop the reactor."""
|
|
304
|
-
self.conbus_protocol.stop_reactor()
|
|
305
|
-
|
|
306
|
-
def __enter__(self) -> "MsActionTableUploadService":
|
|
307
|
-
"""Enter context manager - reset state for singleton reuse.
|
|
308
|
-
|
|
309
|
-
Returns:
|
|
310
|
-
Self for context manager protocol.
|
|
311
|
-
"""
|
|
312
|
-
# Reset state
|
|
313
|
-
self.upload_data = ""
|
|
314
|
-
self.upload_initiated = False
|
|
315
|
-
self.serial_number = ""
|
|
316
|
-
self.xpmoduletype = ""
|
|
317
|
-
return self
|
|
318
|
-
|
|
319
|
-
def __exit__(self, _exc_type: Any, _exc_val: Any, _exc_tb: Any) -> None:
|
|
320
|
-
"""Exit context manager - cleanup signals and reactor."""
|
|
321
|
-
# Disconnect protocol signals
|
|
322
|
-
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
323
|
-
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
324
|
-
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
325
|
-
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
326
|
-
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
327
|
-
# Disconnect service signals
|
|
328
|
-
self.on_progress.disconnect()
|
|
329
|
-
self.on_error.disconnect()
|
|
330
|
-
self.on_finish.disconnect()
|
|
331
|
-
# Stop reactor
|
|
332
|
-
self.stop_reactor()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|