conson-xp 1.0.1__py3-none-any.whl → 1.2.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.0.1.dist-info → conson_xp-1.2.0.dist-info}/METADATA +1 -1
- conson_xp-1.2.0.dist-info/RECORD +181 -0
- xp/__init__.py +4 -3
- xp/api/main.py +18 -3
- xp/api/models/api.py +13 -2
- xp/api/models/discover.py +12 -2
- xp/api/routers/conbus_blink.py +18 -6
- xp/api/routers/conbus_custom.py +11 -3
- xp/api/routers/conbus_datapoint.py +10 -3
- xp/api/routers/conbus_output.py +29 -9
- xp/api/routers/errors.py +6 -5
- xp/cli/__init__.py +1 -1
- xp/cli/commands/__init__.py +1 -0
- xp/cli/commands/api.py +1 -5
- xp/cli/commands/api_start_commands.py +14 -8
- xp/cli/commands/conbus/conbus.py +9 -37
- xp/cli/commands/conbus/conbus_actiontable_commands.py +21 -1
- xp/cli/commands/conbus/conbus_autoreport_commands.py +21 -11
- xp/cli/commands/conbus/conbus_blink_commands.py +53 -21
- xp/cli/commands/conbus/conbus_config_commands.py +7 -4
- xp/cli/commands/conbus/conbus_custom_commands.py +13 -4
- xp/cli/commands/conbus/conbus_datapoint_commands.py +28 -8
- xp/cli/commands/conbus/conbus_discover_commands.py +15 -4
- xp/cli/commands/conbus/conbus_lightlevel_commands.py +50 -11
- xp/cli/commands/conbus/conbus_linknumber_commands.py +21 -11
- xp/cli/commands/conbus/conbus_msactiontable_commands.py +25 -1
- xp/cli/commands/conbus/conbus_output_commands.py +46 -12
- xp/cli/commands/conbus/conbus_raw_commands.py +17 -6
- xp/cli/commands/conbus/conbus_receive_commands.py +15 -7
- xp/cli/commands/conbus/conbus_scan_commands.py +35 -102
- xp/cli/commands/file_commands.py +26 -15
- xp/cli/commands/homekit/homekit.py +14 -8
- xp/cli/commands/homekit/homekit_start_commands.py +5 -5
- xp/cli/commands/module_commands.py +26 -19
- xp/cli/commands/reverse_proxy_commands.py +24 -18
- xp/cli/commands/server/server_commands.py +18 -18
- xp/cli/commands/telegram/telegram.py +4 -12
- xp/cli/commands/telegram/telegram_blink_commands.py +10 -8
- xp/cli/commands/telegram/telegram_checksum_commands.py +19 -8
- xp/cli/commands/telegram/telegram_discover_commands.py +2 -4
- xp/cli/commands/telegram/telegram_linknumber_commands.py +11 -8
- xp/cli/commands/telegram/telegram_parse_commands.py +10 -9
- xp/cli/commands/telegram/telegram_version_commands.py +8 -4
- xp/cli/main.py +5 -1
- xp/cli/utils/click_tree.py +23 -3
- xp/cli/utils/datapoint_type_choice.py +20 -0
- xp/cli/utils/decorators.py +165 -14
- xp/cli/utils/error_handlers.py +49 -18
- xp/cli/utils/formatters.py +95 -10
- xp/cli/utils/serial_number_type.py +18 -0
- xp/cli/utils/system_function_choice.py +20 -0
- xp/cli/utils/xp_module_type.py +20 -0
- xp/connection/__init__.py +1 -1
- xp/connection/exceptions.py +5 -5
- xp/models/__init__.py +1 -1
- xp/models/actiontable/__init__.py +1 -0
- xp/models/actiontable/actiontable.py +17 -1
- xp/models/actiontable/msactiontable_xp20.py +10 -0
- xp/models/actiontable/msactiontable_xp24.py +20 -3
- xp/models/actiontable/msactiontable_xp33.py +27 -4
- xp/models/conbus/__init__.py +1 -0
- xp/models/conbus/conbus.py +34 -4
- xp/models/conbus/conbus_autoreport.py +20 -2
- xp/models/conbus/conbus_blink.py +22 -2
- xp/models/conbus/conbus_client_config.py +22 -1
- xp/models/conbus/conbus_connection_status.py +16 -2
- xp/models/conbus/conbus_custom.py +21 -2
- xp/models/conbus/conbus_datapoint.py +22 -2
- xp/models/conbus/conbus_discover.py +18 -2
- xp/models/conbus/conbus_lightlevel.py +20 -2
- xp/models/conbus/conbus_linknumber.py +20 -2
- xp/models/conbus/conbus_output.py +22 -2
- xp/models/conbus/conbus_raw.py +17 -2
- xp/models/conbus/conbus_receive.py +16 -2
- xp/models/homekit/__init__.py +1 -0
- xp/models/homekit/homekit_accessory.py +15 -1
- xp/models/homekit/homekit_config.py +52 -0
- xp/models/homekit/homekit_conson_config.py +32 -0
- xp/models/log_entry.py +49 -9
- xp/models/protocol/__init__.py +1 -0
- xp/models/protocol/conbus_protocol.py +130 -21
- xp/models/telegram/__init__.py +1 -0
- xp/models/telegram/action_type.py +16 -2
- xp/models/telegram/datapoint_type.py +36 -2
- xp/models/telegram/event_telegram.py +46 -10
- xp/models/telegram/event_type.py +8 -1
- xp/models/telegram/input_action_type.py +34 -2
- xp/models/telegram/input_type.py +9 -1
- xp/models/telegram/module_type.py +69 -19
- xp/models/telegram/module_type_code.py +43 -1
- xp/models/telegram/output_telegram.py +30 -6
- xp/models/telegram/reply_telegram.py +56 -11
- xp/models/telegram/system_function.py +35 -3
- xp/models/telegram/system_telegram.py +18 -4
- xp/models/telegram/telegram.py +12 -3
- xp/models/telegram/telegram_type.py +8 -1
- xp/models/telegram/timeparam_type.py +27 -0
- xp/models/write_config_type.py +17 -2
- xp/services/__init__.py +1 -1
- xp/services/conbus/__init__.py +1 -0
- xp/services/conbus/actiontable/__init__.py +1 -0
- xp/services/conbus/actiontable/actiontable_service.py +33 -2
- xp/services/conbus/actiontable/msactiontable_service.py +40 -3
- xp/services/conbus/actiontable/msactiontable_xp24_serializer.py +36 -4
- xp/services/conbus/actiontable/msactiontable_xp33_serializer.py +45 -5
- xp/services/conbus/conbus_autoreport_get_service.py +17 -8
- xp/services/conbus/conbus_autoreport_set_service.py +29 -16
- xp/services/conbus/conbus_blink_all_service.py +40 -21
- xp/services/conbus/conbus_blink_service.py +37 -13
- xp/services/conbus/conbus_custom_service.py +29 -13
- xp/services/conbus/conbus_datapoint_queryall_service.py +40 -16
- xp/services/conbus/conbus_datapoint_service.py +33 -12
- xp/services/conbus/conbus_discover_service.py +43 -7
- xp/services/conbus/conbus_lightlevel_get_service.py +22 -14
- xp/services/conbus/conbus_lightlevel_set_service.py +40 -20
- xp/services/conbus/conbus_linknumber_get_service.py +18 -10
- xp/services/conbus/conbus_linknumber_set_service.py +34 -8
- xp/services/conbus/conbus_output_service.py +33 -13
- xp/services/conbus/conbus_raw_service.py +36 -16
- xp/services/conbus/conbus_receive_service.py +38 -6
- xp/services/conbus/conbus_scan_service.py +45 -19
- xp/services/homekit/__init__.py +1 -0
- xp/services/homekit/homekit_cache_service.py +31 -6
- xp/services/homekit/homekit_conbus_service.py +33 -2
- xp/services/homekit/homekit_config_validator.py +97 -15
- xp/services/homekit/homekit_conson_validator.py +51 -7
- xp/services/homekit/homekit_dimminglight.py +47 -1
- xp/services/homekit/homekit_dimminglight_service.py +35 -1
- xp/services/homekit/homekit_hap_service.py +71 -18
- xp/services/homekit/homekit_lightbulb.py +35 -1
- xp/services/homekit/homekit_lightbulb_service.py +30 -2
- xp/services/homekit/homekit_module_service.py +23 -1
- xp/services/homekit/homekit_outlet.py +47 -1
- xp/services/homekit/homekit_outlet_service.py +44 -2
- xp/services/homekit/homekit_service.py +113 -19
- xp/services/log_file_service.py +37 -41
- xp/services/module_type_service.py +26 -5
- xp/services/protocol/__init__.py +1 -1
- xp/services/protocol/conbus_protocol.py +115 -20
- xp/services/protocol/protocol_factory.py +40 -0
- xp/services/protocol/telegram_protocol.py +38 -7
- xp/services/reverse_proxy_service.py +79 -14
- xp/services/server/__init__.py +1 -0
- xp/services/server/base_server_service.py +102 -14
- xp/services/server/cp20_server_service.py +12 -4
- xp/services/server/server_service.py +26 -11
- xp/services/server/xp130_server_service.py +11 -3
- xp/services/server/xp20_server_service.py +11 -3
- xp/services/server/xp230_server_service.py +11 -3
- xp/services/server/xp24_server_service.py +33 -6
- xp/services/server/xp33_server_service.py +41 -8
- xp/services/telegram/__init__.py +1 -0
- xp/services/telegram/telegram_blink_service.py +19 -31
- xp/services/telegram/telegram_checksum_service.py +10 -10
- xp/services/telegram/telegram_discover_service.py +58 -29
- xp/services/telegram/telegram_link_number_service.py +27 -40
- xp/services/telegram/telegram_output_service.py +46 -49
- xp/services/telegram/telegram_service.py +41 -41
- xp/services/telegram/telegram_version_service.py +4 -2
- xp/utils/__init__.py +1 -1
- xp/utils/dependencies.py +0 -1
- xp/utils/serialization.py +6 -0
- xp/utils/time_utils.py +6 -11
- conson_xp-1.0.1.dist-info/RECORD +0 -181
- {conson_xp-1.0.1.dist-info → conson_xp-1.2.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.0.1.dist-info → conson_xp-1.2.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.0.1.dist-info → conson_xp-1.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""HomeKit Service for Apple HomeKit integration.
|
|
2
|
+
|
|
3
|
+
This module provides the main service for HomeKit integration.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
# Install asyncio reactor before importing reactor
|
|
2
7
|
|
|
3
8
|
import asyncio
|
|
@@ -29,6 +34,23 @@ from xp.services.protocol.protocol_factory import TelegramFactory
|
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
class HomeKitService:
|
|
37
|
+
"""Main HomeKit service for Apple HomeKit integration.
|
|
38
|
+
|
|
39
|
+
Attributes:
|
|
40
|
+
cli_config: Conbus client configuration.
|
|
41
|
+
reactor: Twisted reactor instance.
|
|
42
|
+
telegram_factory: Telegram factory for protocol.
|
|
43
|
+
protocol: Telegram protocol instance.
|
|
44
|
+
event_bus: Event bus for inter-service communication.
|
|
45
|
+
lightbulb_service: Lightbulb service instance.
|
|
46
|
+
dimminglight_service: Dimming light service instance.
|
|
47
|
+
outlet_service: Outlet service instance.
|
|
48
|
+
cache_service: Cache service instance.
|
|
49
|
+
conbus_service: Conbus service instance.
|
|
50
|
+
module_factory: HAP service instance.
|
|
51
|
+
telegram_service: Telegram service instance.
|
|
52
|
+
logger: Logger instance.
|
|
53
|
+
"""
|
|
32
54
|
|
|
33
55
|
def __init__(
|
|
34
56
|
self,
|
|
@@ -44,7 +66,21 @@ class HomeKitService:
|
|
|
44
66
|
module_factory: HomekitHapService,
|
|
45
67
|
telegram_service: TelegramService,
|
|
46
68
|
):
|
|
47
|
-
|
|
69
|
+
"""Initialize the HomeKit service.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
cli_config: Conbus client configuration.
|
|
73
|
+
event_bus: Event bus instance.
|
|
74
|
+
telegram_factory: Telegram factory instance.
|
|
75
|
+
reactor: Twisted reactor instance.
|
|
76
|
+
lightbulb_service: Lightbulb service instance.
|
|
77
|
+
outlet_service: Outlet service instance.
|
|
78
|
+
dimminglight_service: Dimming light service instance.
|
|
79
|
+
cache_service: Cache service instance.
|
|
80
|
+
conbus_service: Conbus service instance.
|
|
81
|
+
module_factory: HAP service instance.
|
|
82
|
+
telegram_service: Telegram service instance.
|
|
83
|
+
"""
|
|
48
84
|
self.cli_config = cli_config.conbus
|
|
49
85
|
self.reactor = reactor
|
|
50
86
|
self.telegram_factory = telegram_factory
|
|
@@ -67,23 +103,24 @@ class HomeKitService:
|
|
|
67
103
|
self.event_bus.on(ModuleDiscoveredEvent, self.handle_module_discovered)
|
|
68
104
|
|
|
69
105
|
def start(self) -> None:
|
|
70
|
-
|
|
106
|
+
"""Start the HomeKit service."""
|
|
107
|
+
self.logger.info("Starting HomeKit service.")
|
|
71
108
|
self.logger.debug("start")
|
|
72
109
|
|
|
73
110
|
# Run reactor in its own dedicated thread
|
|
74
|
-
self.logger.info("Starting reactor in dedicated thread
|
|
111
|
+
self.logger.info("Starting reactor in dedicated thread.")
|
|
75
112
|
reactor_thread = threading.Thread(
|
|
76
113
|
target=self._run_reactor_in_thread, daemon=True, name="ReactorThread"
|
|
77
114
|
)
|
|
78
115
|
reactor_thread.start()
|
|
79
116
|
|
|
80
117
|
# Keep MainThread alive while reactor thread runs
|
|
81
|
-
self.logger.info("Reactor thread started, MainThread waiting
|
|
118
|
+
self.logger.info("Reactor thread started, MainThread waiting.")
|
|
82
119
|
reactor_thread.join()
|
|
83
120
|
|
|
84
121
|
def _run_reactor_in_thread(self) -> None:
|
|
85
|
-
"""Run reactor in dedicated thread with its own event loop"""
|
|
86
|
-
self.logger.info("Reactor thread starting
|
|
122
|
+
"""Run reactor in dedicated thread with its own event loop."""
|
|
123
|
+
self.logger.info("Reactor thread starting.")
|
|
87
124
|
|
|
88
125
|
# The asyncio reactor already has an event loop set up
|
|
89
126
|
# We just need to use it
|
|
@@ -101,17 +138,21 @@ class HomeKitService:
|
|
|
101
138
|
self.reactor.callLater(0, self._start_module_factory)
|
|
102
139
|
|
|
103
140
|
# Run the reactor (which now uses asyncio underneath)
|
|
104
|
-
self.logger.info("Starting reactor event loop
|
|
141
|
+
self.logger.info("Starting reactor event loop.")
|
|
105
142
|
self.reactor.run()
|
|
106
143
|
|
|
107
144
|
def _start_module_factory(self) -> None:
|
|
108
|
-
"""Start module factory after reactor starts
|
|
109
|
-
|
|
145
|
+
"""Start module factory after reactor starts.
|
|
146
|
+
|
|
147
|
+
Creates and schedules an async task to start the HAP service.
|
|
148
|
+
"""
|
|
149
|
+
self.logger.info("Starting module factory.")
|
|
110
150
|
self.logger.debug("callWhenRunning executed, scheduling async task")
|
|
111
151
|
|
|
112
152
|
# Run HAP-python driver asynchronously in the reactor's event loop
|
|
113
153
|
async def async_start() -> None:
|
|
114
|
-
|
|
154
|
+
"""Start the HAP service asynchronously."""
|
|
155
|
+
self.logger.info("async_start executing.")
|
|
115
156
|
try:
|
|
116
157
|
await self.module_factory.async_start()
|
|
117
158
|
self.logger.info("Module factory started successfully")
|
|
@@ -130,23 +171,42 @@ class HomeKitService:
|
|
|
130
171
|
|
|
131
172
|
# Event handlers
|
|
132
173
|
def handle_connection_made(self, event: ConnectionMadeEvent) -> None:
|
|
133
|
-
"""Handle connection established - send initial telegram
|
|
174
|
+
"""Handle connection established - send initial telegram.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
event: Connection made event.
|
|
178
|
+
"""
|
|
134
179
|
self.logger.debug("Connection established successfully")
|
|
135
180
|
self.logger.debug("Sending initial discovery telegram: S0000000000F01D00")
|
|
136
181
|
event.protocol.sendFrame(b"S0000000000F01D00")
|
|
137
182
|
|
|
138
183
|
def handle_connection_failed(self, event: ConnectionFailedEvent) -> None:
|
|
139
|
-
"""Handle connection failed
|
|
184
|
+
"""Handle connection failed.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
event: Connection failed event.
|
|
188
|
+
"""
|
|
140
189
|
self.logger.error(f"Connection failed: {event.reason}")
|
|
141
190
|
|
|
142
191
|
def handle_connection_lost(self, event: ConnectionLostEvent) -> None:
|
|
143
|
-
"""Handle connection lost
|
|
192
|
+
"""Handle connection lost.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
event: Connection lost event.
|
|
196
|
+
"""
|
|
144
197
|
self.logger.warning(
|
|
145
198
|
f"Connection lost: {event.reason if hasattr(event, 'reason') else 'Unknown reason'}"
|
|
146
199
|
)
|
|
147
200
|
|
|
148
201
|
def handle_telegram_received(self, event: TelegramReceivedEvent) -> str:
|
|
149
|
-
"""Handle received telegram events
|
|
202
|
+
"""Handle received telegram events.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
event: Telegram received event.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Frame data from the event.
|
|
209
|
+
"""
|
|
150
210
|
self.logger.debug(
|
|
151
211
|
f"handle_telegram_received ENTERED with telegram: {event.telegram}"
|
|
152
212
|
)
|
|
@@ -176,10 +236,18 @@ class HomeKitService:
|
|
|
176
236
|
return event.frame
|
|
177
237
|
|
|
178
238
|
def dispatch_light_level_event(self, event: TelegramReceivedEvent) -> None:
|
|
179
|
-
|
|
239
|
+
"""Dispatch light level received event.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
event: Telegram received event.
|
|
243
|
+
"""
|
|
244
|
+
self.logger.debug("Light level Datapoint, parsing telegram.")
|
|
180
245
|
reply_telegram = self.telegram_service.parse_reply_telegram(event.frame)
|
|
181
246
|
self.logger.debug(
|
|
182
|
-
f"Parsed telegram:
|
|
247
|
+
f"Parsed telegram: "
|
|
248
|
+
f"serial={reply_telegram.serial_number}, "
|
|
249
|
+
f"type={reply_telegram.datapoint_type}, "
|
|
250
|
+
f"value={reply_telegram.data_value}"
|
|
183
251
|
)
|
|
184
252
|
self.logger.debug("About to dispatch LightLevelReceivedEvent")
|
|
185
253
|
self.event_bus.dispatch(
|
|
@@ -192,10 +260,18 @@ class HomeKitService:
|
|
|
192
260
|
self.logger.debug("LightLevelReceivedEvent dispatched successfully")
|
|
193
261
|
|
|
194
262
|
def dispatch_output_state_event(self, event: TelegramReceivedEvent) -> None:
|
|
195
|
-
|
|
263
|
+
"""Dispatch output state received event.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
event: Telegram received event.
|
|
267
|
+
"""
|
|
268
|
+
self.logger.debug("Module Read Datapoint, parsing telegram.")
|
|
196
269
|
reply_telegram = self.telegram_service.parse_reply_telegram(event.frame)
|
|
197
270
|
self.logger.debug(
|
|
198
|
-
f"Parsed telegram:
|
|
271
|
+
f"Parsed telegram: "
|
|
272
|
+
f"serial={reply_telegram.serial_number}, "
|
|
273
|
+
f"type={reply_telegram.datapoint_type}, "
|
|
274
|
+
f"value={reply_telegram.data_value}"
|
|
199
275
|
)
|
|
200
276
|
self.logger.debug("About to dispatch OutputStateReceivedEvent")
|
|
201
277
|
self.event_bus.dispatch(
|
|
@@ -210,7 +286,12 @@ class HomeKitService:
|
|
|
210
286
|
def dispatch_event_telegram_received_event(
|
|
211
287
|
self, event: TelegramReceivedEvent
|
|
212
288
|
) -> None:
|
|
213
|
-
|
|
289
|
+
"""Dispatch event telegram received event.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
event: Telegram received event.
|
|
293
|
+
"""
|
|
294
|
+
self.logger.debug("Event telegram received, parsing.")
|
|
214
295
|
|
|
215
296
|
# Parse event telegram to extract module information
|
|
216
297
|
event_telegram = self.telegram_service.parse_event_telegram(event.frame)
|
|
@@ -238,6 +319,11 @@ class HomeKitService:
|
|
|
238
319
|
self.logger.debug("ModuleStateChangedEvent dispatched successfully")
|
|
239
320
|
|
|
240
321
|
def dispatch_module_discovered_event(self, event: TelegramReceivedEvent) -> None:
|
|
322
|
+
"""Dispatch module discovered event.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
event: Telegram received event.
|
|
326
|
+
"""
|
|
241
327
|
self.logger.debug("Module discovered, dispatching ModuleDiscoveredEvent")
|
|
242
328
|
self.event_bus.dispatch(
|
|
243
329
|
ModuleDiscoveredEvent(
|
|
@@ -253,6 +339,14 @@ class HomeKitService:
|
|
|
253
339
|
self.logger.debug("ModuleDiscoveredEvent dispatched successfully")
|
|
254
340
|
|
|
255
341
|
def handle_module_discovered(self, event: ModuleDiscoveredEvent) -> str:
|
|
342
|
+
"""Handle module discovered event.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
event: Module discovered event.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
Serial number of the discovered module.
|
|
349
|
+
"""
|
|
256
350
|
self.logger.debug("Handling module discovered event")
|
|
257
351
|
|
|
258
352
|
# Replace R with S and F01D with F02D00
|
xp/services/log_file_service.py
CHANGED
|
@@ -15,7 +15,7 @@ from xp.utils.time_utils import (
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class LogFileParsingError(Exception):
|
|
18
|
-
"""Raised when log file parsing fails"""
|
|
18
|
+
"""Raised when log file parsing fails."""
|
|
19
19
|
|
|
20
20
|
pass
|
|
21
21
|
|
|
@@ -26,6 +26,10 @@ class LogFileService:
|
|
|
26
26
|
|
|
27
27
|
Handles parsing of log files containing timestamped telegram transmissions
|
|
28
28
|
and receptions with automatic telegram parsing and validation.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
telegram_service: Telegram service for parsing telegrams.
|
|
32
|
+
LOG_LINE_PATTERN: Regex pattern for log line format.
|
|
29
33
|
"""
|
|
30
34
|
|
|
31
35
|
# Regex pattern for log line format: HH:MM:SS,mmm [TX/RX] <telegram>
|
|
@@ -34,29 +38,27 @@ class LogFileService:
|
|
|
34
38
|
)
|
|
35
39
|
|
|
36
40
|
def __init__(self, telegram_service: TelegramService):
|
|
37
|
-
"""
|
|
38
|
-
Initialize the log file service
|
|
41
|
+
"""Initialize the log file service.
|
|
39
42
|
|
|
40
43
|
Args:
|
|
41
|
-
telegram_service: Telegram service for parsing telegrams
|
|
44
|
+
telegram_service: Telegram service for parsing telegrams.
|
|
42
45
|
"""
|
|
43
46
|
self.telegram_service = telegram_service
|
|
44
47
|
|
|
45
48
|
def parse_log_file(
|
|
46
49
|
self, file_path: str, base_date: Optional[datetime] = None
|
|
47
50
|
) -> List[LogEntry]:
|
|
48
|
-
"""
|
|
49
|
-
Parse a console bus log file into LogEntry objects
|
|
51
|
+
"""Parse a console bus log file into LogEntry objects.
|
|
50
52
|
|
|
51
53
|
Args:
|
|
52
|
-
file_path: Path to the log file
|
|
53
|
-
base_date: Base date for timestamps (defaults to today)
|
|
54
|
+
file_path: Path to the log file.
|
|
55
|
+
base_date: Base date for timestamps (defaults to today).
|
|
54
56
|
|
|
55
57
|
Returns:
|
|
56
|
-
List of parsed LogEntry objects
|
|
58
|
+
List of parsed LogEntry objects.
|
|
57
59
|
|
|
58
60
|
Raises:
|
|
59
|
-
LogFileParsingError: If file cannot be read or parsed
|
|
61
|
+
LogFileParsingError: If file cannot be read or parsed.
|
|
60
62
|
"""
|
|
61
63
|
try:
|
|
62
64
|
path = Path(file_path)
|
|
@@ -77,15 +79,14 @@ class LogFileService:
|
|
|
77
79
|
def parse_log_lines(
|
|
78
80
|
self, lines: List[str], base_date: Optional[datetime] = None
|
|
79
81
|
) -> List[LogEntry]:
|
|
80
|
-
"""
|
|
81
|
-
Parse log lines into LogEntry objects
|
|
82
|
+
"""Parse log lines into LogEntry objects.
|
|
82
83
|
|
|
83
84
|
Args:
|
|
84
|
-
lines: List of log lines to parse
|
|
85
|
-
base_date: Base date for timestamps
|
|
85
|
+
lines: List of log lines to parse.
|
|
86
|
+
base_date: Base date for timestamps.
|
|
86
87
|
|
|
87
88
|
Returns:
|
|
88
|
-
List of parsed LogEntry objects
|
|
89
|
+
List of parsed LogEntry objects.
|
|
89
90
|
"""
|
|
90
91
|
entries = []
|
|
91
92
|
|
|
@@ -114,16 +115,15 @@ class LogFileService:
|
|
|
114
115
|
def _parse_log_line(
|
|
115
116
|
self, line: str, line_number: int, base_date: Optional[datetime] = None
|
|
116
117
|
) -> Optional[LogEntry]:
|
|
117
|
-
"""
|
|
118
|
-
Parse a single log line into a LogEntry
|
|
118
|
+
"""Parse a single log line into a LogEntry.
|
|
119
119
|
|
|
120
120
|
Args:
|
|
121
|
-
line: Log line to parse
|
|
122
|
-
line_number: Line number in the file
|
|
123
|
-
base_date: Base date for timestamp
|
|
121
|
+
line: Log line to parse.
|
|
122
|
+
line_number: Line number in the file.
|
|
123
|
+
base_date: Base date for timestamp.
|
|
124
124
|
|
|
125
125
|
Returns:
|
|
126
|
-
LogEntry object or None if line format is invalid
|
|
126
|
+
LogEntry object or None if line format is invalid.
|
|
127
127
|
"""
|
|
128
128
|
match = self.LOG_LINE_PATTERN.match(line)
|
|
129
129
|
if not match:
|
|
@@ -157,14 +157,13 @@ class LogFileService:
|
|
|
157
157
|
return entry
|
|
158
158
|
|
|
159
159
|
def validate_log_format(self, file_path: str) -> bool:
|
|
160
|
-
"""
|
|
161
|
-
Validate that a file follows the expected log format
|
|
160
|
+
"""Validate that a file follows the expected log format.
|
|
162
161
|
|
|
163
162
|
Args:
|
|
164
|
-
file_path: Path to the log file
|
|
163
|
+
file_path: Path to the log file.
|
|
165
164
|
|
|
166
165
|
Returns:
|
|
167
|
-
True if format is valid, False otherwise
|
|
166
|
+
True if format is valid, False otherwise.
|
|
168
167
|
"""
|
|
169
168
|
try:
|
|
170
169
|
entries = self.parse_log_file(file_path)
|
|
@@ -175,28 +174,26 @@ class LogFileService:
|
|
|
175
174
|
return False
|
|
176
175
|
|
|
177
176
|
def extract_telegrams(self, file_path: str) -> List[str]:
|
|
178
|
-
"""
|
|
179
|
-
Extract all telegram strings from a log file
|
|
177
|
+
"""Extract all telegram strings from a log file.
|
|
180
178
|
|
|
181
179
|
Args:
|
|
182
|
-
file_path: Path to the log file
|
|
180
|
+
file_path: Path to the log file.
|
|
183
181
|
|
|
184
182
|
Returns:
|
|
185
|
-
List of telegram strings
|
|
183
|
+
List of telegram strings.
|
|
186
184
|
"""
|
|
187
185
|
entries = self.parse_log_file(file_path)
|
|
188
186
|
return [entry.raw_telegram for entry in entries]
|
|
189
187
|
|
|
190
188
|
@staticmethod
|
|
191
189
|
def get_file_statistics(entries: List[LogEntry]) -> Dict[str, Any]:
|
|
192
|
-
"""
|
|
193
|
-
Generate statistics for a list of log entries
|
|
190
|
+
"""Generate statistics for a list of log entries.
|
|
194
191
|
|
|
195
192
|
Args:
|
|
196
|
-
entries: List of LogEntry objects
|
|
193
|
+
entries: List of LogEntry objects.
|
|
197
194
|
|
|
198
195
|
Returns:
|
|
199
|
-
Dictionary containing statistics
|
|
196
|
+
Dictionary containing statistics.
|
|
200
197
|
"""
|
|
201
198
|
if not entries:
|
|
202
199
|
return {"total_entries": 0}
|
|
@@ -283,18 +280,17 @@ class LogFileService:
|
|
|
283
280
|
start_time: Optional[datetime] = None,
|
|
284
281
|
end_time: Optional[datetime] = None,
|
|
285
282
|
) -> List[LogEntry]:
|
|
286
|
-
"""
|
|
287
|
-
Filter log entries based on criteria
|
|
283
|
+
"""Filter log entries based on criteria.
|
|
288
284
|
|
|
289
285
|
Args:
|
|
290
|
-
entries: List of LogEntry objects to filter
|
|
291
|
-
telegram_type: Filter by telegram type (event, system, reply)
|
|
292
|
-
direction: Filter by direction (TX, RX)
|
|
293
|
-
start_time: Filter entries after this time
|
|
294
|
-
end_time: Filter entries before this time
|
|
286
|
+
entries: List of LogEntry objects to filter.
|
|
287
|
+
telegram_type: Filter by telegram type (event, system, reply).
|
|
288
|
+
direction: Filter by direction (TX, RX).
|
|
289
|
+
start_time: Filter entries after this time.
|
|
290
|
+
end_time: Filter entries before this time.
|
|
295
291
|
|
|
296
292
|
Returns:
|
|
297
|
-
Filtered list of LogEntry objects
|
|
293
|
+
Filtered list of LogEntry objects.
|
|
298
294
|
"""
|
|
299
295
|
filtered = entries.copy()
|
|
300
296
|
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""Module Type Service for XP module management.
|
|
2
|
+
|
|
3
|
+
This module provides lookup, validation, and search functionality for XP system module types.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
from typing import Dict, List, Optional, Union
|
|
2
7
|
|
|
3
8
|
from xp.models.telegram.module_type import (
|
|
@@ -9,7 +14,7 @@ from xp.models.telegram.module_type import (
|
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
class ModuleTypeNotFoundError(Exception):
|
|
12
|
-
"""Raised when a module type cannot be found"""
|
|
17
|
+
"""Raised when a module type cannot be found."""
|
|
13
18
|
|
|
14
19
|
pass
|
|
15
20
|
|
|
@@ -17,11 +22,12 @@ class ModuleTypeNotFoundError(Exception):
|
|
|
17
22
|
class ModuleTypeService:
|
|
18
23
|
"""
|
|
19
24
|
Service for managing module type operations.
|
|
25
|
+
|
|
20
26
|
Provides lookup, validation, and search functionality for XP system module types.
|
|
21
27
|
"""
|
|
22
28
|
|
|
23
29
|
def __init__(self) -> None:
|
|
24
|
-
"""Initialize the module type service"""
|
|
30
|
+
"""Initialize the module type service."""
|
|
25
31
|
pass
|
|
26
32
|
|
|
27
33
|
@staticmethod
|
|
@@ -193,7 +199,14 @@ class ModuleTypeService:
|
|
|
193
199
|
|
|
194
200
|
@staticmethod
|
|
195
201
|
def _format_module_summary(module_type: ModuleType) -> str:
|
|
196
|
-
"""Format a single module type for display
|
|
202
|
+
"""Format a single module type for display.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
module_type: The module type to format.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Formatted string with module information.
|
|
209
|
+
"""
|
|
197
210
|
summary = f"Module: {module_type.name} (Code {module_type.code})\n"
|
|
198
211
|
summary += f"Description: {module_type.description}\n"
|
|
199
212
|
summary += f"Category: {module_type.category}\n"
|
|
@@ -213,7 +226,11 @@ class ModuleTypeService:
|
|
|
213
226
|
|
|
214
227
|
@staticmethod
|
|
215
228
|
def _format_all_modules() -> str:
|
|
216
|
-
"""Format all modules in a simple list
|
|
229
|
+
"""Format all modules in a simple list.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Formatted string with all modules.
|
|
233
|
+
"""
|
|
217
234
|
modules = get_all_module_types()
|
|
218
235
|
lines = ["Code | Name | Description", "-" * 60]
|
|
219
236
|
|
|
@@ -224,7 +241,11 @@ class ModuleTypeService:
|
|
|
224
241
|
|
|
225
242
|
@staticmethod
|
|
226
243
|
def _format_modules_by_category() -> str:
|
|
227
|
-
"""Format modules grouped by category
|
|
244
|
+
"""Format modules grouped by category.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Formatted string with modules grouped by category.
|
|
248
|
+
"""
|
|
228
249
|
categories = get_module_types_by_category()
|
|
229
250
|
lines = []
|
|
230
251
|
|
xp/services/protocol/__init__.py
CHANGED