conson-xp 1.18.0__py3-none-any.whl → 1.20.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 → conson_xp-1.20.0.dist-info}/METADATA +7 -1
- {conson_xp-1.18.0.dist-info → conson_xp-1.20.0.dist-info}/RECORD +27 -15
- {conson_xp-1.18.0.dist-info → conson_xp-1.20.0.dist-info}/WHEEL +1 -1
- xp/__init__.py +1 -1
- xp/cli/commands/__init__.py +4 -0
- xp/cli/commands/conbus/conbus_event_commands.py +25 -0
- xp/cli/commands/conbus/conbus_receive_commands.py +2 -1
- xp/cli/commands/term/__init__.py +5 -0
- xp/cli/commands/term/term.py +12 -0
- xp/cli/commands/term/term_commands.py +31 -0
- xp/cli/main.py +7 -35
- xp/models/__init__.py +2 -0
- xp/models/conbus/conbus_client_config.py +1 -0
- xp/models/conbus/conbus_event_list.py +34 -0
- xp/models/conbus/conbus_logger_config.py +107 -0
- xp/services/conbus/conbus_event_list_service.py +91 -0
- xp/services/conbus/conbus_receive_service.py +58 -30
- xp/services/protocol/conbus_event_protocol.py +28 -3
- xp/tui/__init__.py +1 -0
- xp/tui/app.py +72 -0
- xp/tui/protocol.tcss +50 -0
- xp/tui/widgets/__init__.py +1 -0
- xp/tui/widgets/protocol_log.py +312 -0
- xp/utils/dependencies.py +34 -6
- xp/utils/logging.py +91 -0
- {conson_xp-1.18.0.dist-info → conson_xp-1.20.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.18.0.dist-info → conson_xp-1.20.0.dist-info}/licenses/LICENSE +0 -0
xp/utils/dependencies.py
CHANGED
|
@@ -7,6 +7,7 @@ from twisted.internet.interfaces import IConnector
|
|
|
7
7
|
from twisted.internet.posixbase import PosixReactorBase
|
|
8
8
|
|
|
9
9
|
from xp.models import ConbusClientConfig
|
|
10
|
+
from xp.models.conbus.conbus_logger_config import ConbusLoggerConfig
|
|
10
11
|
from xp.models.homekit.homekit_config import HomekitConfig
|
|
11
12
|
from xp.models.homekit.homekit_conson_config import ConsonModuleListConfig
|
|
12
13
|
from xp.services.actiontable.actiontable_serializer import ActionTableSerializer
|
|
@@ -43,6 +44,7 @@ from xp.services.conbus.conbus_datapoint_service import (
|
|
|
43
44
|
ConbusDatapointService,
|
|
44
45
|
)
|
|
45
46
|
from xp.services.conbus.conbus_discover_service import ConbusDiscoverService
|
|
47
|
+
from xp.services.conbus.conbus_event_list_service import ConbusEventListService
|
|
46
48
|
from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
|
|
47
49
|
from xp.services.conbus.conbus_output_service import ConbusOutputService
|
|
48
50
|
from xp.services.conbus.conbus_raw_service import ConbusRawService
|
|
@@ -71,6 +73,7 @@ from xp.services.telegram.telegram_discover_service import TelegramDiscoverServi
|
|
|
71
73
|
from xp.services.telegram.telegram_link_number_service import LinkNumberService
|
|
72
74
|
from xp.services.telegram.telegram_output_service import TelegramOutputService
|
|
73
75
|
from xp.services.telegram.telegram_service import TelegramService
|
|
76
|
+
from xp.utils.logging import LoggerService
|
|
74
77
|
|
|
75
78
|
asyncioreactor.install()
|
|
76
79
|
from twisted.internet import reactor # noqa: E402
|
|
@@ -86,7 +89,8 @@ class ServiceContainer:
|
|
|
86
89
|
|
|
87
90
|
def __init__(
|
|
88
91
|
self,
|
|
89
|
-
|
|
92
|
+
client_config_path: str = "cli.yml",
|
|
93
|
+
logger_config_path: str = "logger.yml",
|
|
90
94
|
homekit_config_path: str = "homekit.yml",
|
|
91
95
|
conson_config_path: str = "conson.yml",
|
|
92
96
|
server_port: int = 10001,
|
|
@@ -96,14 +100,16 @@ class ServiceContainer:
|
|
|
96
100
|
Initialize the service container.
|
|
97
101
|
|
|
98
102
|
Args:
|
|
99
|
-
|
|
103
|
+
client_config_path: Path to the Conbus CLI configuration file
|
|
104
|
+
logger_config_path: Path to the Conbus Loggerr configuration file
|
|
100
105
|
homekit_config_path: Path to the HomeKit configuration file
|
|
101
106
|
conson_config_path: Path to the Conson configuration file
|
|
102
107
|
server_port: Port for the server service
|
|
103
108
|
reverse_proxy_port: Port for the reverse proxy service
|
|
104
109
|
"""
|
|
105
110
|
self.container = punq.Container()
|
|
106
|
-
self.
|
|
111
|
+
self._client_config_path = client_config_path
|
|
112
|
+
self._logger_config_path = logger_config_path
|
|
107
113
|
self._homekit_config_path = homekit_config_path
|
|
108
114
|
self._conson_config_path = conson_config_path
|
|
109
115
|
self._server_port = server_port
|
|
@@ -116,7 +122,13 @@ class ServiceContainer:
|
|
|
116
122
|
# ConbusClientConfig
|
|
117
123
|
self.container.register(
|
|
118
124
|
ConbusClientConfig,
|
|
119
|
-
factory=lambda: ConbusClientConfig.from_yaml(self.
|
|
125
|
+
factory=lambda: ConbusClientConfig.from_yaml(self._client_config_path),
|
|
126
|
+
scope=punq.Scope.singleton,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
self.container.register(
|
|
130
|
+
ConbusLoggerConfig,
|
|
131
|
+
factory=lambda: ConbusLoggerConfig.from_yaml(self._logger_config_path),
|
|
120
132
|
scope=punq.Scope.singleton,
|
|
121
133
|
)
|
|
122
134
|
|
|
@@ -189,6 +201,14 @@ class ServiceContainer:
|
|
|
189
201
|
scope=punq.Scope.singleton,
|
|
190
202
|
)
|
|
191
203
|
|
|
204
|
+
self.container.register(
|
|
205
|
+
ConbusEventListService,
|
|
206
|
+
factory=lambda: ConbusEventListService(
|
|
207
|
+
conson_config=self.container.resolve(ConsonModuleListConfig)
|
|
208
|
+
),
|
|
209
|
+
scope=punq.Scope.singleton,
|
|
210
|
+
)
|
|
211
|
+
|
|
192
212
|
self.container.register(
|
|
193
213
|
ConbusBlinkService,
|
|
194
214
|
factory=lambda: ConbusBlinkService(
|
|
@@ -323,8 +343,7 @@ class ServiceContainer:
|
|
|
323
343
|
self.container.register(
|
|
324
344
|
ConbusReceiveService,
|
|
325
345
|
factory=lambda: ConbusReceiveService(
|
|
326
|
-
|
|
327
|
-
reactor=self.container.resolve(PosixReactorBase),
|
|
346
|
+
conbus_protocol=self.container.resolve(ConbusEventProtocol)
|
|
328
347
|
),
|
|
329
348
|
scope=punq.Scope.singleton,
|
|
330
349
|
)
|
|
@@ -378,6 +397,15 @@ class ServiceContainer:
|
|
|
378
397
|
scope=punq.Scope.singleton,
|
|
379
398
|
)
|
|
380
399
|
|
|
400
|
+
# Logging
|
|
401
|
+
self.container.register(
|
|
402
|
+
LoggerService,
|
|
403
|
+
factory=lambda: LoggerService(
|
|
404
|
+
logger_config=self.container.resolve(ConbusLoggerConfig),
|
|
405
|
+
),
|
|
406
|
+
scope=punq.Scope.singleton,
|
|
407
|
+
)
|
|
408
|
+
|
|
381
409
|
# Module type services layer
|
|
382
410
|
self.container.register(ModuleTypeService, scope=punq.Scope.singleton)
|
|
383
411
|
|
xp/utils/logging.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Logging service for XP application."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from logging.handlers import RotatingFileHandler
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from xp.models.conbus.conbus_logger_config import ConbusLoggerConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LoggerService:
|
|
11
|
+
"""Service for managing logging configuration and setup."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, logger_config: ConbusLoggerConfig):
|
|
14
|
+
"""Initialize LoggerService with configuration.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
logger_config: Logger configuration object.
|
|
18
|
+
"""
|
|
19
|
+
self.logging_config = logger_config.log
|
|
20
|
+
self.logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
def setup(self) -> None:
|
|
23
|
+
"""Setup console and file logging with configured levels."""
|
|
24
|
+
# Setup file logging for term app
|
|
25
|
+
self.setup_console_logging(
|
|
26
|
+
self.logging_config.log_format, self.logging_config.date_format
|
|
27
|
+
)
|
|
28
|
+
self.setup_file_logging(
|
|
29
|
+
self.logging_config.log_format, self.logging_config.date_format
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
for module in self.logging_config.levels.keys():
|
|
33
|
+
logging.getLogger(module).setLevel(self.logging_config.levels[module])
|
|
34
|
+
|
|
35
|
+
def setup_console_logging(self, log_format: str, date_format: str) -> None:
|
|
36
|
+
"""Setup console logging with specified format.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
log_format: Log message format string.
|
|
40
|
+
date_format: Date format string for log timestamps.
|
|
41
|
+
"""
|
|
42
|
+
# Force format on root logger and all handlers
|
|
43
|
+
formatter = logging.Formatter(log_format, datefmt=date_format)
|
|
44
|
+
root_logger = logging.getLogger()
|
|
45
|
+
|
|
46
|
+
# Set log level from CLI argument
|
|
47
|
+
numeric_level = getattr(logging, self.logging_config.default_level.upper())
|
|
48
|
+
root_logger.setLevel(numeric_level)
|
|
49
|
+
|
|
50
|
+
# Update all existing handlers or create new one
|
|
51
|
+
if root_logger.handlers:
|
|
52
|
+
for handler in root_logger.handlers:
|
|
53
|
+
handler.setFormatter(formatter)
|
|
54
|
+
else:
|
|
55
|
+
handler = logging.StreamHandler()
|
|
56
|
+
handler.setFormatter(formatter)
|
|
57
|
+
root_logger.addHandler(handler)
|
|
58
|
+
|
|
59
|
+
def setup_file_logging(self, log_format: str, date_format: str) -> None:
|
|
60
|
+
"""Setup file logging with rotation for term application.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
log_format: Log message format string.
|
|
64
|
+
date_format: Date format string for log timestamps.
|
|
65
|
+
"""
|
|
66
|
+
log_path = Path(self.logging_config.path)
|
|
67
|
+
log_level = self.logging_config.default_level
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
# Create log directory if it doesn't exist
|
|
71
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
|
|
73
|
+
# Create rotating file handler
|
|
74
|
+
file_handler = RotatingFileHandler(
|
|
75
|
+
log_path,
|
|
76
|
+
maxBytes=self.logging_config.max_bytes,
|
|
77
|
+
backupCount=self.logging_config.backup_count,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Configure formatter to match console format
|
|
81
|
+
formatter = logging.Formatter(log_format, datefmt=date_format)
|
|
82
|
+
file_handler.setFormatter(formatter)
|
|
83
|
+
file_handler.setLevel(log_level)
|
|
84
|
+
|
|
85
|
+
# Attach to root logger
|
|
86
|
+
root_logger = logging.getLogger()
|
|
87
|
+
root_logger.addHandler(file_handler)
|
|
88
|
+
|
|
89
|
+
except (OSError, PermissionError) as e:
|
|
90
|
+
self.logger.warning(f"Failed to setup file logging at {log_path}: {e}")
|
|
91
|
+
self.logger.warning("Continuing without file logging")
|
|
File without changes
|
|
File without changes
|