conson-xp 1.2.0__py3-none-any.whl → 1.3.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.
Files changed (49) hide show
  1. {conson_xp-1.2.0.dist-info → conson_xp-1.3.0.dist-info}/METADATA +1 -5
  2. {conson_xp-1.2.0.dist-info → conson_xp-1.3.0.dist-info}/RECORD +30 -47
  3. xp/__init__.py +1 -1
  4. xp/cli/commands/__init__.py +0 -2
  5. xp/cli/commands/conbus/conbus_actiontable_commands.py +5 -3
  6. xp/cli/commands/conbus/conbus_autoreport_commands.py +39 -21
  7. xp/cli/commands/conbus/conbus_blink_commands.py +8 -8
  8. xp/cli/commands/conbus/conbus_config_commands.py +3 -1
  9. xp/cli/commands/conbus/conbus_custom_commands.py +3 -1
  10. xp/cli/commands/conbus/conbus_datapoint_commands.py +4 -2
  11. xp/cli/commands/conbus/conbus_discover_commands.py +5 -3
  12. xp/cli/commands/conbus/conbus_lightlevel_commands.py +68 -32
  13. xp/cli/commands/conbus/conbus_linknumber_commands.py +32 -17
  14. xp/cli/commands/conbus/conbus_msactiontable_commands.py +11 -4
  15. xp/cli/commands/conbus/conbus_output_commands.py +6 -2
  16. xp/cli/commands/conbus/conbus_receive_commands.py +5 -3
  17. xp/cli/commands/file_commands.py +9 -3
  18. xp/cli/commands/homekit/homekit_start_commands.py +3 -1
  19. xp/cli/commands/module_commands.py +12 -4
  20. xp/cli/commands/reverse_proxy_commands.py +3 -1
  21. xp/cli/main.py +0 -2
  22. xp/models/conbus/conbus_datapoint.py +3 -0
  23. xp/models/conbus/conbus_writeconfig.py +60 -0
  24. xp/services/conbus/conbus_datapoint_service.py +9 -6
  25. xp/services/conbus/{conbus_linknumber_set_service.py → write_config_service.py} +78 -66
  26. xp/services/telegram/telegram_datapoint_service.py +70 -0
  27. xp/utils/dependencies.py +4 -46
  28. xp/api/__init__.py +0 -1
  29. xp/api/main.py +0 -125
  30. xp/api/models/__init__.py +0 -1
  31. xp/api/models/api.py +0 -31
  32. xp/api/models/discover.py +0 -31
  33. xp/api/routers/__init__.py +0 -17
  34. xp/api/routers/conbus.py +0 -5
  35. xp/api/routers/conbus_blink.py +0 -117
  36. xp/api/routers/conbus_custom.py +0 -71
  37. xp/api/routers/conbus_datapoint.py +0 -74
  38. xp/api/routers/conbus_output.py +0 -167
  39. xp/api/routers/errors.py +0 -38
  40. xp/cli/commands/api.py +0 -12
  41. xp/cli/commands/api_start_commands.py +0 -132
  42. xp/services/conbus/conbus_autoreport_get_service.py +0 -94
  43. xp/services/conbus/conbus_autoreport_set_service.py +0 -141
  44. xp/services/conbus/conbus_lightlevel_get_service.py +0 -109
  45. xp/services/conbus/conbus_lightlevel_set_service.py +0 -225
  46. xp/services/conbus/conbus_linknumber_get_service.py +0 -94
  47. {conson_xp-1.2.0.dist-info → conson_xp-1.3.0.dist-info}/WHEEL +0 -0
  48. {conson_xp-1.2.0.dist-info → conson_xp-1.3.0.dist-info}/entry_points.txt +0 -0
  49. {conson_xp-1.2.0.dist-info → conson_xp-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,167 +0,0 @@
1
- """FastAPI router for Conbus operations."""
2
-
3
- import json
4
- import logging
5
- from typing import Union
6
-
7
- from fastapi import Request
8
- from fastapi.responses import JSONResponse
9
-
10
- from xp.api.models.api import ApiErrorResponse, ApiResponse
11
- from xp.api.routers.conbus import router
12
- from xp.api.routers.errors import handle_service_error
13
- from xp.models.telegram.action_type import ActionType
14
- from xp.services.conbus.conbus_output_service import ConbusOutputService
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- @router.get(
20
- "/output/{action}/{serial}/{device_input}",
21
- response_model=Union[ApiResponse, ApiErrorResponse],
22
- responses={
23
- 200: {"model": ApiResponse, "description": "Input completed successfully"},
24
- 400: {"model": ApiErrorResponse, "description": "Connection or request error"},
25
- 408: {"model": ApiErrorResponse, "description": "Request timeout"},
26
- 500: {"model": ApiErrorResponse, "description": "Internal server error"},
27
- },
28
- )
29
- async def input_action(
30
- request: Request,
31
- action: ActionType = ActionType.OFF_PRESS,
32
- serial: str = "1702033007",
33
- device_input: int = 0,
34
- ) -> Union[ApiResponse, ApiErrorResponse, JSONResponse]:
35
- """Initiate Input operation to find devices on the network.
36
-
37
- Sends a broadcast Input telegram and collects responses from all connected devices.
38
-
39
- Args:
40
- request: FastAPI request object.
41
- action: Action type to perform (default: OFF_PRESS).
42
- serial: Serial number of the device.
43
- device_input: Device input number.
44
-
45
- Returns:
46
- API response with operation result or error.
47
- """
48
- service = request.app.state.container.get_container().resolve(ConbusOutputService)
49
-
50
- # SendInput telegram and receive responses
51
- with service:
52
- response = service.send_action(serial, device_input, action)
53
-
54
- if not response.success:
55
- return handle_service_error(response.error or "Unknown error")
56
-
57
- logger.debug(json.dumps(response.to_dict(), indent=2))
58
-
59
- # Build successful response
60
- if response.output_telegram and response.output_telegram.system_function:
61
- return ApiResponse(
62
- success=True,
63
- result=response.output_telegram.system_function.name,
64
- description=response.output_telegram.system_function.get_description(),
65
- # raw_telegram = response.output_telegram.raw_telegram,
66
- )
67
- return ApiResponse(
68
- success=True,
69
- result="Output command sent",
70
- description="Output command was sent successfully",
71
- )
72
-
73
-
74
- @router.get(
75
- "/output/status/{serial_number}",
76
- response_model=Union[ApiResponse, ApiErrorResponse],
77
- responses={
78
- 200: {"model": ApiResponse, "description": "Query completed successfully"},
79
- 400: {"model": ApiErrorResponse, "description": "Connection or request error"},
80
- 408: {"model": ApiErrorResponse, "description": "Request timeout"},
81
- 500: {"model": ApiErrorResponse, "description": "Internal server error"},
82
- },
83
- )
84
- async def output_status(
85
- request: Request,
86
- serial_number: str,
87
- ) -> Union[ApiResponse, ApiErrorResponse, JSONResponse]:
88
- """Query output status from a device.
89
-
90
- Sends a status query telegram and retrieves the output state.
91
-
92
- Args:
93
- request: FastAPI request object.
94
- serial_number: Serial number of the device to query.
95
-
96
- Returns:
97
- API response with output status or error.
98
- """
99
- service = request.app.state.container.get_container().resolve(ConbusOutputService)
100
-
101
- # SendInput telegram and receive responses
102
- with service:
103
- response = service.get_output_state(serial_number)
104
-
105
- if not response.success:
106
- return handle_service_error(response.error or "Unknown error")
107
-
108
- # Build successful response
109
- if response.datapoint_telegram and response.datapoint_telegram.datapoint_type:
110
- return ApiResponse(
111
- success=True,
112
- result=response.datapoint_telegram.data_value,
113
- description=response.datapoint_telegram.datapoint_type.name,
114
- )
115
- return ApiResponse(
116
- success=True,
117
- result="No data available",
118
- description="Output status retrieved but no data available",
119
- )
120
-
121
-
122
- @router.get(
123
- "/output/state/{serial_number}",
124
- response_model=Union[ApiResponse, ApiErrorResponse],
125
- responses={
126
- 200: {"model": ApiResponse, "description": "Query completed successfully"},
127
- 400: {"model": ApiErrorResponse, "description": "Connection or request error"},
128
- 408: {"model": ApiErrorResponse, "description": "Request timeout"},
129
- 500: {"model": ApiErrorResponse, "description": "Internal server error"},
130
- },
131
- )
132
- async def output_state(
133
- request: Request,
134
- serial_number: str,
135
- ) -> Union[ApiResponse, ApiErrorResponse, JSONResponse]:
136
- """Query module state from a device.
137
-
138
- Sends a state query telegram and retrieves the module state.
139
-
140
- Args:
141
- request: FastAPI request object.
142
- serial_number: Serial number of the device to query.
143
-
144
- Returns:
145
- API response with module state or error.
146
- """
147
- service = request.app.state.container.get_container().resolve(ConbusOutputService)
148
-
149
- # SendInput telegram and receive responses
150
- with service:
151
- response = service.get_module_state(serial_number)
152
-
153
- if not response.success:
154
- return handle_service_error(response.error or "Unknown error")
155
-
156
- # Build successful response
157
- if response.datapoint_telegram and response.datapoint_telegram.datapoint_type:
158
- return ApiResponse(
159
- success=True,
160
- result=response.datapoint_telegram.data_value,
161
- description=response.datapoint_telegram.datapoint_type.name,
162
- )
163
- return ApiResponse(
164
- success=True,
165
- result="No data available",
166
- description="Module state retrieved but no data available",
167
- )
xp/api/routers/errors.py DELETED
@@ -1,38 +0,0 @@
1
- """Error handling utilities for API endpoints."""
2
-
3
- from starlette import status
4
- from starlette.responses import JSONResponse
5
-
6
- from xp.api.models.discover import DiscoverErrorResponse
7
-
8
-
9
- def handle_service_error(
10
- error: str, default_status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR
11
- ) -> JSONResponse:
12
- """Handle service errors by creating a standardized JSON error response.
13
-
14
- Args:
15
- error: Service response object with success and error attributes.
16
- default_status_code: HTTP status code to use (defaults to 500).
17
-
18
- Returns:
19
- JSONResponse with error details.
20
- """
21
- error_msg = error or "Unknown service error"
22
-
23
- # Map specific error patterns to appropriate HTTP status codes
24
- if "Not connected to server" in error_msg:
25
- status_code = status.HTTP_400_BAD_REQUEST
26
- elif "Failed to generate telegram" in error_msg:
27
- status_code = status.HTTP_400_BAD_REQUEST
28
- elif "Response timeout" in error_msg:
29
- status_code = status.HTTP_408_REQUEST_TIMEOUT
30
- elif "Failed to send telegram" in error_msg:
31
- status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
32
- else:
33
- status_code = default_status_code
34
-
35
- return JSONResponse(
36
- status_code=status_code,
37
- content=DiscoverErrorResponse(error=error_msg).model_dump(),
38
- )
xp/cli/commands/api.py DELETED
@@ -1,12 +0,0 @@
1
- """API server management CLI commands."""
2
-
3
- import click
4
- from click_help_colors import HelpColorsGroup
5
-
6
-
7
- @click.group(
8
- cls=HelpColorsGroup, help_headers_color="yellow", help_options_color="green"
9
- )
10
- def api() -> None:
11
- """Manage the FastAPI server for XP Protocol operations."""
12
- pass
@@ -1,132 +0,0 @@
1
- """API server start command."""
2
-
3
- import sys
4
-
5
- import click
6
- import uvicorn
7
-
8
- from xp.api.main import create_app
9
- from xp.cli.commands.api import api
10
-
11
-
12
- @api.command("start")
13
- @click.option(
14
- "--host",
15
- default="127.0.0.1",
16
- help="Host to bind the server to (default: 127.0.0.1)",
17
- show_default=True,
18
- )
19
- @click.option(
20
- "--port",
21
- default=8000,
22
- type=int,
23
- help="Port to bind the server to (default: 8000)",
24
- show_default=True,
25
- )
26
- @click.option(
27
- "--reload",
28
- is_flag=True,
29
- default=True,
30
- help="Enable auto-reload for development",
31
- )
32
- @click.option(
33
- "--workers",
34
- default=1,
35
- type=int,
36
- help="Number of worker processes (default: 1)",
37
- show_default=True,
38
- )
39
- @click.option(
40
- "--log-level",
41
- default="info",
42
- type=click.Choice(["critical", "error", "warning", "info", "debug", "trace"]),
43
- help="Log level (default: info)",
44
- show_default=True,
45
- )
46
- @click.option(
47
- "--access-log/--no-access-log",
48
- default=True,
49
- help="Enable/disable access log (default: enabled)",
50
- )
51
- @click.pass_context
52
- def start_api_server(
53
- context: click.Context,
54
- host: str,
55
- port: int,
56
- reload: bool,
57
- workers: int,
58
- log_level: str,
59
- access_log: bool,
60
- ) -> None:
61
- r"""Start the FastAPI server.
62
-
63
- This command starts the XP Protocol FastAPI server using uvicorn.
64
- The server provides REST API endpoints for Conbus operations.
65
-
66
- Args:
67
- context: Click context object.
68
- host: Host to bind the server to.
69
- port: Port to bind the server to.
70
- reload: Enable auto-reload for development.
71
- workers: Number of worker processes.
72
- log_level: Log level for the server.
73
- access_log: Enable/disable access log.
74
-
75
- Examples:
76
- \b
77
- # Start server on default host and port
78
- xp api start
79
-
80
- \b
81
- # Start server on specific host and port
82
- xp api start --host 0.0.0.0 --port 8080
83
-
84
- \b
85
- # Start development server with auto-reload
86
- xp api start --reload
87
-
88
- \b
89
- # Start production server with multiple workers
90
- xp api start --host 0.0.0.0 --workers 4 --no-access-log
91
- """
92
- # Validate workers and reload options
93
- if reload and workers > 1:
94
- click.echo(
95
- click.style(
96
- "Warning: Auto-reload is enabled. Setting workers to 1.",
97
- fg="yellow",
98
- )
99
- )
100
- workers = 1
101
-
102
- click.echo("Starting XP Protocol API server...")
103
- click.echo(f"Server will be available at: https://{host}:{port}")
104
- click.echo(f"API documentation at: https://{host}:{port}/docs")
105
- click.echo(f"Health check at: https://{host}:{port}/health")
106
-
107
- if reload:
108
- click.echo(click.style("Development mode: Auto-reload enabled", fg="green"))
109
-
110
- # Get container from CLI context or create new one
111
- container = context.obj.get("container")
112
-
113
- try:
114
- # For production mode, create app instance with container
115
- app = create_app(container)
116
- uvicorn.run(
117
- app,
118
- host=host,
119
- port=port,
120
- reload=reload,
121
- workers=workers,
122
- log_level=log_level,
123
- access_log=access_log,
124
- )
125
- except KeyboardInterrupt:
126
- click.echo("\nShutting down server...")
127
- except Exception as e:
128
- click.echo(
129
- click.style(f"Error starting server: {e}", fg="red"),
130
- err=True,
131
- )
132
- sys.exit(1)
@@ -1,94 +0,0 @@
1
- """Conbus Auto Report Service for getting and setting module auto report status.
2
-
3
- This service handles auto report status operations for modules through Conbus telegrams.
4
- """
5
-
6
- import logging
7
- from typing import Callable, Optional
8
-
9
- from twisted.internet.posixbase import PosixReactorBase
10
-
11
- from xp.models import ConbusClientConfig, ConbusDatapointResponse
12
- from xp.models.conbus.conbus_autoreport import ConbusAutoreportResponse
13
- from xp.models.telegram.datapoint_type import DataPointType
14
- from xp.services.conbus.conbus_datapoint_service import ConbusDatapointService
15
- from xp.services.telegram.telegram_service import TelegramService
16
-
17
-
18
- class ConbusAutoreportGetService(ConbusDatapointService):
19
- """
20
- Service for getting auto report status from Conbus modules.
21
-
22
- Uses ConbusProtocol to provide auto report status query functionality
23
- for reading the current auto report configuration from modules.
24
- """
25
-
26
- def __init__(
27
- self,
28
- telegram_service: TelegramService,
29
- cli_config: ConbusClientConfig,
30
- reactor: PosixReactorBase,
31
- ) -> None:
32
- """Initialize the Conbus autoreport get service.
33
-
34
- Args:
35
- telegram_service: Telegram service for parsing.
36
- cli_config: Conbus client configuration.
37
- reactor: Twisted reactor instance.
38
- """
39
- super().__init__(telegram_service, cli_config, reactor)
40
- self.service_callback: Optional[Callable[[ConbusAutoreportResponse], None]] = (
41
- None
42
- )
43
-
44
- # Set up logging
45
- self.logger = logging.getLogger(__name__)
46
-
47
- def finish_service_callback(
48
- self, datapoint_response: ConbusDatapointResponse
49
- ) -> None:
50
- """Handle finished service callback.
51
-
52
- Args:
53
- datapoint_response: Datapoint response from service.
54
- """
55
- self.logger.debug("Parsing datapoint response")
56
- autoreport_status = ""
57
- if datapoint_response.success and datapoint_response.datapoint_telegram:
58
- autoreport_status = datapoint_response.datapoint_telegram.data_value
59
-
60
- service_response = ConbusAutoreportResponse(
61
- success=datapoint_response.success,
62
- serial_number=self.serial_number,
63
- auto_report_status=autoreport_status,
64
- error=datapoint_response.error,
65
- sent_telegram=datapoint_response.sent_telegram,
66
- received_telegrams=datapoint_response.received_telegrams,
67
- timestamp=datapoint_response.timestamp,
68
- )
69
-
70
- if self.service_callback:
71
- self.service_callback(service_response)
72
-
73
- def get_autoreport_status(
74
- self,
75
- serial_number: str,
76
- finish_callback: Callable[[ConbusAutoreportResponse], None],
77
- timeout_seconds: Optional[float] = None,
78
- ) -> None:
79
- """
80
- Get the current auto report status for a specific module.
81
-
82
- Args:
83
- serial_number: 10-digit module serial number
84
- finish_callback: callback function to call when the auto report status is received
85
- timeout_seconds: timeout in seconds
86
- """
87
- self.logger.info("Starting get_autoreport_status")
88
- if timeout_seconds:
89
- self.timeout_seconds = timeout_seconds
90
- self.serial_number = serial_number
91
- self.datapoint_type = DataPointType.AUTO_REPORT_STATUS
92
- self.finish_callback = self.finish_service_callback
93
- self.service_callback = finish_callback
94
- self.start_reactor()
@@ -1,141 +0,0 @@
1
- """Conbus Auto Report Service for getting and setting module auto report status.
2
-
3
- This service handles auto report status operations for modules through Conbus telegrams.
4
- """
5
-
6
- import logging
7
- from datetime import datetime
8
- from typing import Callable, Optional
9
-
10
- from twisted.internet.posixbase import PosixReactorBase
11
-
12
- from xp.models import ConbusClientConfig
13
- from xp.models.conbus.conbus_autoreport import ConbusAutoreportResponse
14
- from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
15
- from xp.models.telegram.datapoint_type import DataPointType
16
- from xp.models.telegram.system_function import SystemFunction
17
- from xp.models.telegram.telegram_type import TelegramType
18
- from xp.services.protocol import ConbusProtocol
19
-
20
-
21
- class ConbusAutoreportSetService(ConbusProtocol):
22
- """
23
- Service for setting auto report status on Conbus modules.
24
-
25
- Uses ConbusProtocol to provide auto report configuration functionality
26
- for enabling/disabling automatic reporting on modules.
27
- """
28
-
29
- def __init__(
30
- self,
31
- cli_config: ConbusClientConfig,
32
- reactor: PosixReactorBase,
33
- ) -> None:
34
- """Initialize the Conbus autoreport set service.
35
-
36
- Args:
37
- cli_config: Conbus client configuration.
38
- reactor: Twisted reactor instance.
39
- """
40
- super().__init__(cli_config, reactor)
41
- self.serial_number: str = ""
42
- self.status: bool = False
43
- self.finish_callback: Optional[Callable[[ConbusAutoreportResponse], None]] = (
44
- None
45
- )
46
- self.service_response: ConbusAutoreportResponse = ConbusAutoreportResponse(
47
- success=False,
48
- serial_number=self.serial_number,
49
- )
50
-
51
- # Set up logging
52
- self.logger = logging.getLogger(__name__)
53
-
54
- def connection_established(self) -> None:
55
- """Handle connection established event."""
56
- # Convert boolean to appropriate value
57
- status_value = "PP" if self.status else "AA"
58
- status_text = "on" if self.status else "off"
59
-
60
- self.logger.debug("Connection established, set autoreport to %s", status_text)
61
- self.send_telegram(
62
- telegram_type=TelegramType.SYSTEM,
63
- serial_number=self.serial_number,
64
- system_function=SystemFunction.WRITE_CONFIG,
65
- data_value=f"{DataPointType.AUTO_REPORT_STATUS.value}{status_value}",
66
- )
67
-
68
- def telegram_sent(self, telegram_sent: str) -> None:
69
- """Handle telegram sent event.
70
-
71
- Args:
72
- telegram_sent: The telegram that was sent.
73
- """
74
- self.logger.debug("Autoreport reply telegram sent %s", telegram_sent)
75
- self.service_response.sent_telegram = telegram_sent
76
-
77
- def telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
78
- """Handle telegram received event.
79
-
80
- Args:
81
- telegram_received: The telegram received event.
82
- """
83
- self.logger.debug(f"Telegram received: {telegram_received}")
84
- if not self.service_response.received_telegrams:
85
- self.service_response.received_telegrams = []
86
- self.service_response.received_telegrams.append(telegram_received.frame)
87
-
88
- if not (
89
- telegram_received.checksum_valid
90
- and telegram_received.telegram_type == TelegramType.REPLY
91
- and telegram_received.serial_number == self.serial_number
92
- and telegram_received.system_function
93
- in (SystemFunction.ACK, SystemFunction.NAK)
94
- ):
95
- self.logger.debug(f"Not a reply telegram received: {telegram_received}")
96
- return
97
-
98
- self.service_response.success = True
99
- self.service_response.timestamp = datetime.now()
100
- self.service_response.result = telegram_received.system_function.name
101
- self.service_response.auto_report_status = "on" if self.status else "off"
102
-
103
- self.logger.debug("Received autoreport reply telegram")
104
- if self.finish_callback:
105
- self.finish_callback(self.service_response)
106
-
107
- def failed(self, message: str) -> None:
108
- """Handle failed connection event.
109
-
110
- Args:
111
- message: Failure message.
112
- """
113
- self.logger.debug(f"Failed with message: {message}")
114
- self.service_response.success = False
115
- self.service_response.error = message
116
- self.service_response.timestamp = datetime.now()
117
- if self.finish_callback:
118
- self.finish_callback(self.service_response)
119
-
120
- def set_autoreport_status(
121
- self,
122
- serial_number: str,
123
- status: bool,
124
- finish_callback: Callable[[ConbusAutoreportResponse], None],
125
- timeout_seconds: Optional[float] = None,
126
- ) -> None:
127
- """Set the auto report status for a specific module.
128
-
129
- Args:
130
- serial_number: 10-digit module serial number.
131
- status: True for ON, False for OFF.
132
- finish_callback: Callback function to call when operation completes.
133
- timeout_seconds: Timeout in seconds.
134
- """
135
- self.logger.info("Starting set_autoreport_status")
136
- if timeout_seconds:
137
- self.timeout_seconds = timeout_seconds
138
- self.finish_callback = finish_callback
139
- self.serial_number = serial_number
140
- self.status = status
141
- self.start_reactor()
@@ -1,109 +0,0 @@
1
- """Conbus Lightlevel Get Service for getting module light levels.
2
-
3
- This service handles light level query operations for modules through Conbus telegrams.
4
- """
5
-
6
- import logging
7
- from datetime import datetime
8
- from typing import Callable, Optional
9
-
10
- from twisted.internet.posixbase import PosixReactorBase
11
-
12
- from xp.models import ConbusClientConfig, ConbusDatapointResponse
13
- from xp.models.conbus.conbus_lightlevel import ConbusLightlevelResponse
14
- from xp.models.telegram.datapoint_type import DataPointType
15
- from xp.services.conbus.conbus_datapoint_service import ConbusDatapointService
16
- from xp.services.telegram.telegram_service import TelegramService
17
-
18
-
19
- class ConbusLightlevelGetService(ConbusDatapointService):
20
- """
21
- Service for getting light levels from Conbus modules.
22
-
23
- Uses ConbusProtocol to provide light level query functionality
24
- for reading the current light level configuration from module outputs.
25
- """
26
-
27
- def __init__(
28
- self,
29
- telegram_service: TelegramService,
30
- cli_config: ConbusClientConfig,
31
- reactor: PosixReactorBase,
32
- ) -> None:
33
- """Initialize the Conbus lightlevel get service.
34
-
35
- Args:
36
- telegram_service: Service for parsing telegrams.
37
- cli_config: Configuration for Conbus client connection.
38
- reactor: Twisted reactor for event loop.
39
- """
40
- super().__init__(telegram_service, cli_config, reactor)
41
- self.output_number: int = 0
42
- self.service_callback: Optional[Callable[[ConbusLightlevelResponse], None]] = (
43
- None
44
- )
45
-
46
- # Set up logging
47
- self.logger = logging.getLogger(__name__)
48
-
49
- def finish_service_callback(
50
- self, datapoint_response: ConbusDatapointResponse
51
- ) -> None:
52
- """Process datapoint response and extract light level.
53
-
54
- Args:
55
- datapoint_response: The datapoint response from the module.
56
- """
57
- self.logger.debug("Parsing datapoint response")
58
-
59
- level = 0
60
- if datapoint_response.success and datapoint_response.datapoint_telegram:
61
- for output_data in datapoint_response.datapoint_telegram.data_value.split(
62
- ","
63
- ):
64
- if ":" in output_data:
65
- output_str, level_str = output_data.split(":")
66
- if int(output_str) == self.output_number:
67
- level_str = level_str.replace("[%]", "")
68
- level = int(level_str)
69
- break
70
-
71
- service_response = ConbusLightlevelResponse(
72
- success=datapoint_response.success,
73
- serial_number=self.serial_number,
74
- output_number=self.output_number,
75
- level=level,
76
- error=datapoint_response.error,
77
- sent_telegram=datapoint_response.sent_telegram,
78
- received_telegrams=datapoint_response.received_telegrams,
79
- timestamp=datetime.now(),
80
- )
81
-
82
- if self.service_callback:
83
- self.service_callback(service_response)
84
-
85
- def get_light_level(
86
- self,
87
- serial_number: str,
88
- output_number: int,
89
- finish_callback: Callable[[ConbusLightlevelResponse], None],
90
- timeout_seconds: Optional[float] = None,
91
- ) -> None:
92
- """Get the current light level for a specific module output.
93
-
94
- Args:
95
- serial_number: 10-digit module serial number.
96
- output_number: Output module number.
97
- finish_callback: Callback function to call when the light level is received.
98
- timeout_seconds: Timeout in seconds.
99
- """
100
- self.logger.info("Starting get_light_level")
101
- if timeout_seconds:
102
- self.timeout_seconds = timeout_seconds
103
- self.serial_number = serial_number
104
- self.output_number = output_number
105
- self.datapoint_type = DataPointType.MODULE_LIGHT_LEVEL
106
-
107
- self.finish_callback = self.finish_service_callback
108
- self.service_callback = finish_callback
109
- self.start_reactor()