conson-xp 1.16.0__py3-none-any.whl → 1.17.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.16.0.dist-info → conson_xp-1.17.0.dist-info}/METADATA +5 -1
- {conson_xp-1.16.0.dist-info → conson_xp-1.17.0.dist-info}/RECORD +12 -9
- xp/__init__.py +1 -1
- xp/cli/commands/__init__.py +3 -0
- xp/cli/commands/conbus/conbus_event_commands.py +115 -0
- xp/models/__init__.py +2 -0
- xp/models/conbus/conbus_event_raw.py +47 -0
- xp/services/conbus/conbus_event_raw_service.py +185 -0
- xp/utils/dependencies.py +9 -0
- {conson_xp-1.16.0.dist-info → conson_xp-1.17.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.16.0.dist-info → conson_xp-1.17.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.16.0.dist-info → conson_xp-1.17.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: conson-xp
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.17.0
|
|
4
4
|
Summary: XP Protocol Communication Tools
|
|
5
5
|
Author-Email: ldvchosal <ldvchosal@github.com>
|
|
6
6
|
License: MIT License
|
|
@@ -305,6 +305,10 @@ xp conbus datapoint query
|
|
|
305
305
|
|
|
306
306
|
xp conbus discover
|
|
307
307
|
|
|
308
|
+
xp conbus event
|
|
309
|
+
xp conbus event raw
|
|
310
|
+
|
|
311
|
+
|
|
308
312
|
xp conbus lightlevel
|
|
309
313
|
xp conbus lightlevel get
|
|
310
314
|
xp conbus lightlevel off
|
|
@@ -1,11 +1,11 @@
|
|
|
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.17.0.dist-info/METADATA,sha256=Ib3pQUP44vhlduSotZu5juw2A86rHXgnO1e3fHrhuLg,9506
|
|
2
|
+
conson_xp-1.17.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
conson_xp-1.17.0.dist-info/entry_points.txt,sha256=1OcdIcDM1hz3ljCXgybaPUh1IOFEwkaTgLIW9u9zGeg,50
|
|
4
|
+
conson_xp-1.17.0.dist-info/licenses/LICENSE,sha256=rxj6woMM-r3YCyGq_UHFtbh7kHTAJgrccH6O-33IDE4,1419
|
|
5
|
+
xp/__init__.py,sha256=3Amcz5pSjBDLeWf7aPWXM1DtmHeDt9T4cbNlNM6t964,181
|
|
6
6
|
xp/cli/__init__.py,sha256=QjnKB1KaI2aIyKlzrnvCwfbBuUj8HNgwNMvNJVQofbI,81
|
|
7
7
|
xp/cli/__main__.py,sha256=l2iKwMdat5rTGd3JWs-uGksnYYDDffp_Npz05QdKEeU,117
|
|
8
|
-
xp/cli/commands/__init__.py,sha256=
|
|
8
|
+
xp/cli/commands/__init__.py,sha256=wvo9Z5viwpjvO2432E7YP5HWjLLiW1IFpyXLc5puuGY,4766
|
|
9
9
|
xp/cli/commands/conbus/__init__.py,sha256=gE3K5OEoXkkZX8UOc2v3nreQQzwkOQi7n0VZ-Z2juXA,495
|
|
10
10
|
xp/cli/commands/conbus/conbus.py,sha256=eqdY8ArapvD08Z4p7Xk7eh4z0dESHuMSw7PKtwTJRYU,3021
|
|
11
11
|
xp/cli/commands/conbus/conbus_actiontable_commands.py,sha256=cdjLV9cnm7teEOlu5Jf1MS_aL7lNy8KiDIyjCQa5Nzw,7138
|
|
@@ -15,6 +15,7 @@ xp/cli/commands/conbus/conbus_config_commands.py,sha256=BugIbgNX6_s4MySGvI6tWZkw
|
|
|
15
15
|
xp/cli/commands/conbus/conbus_custom_commands.py,sha256=lICT93ijMdhVRm8KjNMLo7kQ2BLlnOZvMPbR3SxSmZ4,1692
|
|
16
16
|
xp/cli/commands/conbus/conbus_datapoint_commands.py,sha256=r36OuTjREtbGKL-bskAGa0-WLw7x06td6woZn3GYJNA,3630
|
|
17
17
|
xp/cli/commands/conbus/conbus_discover_commands.py,sha256=-y3TDgOnw1_cjvxvgyfQ1GQE2_WmYq-l8Md7DsdTXmo,1719
|
|
18
|
+
xp/cli/commands/conbus/conbus_event_commands.py,sha256=8IjQfX9vXlTRprb1oGkMRHRDPmxb02ZnmVbv3ltCqGk,3369
|
|
18
19
|
xp/cli/commands/conbus/conbus_lightlevel_commands.py,sha256=FpCwogdxa7yFUjlrxM7e8Q2Ut32tKAHabngQQChvtJI,6763
|
|
19
20
|
xp/cli/commands/conbus/conbus_linknumber_commands.py,sha256=KitaGDM5HpwVUz8rLpO8VZUypUTcAg3Bzl0DVm6gnSk,3391
|
|
20
21
|
xp/cli/commands/conbus/conbus_modulenumber_commands.py,sha256=L7-6y3rDllOjQ9g6Bk_RiTKIhAOHVPLdxWif9exkngs,3463
|
|
@@ -51,7 +52,7 @@ xp/cli/utils/system_function_choice.py,sha256=0J02EMgAQcsrE-9rEkv6YHelBoBkZ73T8V
|
|
|
51
52
|
xp/cli/utils/xp_module_type.py,sha256=qSFJBRceqPi_cUFPxAWtLUNq37-KwUEjo9ekYOj7kLQ,1471
|
|
52
53
|
xp/connection/__init__.py,sha256=ClJsVWALYZgAGYZK_Jznd3YKLrHDu17kBfwugjuPfu0,209
|
|
53
54
|
xp/connection/exceptions.py,sha256=7CcRUzkyay5zA6Z9-5dIDRzua806v5N7pCcJazP_1dE,365
|
|
54
|
-
xp/models/__init__.py,sha256=
|
|
55
|
+
xp/models/__init__.py,sha256=UaUiuvWevneh9gPzKNaVsuy6rxM7YlZg4mi8VlEJpfg,1210
|
|
55
56
|
xp/models/actiontable/__init__.py,sha256=6kVq1rTOlpc24sZxGGVWkY48tqR42YWHLQHqakWqlPc,43
|
|
56
57
|
xp/models/actiontable/actiontable.py,sha256=bIeluZhMsvukkSwy2neaewavU8YR6Pso3PIvJ8ENlGg,1251
|
|
57
58
|
xp/models/actiontable/msactiontable_xp20.py,sha256=C_lYYIQagEFap0S5S40_S7AhLO2UZG2EmXjjeem7uw8,1967
|
|
@@ -66,6 +67,7 @@ xp/models/conbus/conbus_connection_status.py,sha256=iGbmtBaAMwV6UD7XG3H3tnB0fl2M
|
|
|
66
67
|
xp/models/conbus/conbus_custom.py,sha256=8H2sPR6_LIlksuOvL7-8bPkzAJLR0rpYiiwfYYFVjEo,1965
|
|
67
68
|
xp/models/conbus/conbus_datapoint.py,sha256=4ncR-vB2lRzRBAA30rYn8eguyTxsZoOKrrXtjGmPpWg,3396
|
|
68
69
|
xp/models/conbus/conbus_discover.py,sha256=nxxUEKfEsH1kd0BF8ovMs7zLujRhrq1oL9ZJtysPr5o,2238
|
|
70
|
+
xp/models/conbus/conbus_event_raw.py,sha256=i5gc7z-0yeunWOZ4rw3AiBt4MANezmhBQKjOOQk3oDc,1567
|
|
69
71
|
xp/models/conbus/conbus_lightlevel.py,sha256=GQGhzrCBEJROosNHInXIzBy6MD2AskEIMoFEGgZ60-0,1695
|
|
70
72
|
xp/models/conbus/conbus_linknumber.py,sha256=uFzKzfB06oIzZEKCb5X2JEI80JjMPFuYglsT1W1k8j4,1815
|
|
71
73
|
xp/models/conbus/conbus_output.py,sha256=q7QKsD_CWT7YOk-V3otKWD1VM7qThrSLIUOunntMrMc,1953
|
|
@@ -117,6 +119,7 @@ xp/services/conbus/conbus_custom_service.py,sha256=4aneYdPObiZOGxPFYg5Wr70cl_xFx
|
|
|
117
119
|
xp/services/conbus/conbus_datapoint_queryall_service.py,sha256=p9R02cVimhdJILHQ6BoeZj8Hog4oRpqBnMo3t4R8ecY,6816
|
|
118
120
|
xp/services/conbus/conbus_datapoint_service.py,sha256=SYhHj9RmTmaJ750tyZ1IW2kl7tgDQ1xm_EM1zUjk1aQ,6421
|
|
119
121
|
xp/services/conbus/conbus_discover_service.py,sha256=sSCSDNWWGtx5QOShwJfcbG54WCYH-BxWvgE10ghibN4,12326
|
|
122
|
+
xp/services/conbus/conbus_event_raw_service.py,sha256=zNY7GxT4R6ROsT1dDhoOoJkGtGbv2_AIBgOlLxZJl1A,7068
|
|
120
123
|
xp/services/conbus/conbus_output_service.py,sha256=mHFOAPx2zo0TStZ3pokp6v94AQjIamcwZDeg5YH_-eo,7240
|
|
121
124
|
xp/services/conbus/conbus_raw_service.py,sha256=4yZLLTIAOxpgByUTWZXw1ihGa6Xtl98ckj9T7VfprDI,4335
|
|
122
125
|
xp/services/conbus/conbus_receive_service.py,sha256=frXrS0OyKKvYYQTWdma21Kd0BKw5aSuHn3ZXTTqOaj0,3953
|
|
@@ -165,8 +168,8 @@ xp/services/telegram/telegram_service.py,sha256=XrP1CPi0ckxoKBaNwLA6lo-TogWxXgmX
|
|
|
165
168
|
xp/services/telegram/telegram_version_service.py,sha256=M5HdOTsLdcwo122FP-jW6R740ktLrtKf2TiMDVz23h8,10528
|
|
166
169
|
xp/utils/__init__.py,sha256=_avMF_UOkfR3tNeDIPqQ5odmbq5raKkaq1rZ9Cn1CJs,332
|
|
167
170
|
xp/utils/checksum.py,sha256=HDpiQxmdIedbCbZ4o_Box0i_Zig417BtCV_46ZyhiTk,1711
|
|
168
|
-
xp/utils/dependencies.py,sha256=
|
|
171
|
+
xp/utils/dependencies.py,sha256=QsZfPDMdlrQK01YQ4PRQ8Q59ZF9w22h1evWX3J4xCjE,20930
|
|
169
172
|
xp/utils/event_helper.py,sha256=W-A_xmoXlpWZBbJH6qdaN50o3-XrwFsDgvAGMJDiAgo,1001
|
|
170
173
|
xp/utils/serialization.py,sha256=RWHHk86feaB4ZP7rjE4qOWK0900yg2joUBDkP76gfOY,4618
|
|
171
174
|
xp/utils/time_utils.py,sha256=dEyViDlAG9GWU-J3D_YVa-sGma6yiyyMTgN4h2x3PY4,3781
|
|
172
|
-
conson_xp-1.
|
|
175
|
+
conson_xp-1.17.0.dist-info/RECORD,,
|
xp/__init__.py
CHANGED
xp/cli/commands/__init__.py
CHANGED
|
@@ -37,6 +37,7 @@ from xp.cli.commands.conbus.conbus_datapoint_commands import (
|
|
|
37
37
|
query_datapoint,
|
|
38
38
|
)
|
|
39
39
|
from xp.cli.commands.conbus.conbus_discover_commands import send_discover_telegram
|
|
40
|
+
from xp.cli.commands.conbus.conbus_event_commands import conbus_event, send_event_raw
|
|
40
41
|
from xp.cli.commands.conbus.conbus_lightlevel_commands import (
|
|
41
42
|
xp_lightlevel_get,
|
|
42
43
|
xp_lightlevel_off,
|
|
@@ -97,6 +98,7 @@ __all__ = [
|
|
|
97
98
|
"conbus_lightlevel",
|
|
98
99
|
"conbus_msactiontable",
|
|
99
100
|
"conbus_actiontable",
|
|
101
|
+
"conbus_event",
|
|
100
102
|
"file",
|
|
101
103
|
"module",
|
|
102
104
|
"reverse_proxy",
|
|
@@ -118,6 +120,7 @@ __all__ = [
|
|
|
118
120
|
"show_config",
|
|
119
121
|
"send_custom_telegram",
|
|
120
122
|
"send_discover_telegram",
|
|
123
|
+
"send_event_raw",
|
|
121
124
|
"xp_output_on",
|
|
122
125
|
"xp_output_off",
|
|
123
126
|
"xp_output_status",
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Conbus event operations CLI commands."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from xp.cli.commands.conbus.conbus import conbus
|
|
8
|
+
from xp.cli.utils.decorators import connection_command
|
|
9
|
+
from xp.models import ConbusEventRawResponse
|
|
10
|
+
from xp.models.telegram.module_type_code import ModuleTypeCode
|
|
11
|
+
from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group(name="event")
|
|
15
|
+
def conbus_event() -> None:
|
|
16
|
+
"""Send event telegrams to Conbus modules."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@conbus_event.command("raw")
|
|
21
|
+
@click.argument("module_type", type=str)
|
|
22
|
+
@click.argument("link_number", type=int)
|
|
23
|
+
@click.argument("input_number", type=int)
|
|
24
|
+
@click.argument("time_ms", type=int, default=1000)
|
|
25
|
+
@click.pass_context
|
|
26
|
+
@connection_command()
|
|
27
|
+
def send_event_raw(
|
|
28
|
+
ctx: click.Context,
|
|
29
|
+
module_type: str,
|
|
30
|
+
link_number: int,
|
|
31
|
+
input_number: int,
|
|
32
|
+
time_ms: int,
|
|
33
|
+
) -> None:
|
|
34
|
+
r"""Send raw event telegrams to simulate button presses.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
ctx: Click context object.
|
|
38
|
+
module_type: Module type code (e.g., CP20, XP33).
|
|
39
|
+
link_number: Link number (0-99).
|
|
40
|
+
input_number: Input number (0-9).
|
|
41
|
+
time_ms: Delay between MAKE/BREAK events in milliseconds (default: 1000).
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
\b
|
|
45
|
+
xp conbus event raw CP20 00 00
|
|
46
|
+
xp conbus event raw XP33 00 00 500
|
|
47
|
+
"""
|
|
48
|
+
# Validate parameters
|
|
49
|
+
if link_number < 0 or link_number > 99:
|
|
50
|
+
click.echo(
|
|
51
|
+
json.dumps({"error": "Link number must be between 0 and 99"}, indent=2)
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
if input_number < 0 or input_number > 9:
|
|
56
|
+
click.echo(
|
|
57
|
+
json.dumps({"error": "Input number must be between 0 and 9"}, indent=2)
|
|
58
|
+
)
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
if time_ms <= 0:
|
|
62
|
+
click.echo(json.dumps({"error": "Time must be greater than 0"}, indent=2))
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
# Resolve module type to numeric code
|
|
66
|
+
module_type_code: int = 0
|
|
67
|
+
try:
|
|
68
|
+
# Try to get the enum value by name
|
|
69
|
+
module_type_enum = ModuleTypeCode[module_type.upper()]
|
|
70
|
+
module_type_code = module_type_enum.value
|
|
71
|
+
except KeyError:
|
|
72
|
+
# Module type not found
|
|
73
|
+
click.echo(
|
|
74
|
+
json.dumps(
|
|
75
|
+
{
|
|
76
|
+
"error": f"Unknown module type: {module_type}. Use module types like CP20, XP33, XP24, etc."
|
|
77
|
+
},
|
|
78
|
+
indent=2,
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
def on_finish(response: ConbusEventRawResponse) -> None:
|
|
84
|
+
"""Handle successful completion of event raw operation.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
response: Event raw response with sent and received telegrams.
|
|
88
|
+
"""
|
|
89
|
+
click.echo(json.dumps(response.to_dict(), indent=2))
|
|
90
|
+
|
|
91
|
+
def on_progress(telegram: str) -> None:
|
|
92
|
+
"""Handle progress updates during event operation.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
telegram: Received telegram.
|
|
96
|
+
"""
|
|
97
|
+
click.echo(json.dumps({"telegram": telegram}))
|
|
98
|
+
|
|
99
|
+
service: ConbusEventRawService = (
|
|
100
|
+
ctx.obj.get("container").get_container().resolve(ConbusEventRawService)
|
|
101
|
+
)
|
|
102
|
+
service.run(
|
|
103
|
+
module_type_code=module_type_code,
|
|
104
|
+
link_number=link_number,
|
|
105
|
+
input_number=input_number,
|
|
106
|
+
time_ms=time_ms,
|
|
107
|
+
progress_callback=on_progress,
|
|
108
|
+
finish_callback=on_finish,
|
|
109
|
+
timeout_seconds=5,
|
|
110
|
+
)
|
|
111
|
+
service.start_reactor()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Register the event command group with conbus
|
|
115
|
+
conbus.add_command(conbus_event)
|
xp/models/__init__.py
CHANGED
|
@@ -5,6 +5,7 @@ from xp.models.conbus.conbus_client_config import ConbusClientConfig
|
|
|
5
5
|
from xp.models.conbus.conbus_connection_status import ConbusConnectionStatus
|
|
6
6
|
from xp.models.conbus.conbus_datapoint import ConbusDatapointResponse
|
|
7
7
|
from xp.models.conbus.conbus_discover import ConbusDiscoverResponse
|
|
8
|
+
from xp.models.conbus.conbus_event_raw import ConbusEventRawResponse
|
|
8
9
|
from xp.models.log_entry import LogEntry
|
|
9
10
|
from xp.models.telegram.event_telegram import EventTelegram
|
|
10
11
|
from xp.models.telegram.event_type import EventType
|
|
@@ -30,5 +31,6 @@ __all__ = [
|
|
|
30
31
|
"ConbusResponse",
|
|
31
32
|
"ConbusDatapointResponse",
|
|
32
33
|
"ConbusDiscoverResponse",
|
|
34
|
+
"ConbusEventRawResponse",
|
|
33
35
|
"ConbusConnectionStatus",
|
|
34
36
|
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Conbus event raw response model."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ConbusEventRawResponse:
|
|
10
|
+
"""Represents a response from Conbus event raw operation.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
success: Whether the operation was successful.
|
|
14
|
+
sent_telegrams: List of event telegrams sent (MAKE and BREAK).
|
|
15
|
+
received_telegrams: List of all telegrams received.
|
|
16
|
+
error: Error message if operation failed.
|
|
17
|
+
timestamp: Timestamp of the response.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
success: bool
|
|
21
|
+
sent_telegrams: Optional[list[str]] = None
|
|
22
|
+
received_telegrams: Optional[list[str]] = None
|
|
23
|
+
error: Optional[str] = None
|
|
24
|
+
timestamp: Optional[datetime] = None
|
|
25
|
+
|
|
26
|
+
def __post_init__(self) -> None:
|
|
27
|
+
"""Initialize timestamp and telegram lists if not provided."""
|
|
28
|
+
if self.timestamp is None:
|
|
29
|
+
self.timestamp = datetime.now()
|
|
30
|
+
if self.sent_telegrams is None:
|
|
31
|
+
self.sent_telegrams = []
|
|
32
|
+
if self.received_telegrams is None:
|
|
33
|
+
self.received_telegrams = []
|
|
34
|
+
|
|
35
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
36
|
+
"""Convert to dictionary for JSON serialization.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Dictionary representation of the response.
|
|
40
|
+
"""
|
|
41
|
+
return {
|
|
42
|
+
"success": self.success,
|
|
43
|
+
"sent_telegrams": self.sent_telegrams,
|
|
44
|
+
"received_telegrams": self.received_telegrams,
|
|
45
|
+
"error": self.error,
|
|
46
|
+
"timestamp": self.timestamp.isoformat() if self.timestamp else None,
|
|
47
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Conbus Event Raw Service for sending raw event telegrams.
|
|
2
|
+
|
|
3
|
+
This service implements a TCP client that connects to Conbus servers and sends
|
|
4
|
+
raw event telegrams to simulate button presses on Conbus modules.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Callable, Optional
|
|
9
|
+
|
|
10
|
+
from twisted.internet.base import DelayedCall
|
|
11
|
+
|
|
12
|
+
from xp.models import ConbusEventRawResponse
|
|
13
|
+
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
14
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ConbusEventRawService:
|
|
18
|
+
"""Service for sending raw event telegrams to Conbus servers.
|
|
19
|
+
|
|
20
|
+
Uses ConbusEventProtocol to send MAKE/BREAK event sequences to
|
|
21
|
+
simulate button presses on Conbus modules.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
conbus_protocol: Protocol instance for Conbus communication.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
conbus_protocol: ConbusEventProtocol
|
|
28
|
+
|
|
29
|
+
def __init__(self, conbus_protocol: ConbusEventProtocol) -> None:
|
|
30
|
+
"""Initialize the Conbus event raw service.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
conbus_protocol: ConbusEventProtocol instance.
|
|
34
|
+
"""
|
|
35
|
+
self.progress_callback: Optional[Callable[[str], None]] = None
|
|
36
|
+
self.finish_callback: Optional[Callable[[ConbusEventRawResponse], None]] = None
|
|
37
|
+
|
|
38
|
+
self.conbus_protocol: ConbusEventProtocol = conbus_protocol
|
|
39
|
+
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
40
|
+
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
41
|
+
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
42
|
+
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
43
|
+
self.conbus_protocol.on_failed.connect(self.failed)
|
|
44
|
+
|
|
45
|
+
self.event_result = ConbusEventRawResponse(success=False)
|
|
46
|
+
self.logger = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
# Event parameters
|
|
49
|
+
self.module_type_code: int = 0
|
|
50
|
+
self.link_number: int = 0
|
|
51
|
+
self.input_number: int = 0
|
|
52
|
+
self.time_ms: int = 1000
|
|
53
|
+
self.break_event_call: Optional[DelayedCall] = None
|
|
54
|
+
|
|
55
|
+
def connection_made(self) -> None:
|
|
56
|
+
"""Handle connection established event."""
|
|
57
|
+
self.logger.debug("Connection established")
|
|
58
|
+
self.logger.debug("Sending MAKE event telegram")
|
|
59
|
+
self._send_make_event()
|
|
60
|
+
|
|
61
|
+
def _send_make_event(self) -> None:
|
|
62
|
+
"""Send MAKE event telegram."""
|
|
63
|
+
payload = f"E{self.module_type_code:02d}L{self.link_number:02d}I{self.input_number:02d}M"
|
|
64
|
+
self.logger.debug(f"Sending MAKE event: {payload}")
|
|
65
|
+
self.conbus_protocol.telegram_queue.put_nowait(payload.encode())
|
|
66
|
+
self.conbus_protocol._reactor.callLater(
|
|
67
|
+
0.0, self.conbus_protocol.start_queue_manager
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Schedule BREAK event after delay
|
|
71
|
+
delay_seconds = self.time_ms / 1000.0
|
|
72
|
+
self.break_event_call = self.conbus_protocol._reactor.callLater(
|
|
73
|
+
delay_seconds, self._send_break_event
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def _send_break_event(self) -> None:
|
|
77
|
+
"""Send BREAK event telegram."""
|
|
78
|
+
payload = f"E{self.module_type_code:02d}L{self.link_number:02d}I{self.input_number:02d}B"
|
|
79
|
+
self.logger.debug(f"Sending BREAK event: {payload}")
|
|
80
|
+
self.conbus_protocol.telegram_queue.put_nowait(payload.encode())
|
|
81
|
+
self.conbus_protocol._reactor.callLater(
|
|
82
|
+
0.0, self.conbus_protocol.start_queue_manager
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def telegram_sent(self, telegram_sent: str) -> None:
|
|
86
|
+
"""Handle telegram sent event.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
telegram_sent: The telegram that was sent.
|
|
90
|
+
"""
|
|
91
|
+
self.logger.debug(f"Telegram sent: {telegram_sent}")
|
|
92
|
+
if self.event_result.sent_telegrams is None:
|
|
93
|
+
self.event_result.sent_telegrams = []
|
|
94
|
+
self.event_result.sent_telegrams.append(telegram_sent)
|
|
95
|
+
|
|
96
|
+
def telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
|
|
97
|
+
"""Handle telegram received event.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
telegram_received: The telegram received event.
|
|
101
|
+
"""
|
|
102
|
+
self.logger.debug(f"Telegram received: {telegram_received.frame}")
|
|
103
|
+
if self.event_result.received_telegrams is None:
|
|
104
|
+
self.event_result.received_telegrams = []
|
|
105
|
+
self.event_result.received_telegrams.append(telegram_received.frame)
|
|
106
|
+
|
|
107
|
+
# Display progress - show ALL received telegrams
|
|
108
|
+
if self.progress_callback:
|
|
109
|
+
self.progress_callback(telegram_received.frame)
|
|
110
|
+
|
|
111
|
+
def timeout(self) -> None:
|
|
112
|
+
"""Handle timeout event.
|
|
113
|
+
|
|
114
|
+
Timeout is the normal/expected way to finish this service.
|
|
115
|
+
"""
|
|
116
|
+
timeout_seconds = self.conbus_protocol.timeout_seconds
|
|
117
|
+
self.logger.info("Event raw finished after timeout: %ss", timeout_seconds)
|
|
118
|
+
self.event_result.success = True
|
|
119
|
+
self.event_result.error = None
|
|
120
|
+
if self.finish_callback:
|
|
121
|
+
self.finish_callback(self.event_result)
|
|
122
|
+
|
|
123
|
+
self.stop_reactor()
|
|
124
|
+
|
|
125
|
+
def failed(self, message: str) -> None:
|
|
126
|
+
"""Handle failed connection event.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
message: Failure message.
|
|
130
|
+
"""
|
|
131
|
+
self.logger.debug(f"Failed: {message}")
|
|
132
|
+
self.event_result.success = False
|
|
133
|
+
self.event_result.error = message
|
|
134
|
+
if self.finish_callback:
|
|
135
|
+
self.finish_callback(self.event_result)
|
|
136
|
+
|
|
137
|
+
self.stop_reactor()
|
|
138
|
+
|
|
139
|
+
def stop_reactor(self) -> None:
|
|
140
|
+
"""Stop reactor."""
|
|
141
|
+
self.logger.info("Stopping reactor")
|
|
142
|
+
# Cancel break event call if it's still pending
|
|
143
|
+
if self.break_event_call and self.break_event_call.active():
|
|
144
|
+
self.break_event_call.cancel()
|
|
145
|
+
self.conbus_protocol.stop_reactor()
|
|
146
|
+
|
|
147
|
+
def start_reactor(self) -> None:
|
|
148
|
+
"""Start reactor."""
|
|
149
|
+
self.logger.info("Starting reactor")
|
|
150
|
+
self.conbus_protocol.start_reactor()
|
|
151
|
+
|
|
152
|
+
def run(
|
|
153
|
+
self,
|
|
154
|
+
module_type_code: int,
|
|
155
|
+
link_number: int,
|
|
156
|
+
input_number: int,
|
|
157
|
+
time_ms: int,
|
|
158
|
+
progress_callback: Optional[Callable[[str], None]],
|
|
159
|
+
finish_callback: Callable[[ConbusEventRawResponse], None],
|
|
160
|
+
timeout_seconds: int = 5,
|
|
161
|
+
) -> None:
|
|
162
|
+
"""Run reactor in dedicated thread with its own event loop.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
module_type_code: Module type code (numeric, e.g., 2 for CP20, 33 for XP33).
|
|
166
|
+
link_number: Link number (0-99).
|
|
167
|
+
input_number: Input number (0-9).
|
|
168
|
+
time_ms: Delay in milliseconds between MAKE and BREAK events.
|
|
169
|
+
progress_callback: Callback for progress updates (received telegrams).
|
|
170
|
+
finish_callback: Callback when operation completes.
|
|
171
|
+
timeout_seconds: Timeout in seconds (default: 5).
|
|
172
|
+
"""
|
|
173
|
+
self.logger.info(
|
|
174
|
+
f"Starting event raw: module={module_type_code}, "
|
|
175
|
+
f"link={link_number}, input={input_number}, time={time_ms}ms"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
self.module_type_code = module_type_code
|
|
179
|
+
self.link_number = link_number
|
|
180
|
+
self.input_number = input_number
|
|
181
|
+
self.time_ms = time_ms
|
|
182
|
+
|
|
183
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
184
|
+
self.progress_callback = progress_callback
|
|
185
|
+
self.finish_callback = finish_callback
|
xp/utils/dependencies.py
CHANGED
|
@@ -43,6 +43,7 @@ from xp.services.conbus.conbus_datapoint_service import (
|
|
|
43
43
|
ConbusDatapointService,
|
|
44
44
|
)
|
|
45
45
|
from xp.services.conbus.conbus_discover_service import ConbusDiscoverService
|
|
46
|
+
from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
|
|
46
47
|
from xp.services.conbus.conbus_output_service import ConbusOutputService
|
|
47
48
|
from xp.services.conbus.conbus_raw_service import ConbusRawService
|
|
48
49
|
from xp.services.conbus.conbus_receive_service import ConbusReceiveService
|
|
@@ -180,6 +181,14 @@ class ServiceContainer:
|
|
|
180
181
|
scope=punq.Scope.singleton,
|
|
181
182
|
)
|
|
182
183
|
|
|
184
|
+
self.container.register(
|
|
185
|
+
ConbusEventRawService,
|
|
186
|
+
factory=lambda: ConbusEventRawService(
|
|
187
|
+
conbus_protocol=self.container.resolve(ConbusEventProtocol)
|
|
188
|
+
),
|
|
189
|
+
scope=punq.Scope.singleton,
|
|
190
|
+
)
|
|
191
|
+
|
|
183
192
|
self.container.register(
|
|
184
193
|
ConbusBlinkService,
|
|
185
194
|
factory=lambda: ConbusBlinkService(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|