conson-xp 1.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- conson_xp-1.18.0.dist-info/METADATA +412 -0
- conson_xp-1.18.0.dist-info/RECORD +176 -0
- conson_xp-1.18.0.dist-info/WHEEL +4 -0
- conson_xp-1.18.0.dist-info/entry_points.txt +5 -0
- conson_xp-1.18.0.dist-info/licenses/LICENSE +29 -0
- xp/__init__.py +9 -0
- xp/cli/__init__.py +5 -0
- xp/cli/__main__.py +6 -0
- xp/cli/commands/__init__.py +153 -0
- xp/cli/commands/conbus/__init__.py +25 -0
- xp/cli/commands/conbus/conbus.py +128 -0
- xp/cli/commands/conbus/conbus_actiontable_commands.py +233 -0
- xp/cli/commands/conbus/conbus_autoreport_commands.py +108 -0
- xp/cli/commands/conbus/conbus_blink_commands.py +163 -0
- xp/cli/commands/conbus/conbus_config_commands.py +29 -0
- xp/cli/commands/conbus/conbus_custom_commands.py +57 -0
- xp/cli/commands/conbus/conbus_datapoint_commands.py +113 -0
- xp/cli/commands/conbus/conbus_discover_commands.py +61 -0
- xp/cli/commands/conbus/conbus_event_commands.py +81 -0
- xp/cli/commands/conbus/conbus_lightlevel_commands.py +207 -0
- xp/cli/commands/conbus/conbus_linknumber_commands.py +102 -0
- xp/cli/commands/conbus/conbus_modulenumber_commands.py +104 -0
- xp/cli/commands/conbus/conbus_msactiontable_commands.py +94 -0
- xp/cli/commands/conbus/conbus_output_commands.py +163 -0
- xp/cli/commands/conbus/conbus_raw_commands.py +62 -0
- xp/cli/commands/conbus/conbus_receive_commands.py +59 -0
- xp/cli/commands/conbus/conbus_scan_commands.py +58 -0
- xp/cli/commands/file_commands.py +186 -0
- xp/cli/commands/homekit/__init__.py +3 -0
- xp/cli/commands/homekit/homekit.py +118 -0
- xp/cli/commands/homekit/homekit_start_commands.py +43 -0
- xp/cli/commands/module_commands.py +187 -0
- xp/cli/commands/reverse_proxy_commands.py +178 -0
- xp/cli/commands/server/__init__.py +3 -0
- xp/cli/commands/server/server_commands.py +135 -0
- xp/cli/commands/telegram/__init__.py +5 -0
- xp/cli/commands/telegram/telegram.py +41 -0
- xp/cli/commands/telegram/telegram_blink_commands.py +79 -0
- xp/cli/commands/telegram/telegram_checksum_commands.py +112 -0
- xp/cli/commands/telegram/telegram_discover_commands.py +41 -0
- xp/cli/commands/telegram/telegram_linknumber_commands.py +86 -0
- xp/cli/commands/telegram/telegram_parse_commands.py +75 -0
- xp/cli/commands/telegram/telegram_version_commands.py +52 -0
- xp/cli/main.py +87 -0
- xp/cli/utils/__init__.py +1 -0
- xp/cli/utils/click_tree.py +57 -0
- xp/cli/utils/datapoint_type_choice.py +57 -0
- xp/cli/utils/decorators.py +351 -0
- xp/cli/utils/error_handlers.py +201 -0
- xp/cli/utils/formatters.py +312 -0
- xp/cli/utils/module_type_choice.py +56 -0
- xp/cli/utils/serial_number_type.py +52 -0
- xp/cli/utils/system_function_choice.py +57 -0
- xp/cli/utils/xp_module_type.py +53 -0
- xp/connection/__init__.py +13 -0
- xp/connection/exceptions.py +22 -0
- xp/models/__init__.py +36 -0
- xp/models/actiontable/__init__.py +1 -0
- xp/models/actiontable/actiontable.py +43 -0
- xp/models/actiontable/msactiontable_xp20.py +53 -0
- xp/models/actiontable/msactiontable_xp24.py +58 -0
- xp/models/actiontable/msactiontable_xp33.py +65 -0
- xp/models/conbus/__init__.py +1 -0
- xp/models/conbus/conbus.py +87 -0
- xp/models/conbus/conbus_autoreport.py +67 -0
- xp/models/conbus/conbus_blink.py +80 -0
- xp/models/conbus/conbus_client_config.py +55 -0
- xp/models/conbus/conbus_connection_status.py +40 -0
- xp/models/conbus/conbus_custom.py +58 -0
- xp/models/conbus/conbus_datapoint.py +89 -0
- xp/models/conbus/conbus_discover.py +64 -0
- xp/models/conbus/conbus_event_raw.py +47 -0
- xp/models/conbus/conbus_lightlevel.py +52 -0
- xp/models/conbus/conbus_linknumber.py +54 -0
- xp/models/conbus/conbus_output.py +57 -0
- xp/models/conbus/conbus_raw.py +45 -0
- xp/models/conbus/conbus_receive.py +42 -0
- xp/models/conbus/conbus_writeconfig.py +60 -0
- xp/models/homekit/__init__.py +1 -0
- xp/models/homekit/homekit_accessory.py +35 -0
- xp/models/homekit/homekit_config.py +106 -0
- xp/models/homekit/homekit_conson_config.py +86 -0
- xp/models/log_entry.py +130 -0
- xp/models/protocol/__init__.py +1 -0
- xp/models/protocol/conbus_protocol.py +312 -0
- xp/models/response.py +42 -0
- xp/models/telegram/__init__.py +1 -0
- xp/models/telegram/action_type.py +31 -0
- xp/models/telegram/datapoint_type.py +82 -0
- xp/models/telegram/event_telegram.py +140 -0
- xp/models/telegram/event_type.py +15 -0
- xp/models/telegram/input_action_type.py +69 -0
- xp/models/telegram/input_type.py +17 -0
- xp/models/telegram/module_type.py +188 -0
- xp/models/telegram/module_type_code.py +205 -0
- xp/models/telegram/output_telegram.py +103 -0
- xp/models/telegram/reply_telegram.py +297 -0
- xp/models/telegram/system_function.py +116 -0
- xp/models/telegram/system_telegram.py +94 -0
- xp/models/telegram/telegram.py +28 -0
- xp/models/telegram/telegram_type.py +19 -0
- xp/models/telegram/timeparam_type.py +51 -0
- xp/models/write_config_type.py +33 -0
- xp/services/__init__.py +26 -0
- xp/services/actiontable/__init__.py +1 -0
- xp/services/actiontable/actiontable_serializer.py +273 -0
- xp/services/actiontable/msactiontable_serializer.py +7 -0
- xp/services/actiontable/msactiontable_xp20_serializer.py +169 -0
- xp/services/actiontable/msactiontable_xp24_serializer.py +120 -0
- xp/services/actiontable/msactiontable_xp33_serializer.py +239 -0
- xp/services/conbus/__init__.py +1 -0
- xp/services/conbus/actiontable/__init__.py +1 -0
- xp/services/conbus/actiontable/actiontable_download_service.py +158 -0
- xp/services/conbus/actiontable/actiontable_list_service.py +91 -0
- xp/services/conbus/actiontable/actiontable_show_service.py +89 -0
- xp/services/conbus/actiontable/actiontable_upload_service.py +211 -0
- xp/services/conbus/actiontable/msactiontable_service.py +232 -0
- xp/services/conbus/conbus_blink_all_service.py +181 -0
- xp/services/conbus/conbus_blink_service.py +158 -0
- xp/services/conbus/conbus_custom_service.py +156 -0
- xp/services/conbus/conbus_datapoint_queryall_service.py +182 -0
- xp/services/conbus/conbus_datapoint_service.py +170 -0
- xp/services/conbus/conbus_discover_service.py +312 -0
- xp/services/conbus/conbus_event_raw_service.py +181 -0
- xp/services/conbus/conbus_output_service.py +194 -0
- xp/services/conbus/conbus_raw_service.py +122 -0
- xp/services/conbus/conbus_receive_service.py +115 -0
- xp/services/conbus/conbus_scan_service.py +150 -0
- xp/services/conbus/write_config_service.py +194 -0
- xp/services/homekit/__init__.py +1 -0
- xp/services/homekit/homekit_cache_service.py +307 -0
- xp/services/homekit/homekit_conbus_service.py +93 -0
- xp/services/homekit/homekit_config_validator.py +310 -0
- xp/services/homekit/homekit_conson_validator.py +121 -0
- xp/services/homekit/homekit_dimminglight.py +182 -0
- xp/services/homekit/homekit_dimminglight_service.py +148 -0
- xp/services/homekit/homekit_hap_service.py +342 -0
- xp/services/homekit/homekit_lightbulb.py +120 -0
- xp/services/homekit/homekit_lightbulb_service.py +86 -0
- xp/services/homekit/homekit_module_service.py +56 -0
- xp/services/homekit/homekit_outlet.py +168 -0
- xp/services/homekit/homekit_outlet_service.py +121 -0
- xp/services/homekit/homekit_service.py +359 -0
- xp/services/log_file_service.py +309 -0
- xp/services/module_type_service.py +257 -0
- xp/services/protocol/__init__.py +21 -0
- xp/services/protocol/conbus_event_protocol.py +360 -0
- xp/services/protocol/conbus_protocol.py +318 -0
- xp/services/protocol/protocol_factory.py +78 -0
- xp/services/protocol/telegram_protocol.py +264 -0
- xp/services/reverse_proxy_service.py +435 -0
- xp/services/server/__init__.py +1 -0
- xp/services/server/base_server_service.py +366 -0
- xp/services/server/cp20_server_service.py +65 -0
- xp/services/server/device_service_factory.py +94 -0
- xp/services/server/server_service.py +428 -0
- xp/services/server/xp130_server_service.py +67 -0
- xp/services/server/xp20_server_service.py +92 -0
- xp/services/server/xp230_server_service.py +58 -0
- xp/services/server/xp24_server_service.py +245 -0
- xp/services/server/xp33_server_service.py +535 -0
- xp/services/telegram/__init__.py +1 -0
- xp/services/telegram/telegram_blink_service.py +138 -0
- xp/services/telegram/telegram_checksum_service.py +149 -0
- xp/services/telegram/telegram_datapoint_service.py +82 -0
- xp/services/telegram/telegram_discover_service.py +277 -0
- xp/services/telegram/telegram_link_number_service.py +216 -0
- xp/services/telegram/telegram_output_service.py +322 -0
- xp/services/telegram/telegram_service.py +380 -0
- xp/services/telegram/telegram_version_service.py +288 -0
- xp/utils/__init__.py +12 -0
- xp/utils/checksum.py +61 -0
- xp/utils/dependencies.py +531 -0
- xp/utils/event_helper.py +31 -0
- xp/utils/serialization.py +205 -0
- xp/utils/time_utils.py +134 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Conbus raw telegram CLI commands."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from click import Context
|
|
7
|
+
|
|
8
|
+
from xp.cli.commands.conbus.conbus import conbus
|
|
9
|
+
from xp.cli.utils.decorators import (
|
|
10
|
+
connection_command,
|
|
11
|
+
)
|
|
12
|
+
from xp.models.conbus.conbus_raw import ConbusRawResponse
|
|
13
|
+
from xp.services.conbus.conbus_raw_service import ConbusRawService
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@conbus.command("raw")
|
|
17
|
+
@click.argument("raw_telegrams")
|
|
18
|
+
@click.pass_context
|
|
19
|
+
@connection_command()
|
|
20
|
+
def send_raw_telegrams(ctx: Context, raw_telegrams: str) -> None:
|
|
21
|
+
r"""Send raw telegram sequence to Conbus server.
|
|
22
|
+
|
|
23
|
+
Accepts a string containing one or more telegrams in format <...>.
|
|
24
|
+
Multiple telegrams should be concatenated without separators.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
ctx: Click context object.
|
|
28
|
+
raw_telegrams: Raw telegram string(s).
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
\b
|
|
32
|
+
xp conbus raw '<S2113010000F02D12>'
|
|
33
|
+
xp conbus raw '<S2113010000F02D12><S2113010001F02D12><S2113010002F02D12>'
|
|
34
|
+
xp conbus raw '<S0012345003F02D12FM>...<S0012345009F02D12FF>'
|
|
35
|
+
"""
|
|
36
|
+
service: ConbusRawService = (
|
|
37
|
+
ctx.obj.get("container").get_container().resolve(ConbusRawService)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def on_progress(message: str) -> None:
|
|
41
|
+
"""Handle progress updates during raw telegram sending.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
message: Progress message string.
|
|
45
|
+
"""
|
|
46
|
+
click.echo(message)
|
|
47
|
+
|
|
48
|
+
def on_finish(service_response: ConbusRawResponse) -> None:
|
|
49
|
+
"""Handle successful completion of raw telegram sending.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
service_response: Raw response object.
|
|
53
|
+
"""
|
|
54
|
+
click.echo(json.dumps(service_response.to_dict(), indent=2))
|
|
55
|
+
|
|
56
|
+
with service:
|
|
57
|
+
service.send_raw_telegram(
|
|
58
|
+
raw_input=raw_telegrams,
|
|
59
|
+
progress_callback=on_progress,
|
|
60
|
+
finish_callback=on_finish,
|
|
61
|
+
timeout_seconds=5.0,
|
|
62
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Conbus receive telegrams CLI commands."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from click import Context
|
|
7
|
+
|
|
8
|
+
from xp.cli.commands.conbus.conbus import conbus
|
|
9
|
+
from xp.cli.utils.decorators import (
|
|
10
|
+
connection_command,
|
|
11
|
+
)
|
|
12
|
+
from xp.models.conbus.conbus_receive import ConbusReceiveResponse
|
|
13
|
+
from xp.services.conbus.conbus_receive_service import (
|
|
14
|
+
ConbusReceiveService,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@conbus.command("receive")
|
|
19
|
+
@click.argument("timeout", type=click.FLOAT, default=2.0)
|
|
20
|
+
@connection_command()
|
|
21
|
+
@click.pass_context
|
|
22
|
+
def receive_telegrams(ctx: Context, timeout: float) -> None:
|
|
23
|
+
r"""Receive waiting event telegrams from Conbus server.
|
|
24
|
+
|
|
25
|
+
Connects to the Conbus server and receives any waiting event telegrams
|
|
26
|
+
without sending any data first. Useful for collecting pending notifications
|
|
27
|
+
or events from the server.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
ctx: Click context object.
|
|
31
|
+
timeout: Timeout in seconds for receiving telegrams (default: 2.0).
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
\b
|
|
35
|
+
xp conbus receive
|
|
36
|
+
xp conbus receive 5.0
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def on_finish(response_received: ConbusReceiveResponse) -> None:
|
|
40
|
+
"""Handle successful completion of telegram receive operation.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
response_received: Receive response object with telegrams.
|
|
44
|
+
"""
|
|
45
|
+
click.echo(json.dumps(response_received.to_dict(), indent=2))
|
|
46
|
+
|
|
47
|
+
def progress(telegram_received: str) -> None:
|
|
48
|
+
"""Handle progress updates during telegram receive operation.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
telegram_received: Received telegram string.
|
|
52
|
+
"""
|
|
53
|
+
click.echo(telegram_received)
|
|
54
|
+
|
|
55
|
+
service: ConbusReceiveService = (
|
|
56
|
+
ctx.obj.get("container").get_container().resolve(ConbusReceiveService)
|
|
57
|
+
)
|
|
58
|
+
with service:
|
|
59
|
+
service.start(progress, on_finish, timeout)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Conbus client operations CLI commands."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from click import Context
|
|
7
|
+
|
|
8
|
+
from xp.cli.commands.conbus.conbus import conbus
|
|
9
|
+
from xp.cli.utils.decorators import connection_command
|
|
10
|
+
from xp.cli.utils.serial_number_type import SERIAL
|
|
11
|
+
from xp.models import ConbusResponse
|
|
12
|
+
from xp.services.conbus.conbus_scan_service import ConbusScanService
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@conbus.command("scan")
|
|
16
|
+
@click.argument("serial_number", type=SERIAL)
|
|
17
|
+
@click.argument("function_code", type=str)
|
|
18
|
+
@click.pass_context
|
|
19
|
+
@connection_command()
|
|
20
|
+
def scan_module(ctx: Context, serial_number: str, function_code: str) -> None:
|
|
21
|
+
r"""Scan all datapoints of a function_code for a module.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
ctx: Click context object.
|
|
25
|
+
serial_number: 10-digit module serial number.
|
|
26
|
+
function_code: Function code.
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
\b
|
|
30
|
+
xp conbus scan 0012345011 02 # Scan all datapoints of function Read data points (02)
|
|
31
|
+
"""
|
|
32
|
+
service: ConbusScanService = (
|
|
33
|
+
ctx.obj.get("container").get_container().resolve(ConbusScanService)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def on_progress(progress: str) -> None:
|
|
37
|
+
"""Handle progress updates during module scan.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
progress: Progress message string.
|
|
41
|
+
"""
|
|
42
|
+
click.echo(progress)
|
|
43
|
+
|
|
44
|
+
def on_finish(service_response: ConbusResponse) -> None:
|
|
45
|
+
"""Handle successful completion of module scan.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
service_response: Scan response object.
|
|
49
|
+
"""
|
|
50
|
+
click.echo(json.dumps(service_response.to_dict(), indent=2))
|
|
51
|
+
|
|
52
|
+
with service:
|
|
53
|
+
service.scan_module(
|
|
54
|
+
serial_number=serial_number,
|
|
55
|
+
function_code=function_code,
|
|
56
|
+
progress_callback=on_progress,
|
|
57
|
+
finish_callback=on_finish,
|
|
58
|
+
)
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""File operations CLI commands for console bus logs."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from click import Context
|
|
7
|
+
from click_help_colors import HelpColorsGroup
|
|
8
|
+
|
|
9
|
+
from xp.cli.utils.decorators import (
|
|
10
|
+
file_operation_command,
|
|
11
|
+
handle_service_errors,
|
|
12
|
+
)
|
|
13
|
+
from xp.cli.utils.error_handlers import CLIErrorHandler
|
|
14
|
+
from xp.cli.utils.formatters import OutputFormatter, StatisticsFormatter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.group(
|
|
18
|
+
cls=HelpColorsGroup, help_headers_color="yellow", help_options_color="green"
|
|
19
|
+
)
|
|
20
|
+
def file() -> None:
|
|
21
|
+
"""Perform file operations for console bus logs."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@file.command("decode")
|
|
26
|
+
@click.argument("log_file_path")
|
|
27
|
+
@click.option("--summary", is_flag=True, help="Show summary statistics only")
|
|
28
|
+
@click.pass_context
|
|
29
|
+
@file_operation_command()
|
|
30
|
+
@handle_service_errors(Exception)
|
|
31
|
+
def decode_log_file(
|
|
32
|
+
ctx: Context,
|
|
33
|
+
log_file_path: str,
|
|
34
|
+
filter_type: str,
|
|
35
|
+
filter_direction: str,
|
|
36
|
+
time_range: str,
|
|
37
|
+
summary: bool,
|
|
38
|
+
) -> None:
|
|
39
|
+
r"""Decode and parse console bus log file.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
ctx: Click context object.
|
|
43
|
+
log_file_path: Path to the log file to decode.
|
|
44
|
+
filter_type: Filter by telegram type.
|
|
45
|
+
filter_direction: Filter by telegram direction.
|
|
46
|
+
time_range: Filter by time range.
|
|
47
|
+
summary: Show summary statistics only.
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
\b
|
|
51
|
+
xp file decode conbus.log
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
SystemExit: If time range is invalid or log file cannot be parsed.
|
|
55
|
+
"""
|
|
56
|
+
from xp.services.log_file_service import LogFileService
|
|
57
|
+
from xp.utils.time_utils import TimeParsingError, parse_time_range
|
|
58
|
+
|
|
59
|
+
service: LogFileService = (
|
|
60
|
+
ctx.obj.get("container").get_container().resolve(LogFileService)
|
|
61
|
+
)
|
|
62
|
+
StatisticsFormatter(True)
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Parse the log file
|
|
66
|
+
entries = service.parse_log_file(log_file_path)
|
|
67
|
+
|
|
68
|
+
# Apply filters
|
|
69
|
+
if filter_type or filter_direction or time_range:
|
|
70
|
+
start_time = None
|
|
71
|
+
end_time = None
|
|
72
|
+
|
|
73
|
+
if time_range:
|
|
74
|
+
try:
|
|
75
|
+
start_time, end_time = parse_time_range(time_range)
|
|
76
|
+
except TimeParsingError as e:
|
|
77
|
+
error_response = OutputFormatter(True).error_response(
|
|
78
|
+
f"Invalid time range: {e}"
|
|
79
|
+
)
|
|
80
|
+
click.echo(error_response)
|
|
81
|
+
raise SystemExit(1)
|
|
82
|
+
|
|
83
|
+
entries = service.filter_entries(
|
|
84
|
+
entries,
|
|
85
|
+
telegram_type=filter_type,
|
|
86
|
+
direction=filter_direction,
|
|
87
|
+
start_time=start_time,
|
|
88
|
+
end_time=end_time,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Generate statistics
|
|
92
|
+
stats = service.get_file_statistics(entries)
|
|
93
|
+
|
|
94
|
+
if summary:
|
|
95
|
+
# Show summary only
|
|
96
|
+
click.echo(
|
|
97
|
+
json.dumps({"statistics": stats, "entry_count": len(entries)}, indent=2)
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
# Show full results
|
|
101
|
+
output = {
|
|
102
|
+
"file_path": log_file_path,
|
|
103
|
+
"statistics": stats,
|
|
104
|
+
"entries": [entry.to_dict() for entry in entries],
|
|
105
|
+
}
|
|
106
|
+
click.echo(json.dumps(output, indent=2))
|
|
107
|
+
|
|
108
|
+
except Exception as e:
|
|
109
|
+
CLIErrorHandler.handle_file_error(e, log_file_path, "log file parsing")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@file.command("analyze")
|
|
113
|
+
@click.argument("log_file_path")
|
|
114
|
+
@click.pass_context
|
|
115
|
+
@handle_service_errors(Exception)
|
|
116
|
+
def analyze_log_file(ctx: Context, log_file_path: str) -> None:
|
|
117
|
+
r"""Analyze console bus log file for patterns and statistics.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
ctx: Click context object.
|
|
121
|
+
log_file_path: Path to the log file to analyze.
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
\b
|
|
125
|
+
xp file analyze conbus.log
|
|
126
|
+
"""
|
|
127
|
+
from xp.services.log_file_service import LogFileService
|
|
128
|
+
|
|
129
|
+
service: LogFileService = (
|
|
130
|
+
ctx.obj.get("container").get_container().resolve(LogFileService)
|
|
131
|
+
)
|
|
132
|
+
StatisticsFormatter(True)
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
entries = service.parse_log_file(log_file_path)
|
|
136
|
+
stats = service.get_file_statistics(entries)
|
|
137
|
+
|
|
138
|
+
click.echo(
|
|
139
|
+
json.dumps({"file_path": log_file_path, "analysis": stats}, indent=2)
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
except Exception as e:
|
|
143
|
+
CLIErrorHandler.handle_file_error(e, log_file_path, "log file analysis")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@file.command("validate")
|
|
147
|
+
@click.argument("log_file_path")
|
|
148
|
+
@click.pass_context
|
|
149
|
+
@handle_service_errors(Exception)
|
|
150
|
+
def validate_log_file(ctx: Context, log_file_path: str) -> None:
|
|
151
|
+
r"""Validate console bus log file format and telegram checksums.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
ctx: Click context object.
|
|
155
|
+
log_file_path: Path to the log file to validate.
|
|
156
|
+
|
|
157
|
+
Examples:
|
|
158
|
+
\b
|
|
159
|
+
xp file validate conbus.log
|
|
160
|
+
"""
|
|
161
|
+
from xp.services.log_file_service import LogFileService
|
|
162
|
+
|
|
163
|
+
service: LogFileService = (
|
|
164
|
+
ctx.obj.get("container").get_container().resolve(LogFileService)
|
|
165
|
+
)
|
|
166
|
+
OutputFormatter(True)
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
entries = service.parse_log_file(log_file_path)
|
|
170
|
+
stats = service.get_file_statistics(entries)
|
|
171
|
+
|
|
172
|
+
is_valid = stats["parse_errors"] == 0
|
|
173
|
+
checksum_issues = stats["checksum_validation"]["invalid_checksums"]
|
|
174
|
+
|
|
175
|
+
result = {
|
|
176
|
+
"file_path": log_file_path,
|
|
177
|
+
"valid_format": is_valid,
|
|
178
|
+
"parse_errors": stats["parse_errors"],
|
|
179
|
+
"checksum_issues": checksum_issues,
|
|
180
|
+
"statistics": stats,
|
|
181
|
+
"success": is_valid and checksum_issues == 0,
|
|
182
|
+
}
|
|
183
|
+
click.echo(json.dumps(result, indent=2))
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
CLIErrorHandler.handle_file_error(e, log_file_path, "log file validation")
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""HomeKit management CLI commands."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from click_help_colors import HelpColorsGroup
|
|
5
|
+
|
|
6
|
+
from xp.cli.utils.decorators import service_command
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group(
|
|
10
|
+
cls=HelpColorsGroup, help_headers_color="yellow", help_options_color="green"
|
|
11
|
+
)
|
|
12
|
+
def homekit() -> None:
|
|
13
|
+
"""Manage the HomeKit server for XP Protocol operations."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@homekit.group(
|
|
18
|
+
cls=HelpColorsGroup, help_headers_color="yellow", help_options_color="green"
|
|
19
|
+
)
|
|
20
|
+
def config() -> None:
|
|
21
|
+
"""Manage HomeKit configuration."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@config.command()
|
|
26
|
+
@click.option(
|
|
27
|
+
"--conson-config",
|
|
28
|
+
default="conson.yml",
|
|
29
|
+
help="Path to conson.yml configuration file",
|
|
30
|
+
)
|
|
31
|
+
@click.option(
|
|
32
|
+
"--homekit-config",
|
|
33
|
+
default="homekit.yml",
|
|
34
|
+
help="Path to homekit.yml configuration file",
|
|
35
|
+
)
|
|
36
|
+
@service_command()
|
|
37
|
+
def validate(conson_config: str, homekit_config: str) -> None:
|
|
38
|
+
"""Validate homekit.yml and conson.yml coherence.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
conson_config: Path to conson.yml configuration file.
|
|
42
|
+
homekit_config: Path to homekit.yml configuration file.
|
|
43
|
+
"""
|
|
44
|
+
from xp.services.homekit.homekit_config_validator import ConfigValidationService
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
validator = ConfigValidationService(conson_config, homekit_config)
|
|
48
|
+
results = validator.validate_all()
|
|
49
|
+
|
|
50
|
+
if results["is_valid"]:
|
|
51
|
+
click.echo(click.style("✓ Configuration validation passed", fg="green"))
|
|
52
|
+
else:
|
|
53
|
+
click.echo(
|
|
54
|
+
click.style(
|
|
55
|
+
f"✗ Configuration validation failed with {results['total_errors']} errors",
|
|
56
|
+
fg="red",
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if results["conson_errors"]:
|
|
61
|
+
click.echo(
|
|
62
|
+
click.style("\nConson Configuration Errors:", fg="red", bold=True)
|
|
63
|
+
)
|
|
64
|
+
for error in results["conson_errors"]:
|
|
65
|
+
click.echo(f" - {error}")
|
|
66
|
+
|
|
67
|
+
if results["homekit_errors"]:
|
|
68
|
+
click.echo(
|
|
69
|
+
click.style("\nHomeKit Configuration Errors:", fg="red", bold=True)
|
|
70
|
+
)
|
|
71
|
+
for error in results["homekit_errors"]:
|
|
72
|
+
click.echo(f" - {error}")
|
|
73
|
+
|
|
74
|
+
if results["cross_reference_errors"]:
|
|
75
|
+
click.echo(
|
|
76
|
+
click.style("\nCross-Reference Errors:", fg="red", bold=True)
|
|
77
|
+
)
|
|
78
|
+
for error in results["cross_reference_errors"]:
|
|
79
|
+
click.echo(f" - {error}")
|
|
80
|
+
|
|
81
|
+
exit(1)
|
|
82
|
+
|
|
83
|
+
except Exception as e:
|
|
84
|
+
click.echo(click.style(f"✗ Validation failed: {e}", fg="red"))
|
|
85
|
+
exit(1)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@config.command("show")
|
|
89
|
+
@click.option(
|
|
90
|
+
"--conson-config",
|
|
91
|
+
default="conson.yml",
|
|
92
|
+
help="Path to conson.yml configuration file",
|
|
93
|
+
)
|
|
94
|
+
@click.option(
|
|
95
|
+
"--homekit-config",
|
|
96
|
+
default="homekit.yml",
|
|
97
|
+
help="Path to homekit.yml configuration file",
|
|
98
|
+
)
|
|
99
|
+
@service_command()
|
|
100
|
+
def show_config(conson_config: str, homekit_config: str) -> None:
|
|
101
|
+
"""Display parsed configuration summary.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
conson_config: Path to conson.yml configuration file.
|
|
105
|
+
homekit_config: Path to homekit.yml configuration file.
|
|
106
|
+
"""
|
|
107
|
+
from xp.services.homekit.homekit_config_validator import ConfigValidationService
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
validator = ConfigValidationService(conson_config, homekit_config)
|
|
111
|
+
summary = validator.print_config_summary()
|
|
112
|
+
|
|
113
|
+
click.echo(click.style("Configuration Summary:", fg="blue", bold=True))
|
|
114
|
+
click.echo(summary)
|
|
115
|
+
|
|
116
|
+
except Exception as e:
|
|
117
|
+
click.echo(click.style(f"✗ Failed to load configuration: {e}", fg="red"))
|
|
118
|
+
exit(1)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""API server start command."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from click import Context
|
|
7
|
+
|
|
8
|
+
from xp.cli.commands.homekit.homekit import homekit
|
|
9
|
+
from xp.services.homekit.homekit_service import HomeKitService
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@homekit.command("start")
|
|
13
|
+
@click.pass_context
|
|
14
|
+
def homekit_start(ctx: Context) -> None:
|
|
15
|
+
r"""Start the HomeKit server.
|
|
16
|
+
|
|
17
|
+
This command starts the XP Protocol HomeKit server using HAP-python.
|
|
18
|
+
The server provides HomeKit endpoints for Conbus operations.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
ctx: Click context object.
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
\b
|
|
25
|
+
# Start server on default host and port
|
|
26
|
+
xp homekit start
|
|
27
|
+
"""
|
|
28
|
+
click.echo("Starting XP Protocol HomeKit server...")
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
service: HomeKitService = (
|
|
32
|
+
ctx.obj.get("container").get_container().resolve(HomeKitService)
|
|
33
|
+
)
|
|
34
|
+
service.start() # Blocking call - reactor.run() never returns
|
|
35
|
+
|
|
36
|
+
except KeyboardInterrupt:
|
|
37
|
+
click.echo("\nShutting down server...")
|
|
38
|
+
except Exception as e:
|
|
39
|
+
click.echo(
|
|
40
|
+
click.style(f"Error starting server: {e}", fg="red"),
|
|
41
|
+
err=True,
|
|
42
|
+
)
|
|
43
|
+
sys.exit(1)
|