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.
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
- config_path: str = "cli.yml",
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
- config_path: Path to the Conbus CLI configuration file
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._config_path = config_path
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._config_path),
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
- cli_config=self.container.resolve(ConbusClientConfig),
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")