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
@@ -0,0 +1,70 @@
1
+ """Service for processing Telegram protocol datapoint values."""
2
+
3
+
4
+ class TelegramDatapointService:
5
+ """Service for processing Telegram protocol datapoint values.
6
+
7
+ Provides methods to parse and extract values from different types of
8
+ Telegram datapoints including autoreport status, light level outputs,
9
+ and link number values.
10
+ """
11
+
12
+ def get_autoreport_status(self, data_value: str) -> bool:
13
+ """Get the autoreport status value.
14
+
15
+ Args:
16
+ data_value: The raw autoreport status data value (PP or AA).
17
+
18
+ Returns:
19
+ The autoreport status: Enable (True) or disable (False).
20
+ """
21
+ status_value = True if data_value == "PP" else False
22
+ return status_value
23
+
24
+ def get_autoreport_status_data_value(self, status_value: bool) -> str:
25
+ """Get the autoreport status data_value.
26
+
27
+ Args:
28
+ status_value: Enable (True) or disable (False).
29
+
30
+ Returns:
31
+ data_value: The raw autoreport status data value (PP or AA).
32
+ """
33
+ data_value = "PP" if status_value else "AA"
34
+ return data_value
35
+
36
+ def get_lightlevel(self, data_value: str, output_number: int) -> int:
37
+ """Extract the light level for a specific output number.
38
+
39
+ Parses comma-separated output data in the format "output:level[%]"
40
+ and returns the level for the requested output number.
41
+
42
+ Args:
43
+ data_value: Comma-separated string of output:level pairs
44
+ (e.g., "1:50[%],2:75[%]").
45
+ output_number: The output number to get the level for.
46
+
47
+ Returns:
48
+ The light level as an integer (0 if output not found).
49
+ """
50
+ level = 0
51
+ for output_data in data_value.split(","):
52
+ if ":" in output_data:
53
+ output_str, level_str = output_data.split(":")
54
+ if int(output_str) == output_number:
55
+ level_str = level_str.replace("[%]", "")
56
+ level = int(level_str)
57
+ break
58
+ return level
59
+
60
+ def get_linknumber(self, data_value: str) -> int:
61
+ """Parse and return the link number value.
62
+
63
+ Args:
64
+ data_value: The raw link number data value as a string.
65
+
66
+ Returns:
67
+ The link number as an integer.
68
+ """
69
+ link_number_value = int(data_value)
70
+ return link_number_value
xp/utils/dependencies.py CHANGED
@@ -21,8 +21,6 @@ from xp.services.conbus.actiontable.msactiontable_xp24_serializer import (
21
21
  from xp.services.conbus.actiontable.msactiontable_xp33_serializer import (
22
22
  Xp33MsActionTableSerializer,
23
23
  )
24
- from xp.services.conbus.conbus_autoreport_get_service import ConbusAutoreportGetService
25
- from xp.services.conbus.conbus_autoreport_set_service import ConbusAutoreportSetService
26
24
  from xp.services.conbus.conbus_blink_all_service import ConbusBlinkAllService
27
25
  from xp.services.conbus.conbus_blink_service import ConbusBlinkService
28
26
  from xp.services.conbus.conbus_custom_service import ConbusCustomService
@@ -33,13 +31,11 @@ from xp.services.conbus.conbus_datapoint_service import (
33
31
  ConbusDatapointService,
34
32
  )
35
33
  from xp.services.conbus.conbus_discover_service import ConbusDiscoverService
36
- from xp.services.conbus.conbus_lightlevel_set_service import ConbusLightlevelSetService
37
- from xp.services.conbus.conbus_linknumber_get_service import ConbusLinknumberGetService
38
- from xp.services.conbus.conbus_linknumber_set_service import ConbusLinknumberSetService
39
34
  from xp.services.conbus.conbus_output_service import ConbusOutputService
40
35
  from xp.services.conbus.conbus_raw_service import ConbusRawService
41
36
  from xp.services.conbus.conbus_receive_service import ConbusReceiveService
42
37
  from xp.services.conbus.conbus_scan_service import ConbusScanService
38
+ from xp.services.conbus.write_config_service import WriteConfigService
43
39
  from xp.services.homekit.homekit_cache_service import HomeKitCacheService
44
40
  from xp.services.homekit.homekit_conbus_service import HomeKitConbusService
45
41
  from xp.services.homekit.homekit_dimminglight_service import HomeKitDimmingLightService
@@ -191,8 +187,9 @@ class ServiceContainer:
191
187
  )
192
188
 
193
189
  self.container.register(
194
- ConbusLightlevelSetService,
195
- factory=lambda: ConbusLightlevelSetService(
190
+ WriteConfigService,
191
+ factory=lambda: WriteConfigService(
192
+ telegram_service=self.container.resolve(TelegramService),
196
193
  cli_config=self.container.resolve(ConbusClientConfig),
197
194
  reactor=self.container.resolve(PosixReactorBase),
198
195
  ),
@@ -247,45 +244,6 @@ class ServiceContainer:
247
244
  scope=punq.Scope.singleton,
248
245
  )
249
246
 
250
- self.container.register(
251
- ConbusAutoreportSetService,
252
- factory=lambda: ConbusAutoreportSetService(
253
- cli_config=self.container.resolve(ConbusClientConfig),
254
- reactor=self.container.resolve(PosixReactorBase),
255
- ),
256
- scope=punq.Scope.singleton,
257
- )
258
-
259
- self.container.register(
260
- ConbusAutoreportGetService,
261
- factory=lambda: ConbusAutoreportGetService(
262
- telegram_service=self.container.resolve(TelegramService),
263
- cli_config=self.container.resolve(ConbusClientConfig),
264
- reactor=self.container.resolve(PosixReactorBase),
265
- ),
266
- scope=punq.Scope.singleton,
267
- )
268
-
269
- self.container.register(
270
- ConbusLinknumberGetService,
271
- factory=lambda: ConbusLinknumberGetService(
272
- telegram_service=self.container.resolve(TelegramService),
273
- cli_config=self.container.resolve(ConbusClientConfig),
274
- reactor=self.container.resolve(PosixReactorBase),
275
- ),
276
- scope=punq.Scope.singleton,
277
- )
278
-
279
- self.container.register(
280
- ConbusLinknumberSetService,
281
- factory=lambda: ConbusLinknumberSetService(
282
- telegram_service=self.container.resolve(TelegramService),
283
- cli_config=self.container.resolve(ConbusClientConfig),
284
- reactor=self.container.resolve(PosixReactorBase),
285
- ),
286
- scope=punq.Scope.singleton,
287
- )
288
-
289
247
  self.container.register(
290
248
  ConbusCustomService,
291
249
  factory=lambda: ConbusCustomService(
xp/api/__init__.py DELETED
@@ -1 +0,0 @@
1
- """API module for FastAPI endpoints and models."""
xp/api/main.py DELETED
@@ -1,125 +0,0 @@
1
- """FastAPI application for XP Protocol API endpoints."""
2
-
3
- import logging
4
- import os
5
- from pathlib import Path
6
- from typing import Any
7
-
8
- import yaml
9
- from fastapi import FastAPI
10
- from fastapi.middleware.cors import CORSMiddleware
11
-
12
- from xp.api.routers import conbus
13
- from xp.utils.dependencies import ServiceContainer
14
-
15
- # Set up logging
16
- logging.basicConfig(level=logging.INFO)
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- def load_api_config() -> dict[str, Any]:
21
- """Load API configuration from api.yml or environment variables.
22
-
23
- Returns:
24
- Dictionary containing API configuration settings.
25
- """
26
- config = {
27
- "title": "XP Protocol API",
28
- "description": "REST API for XP Protocol Conbus operations",
29
- "version": "0.2.0",
30
- "cors_origins": ["*"],
31
- "cors_methods": ["GET", "POST"],
32
- "cors_headers": ["*"],
33
- }
34
-
35
- # Try to load from api.yml
36
- try:
37
- if Path("api.yml").exists():
38
- with Path("api.yml").open("r") as file:
39
- file_config = yaml.safe_load(file)
40
- if file_config:
41
- config.update(file_config.get("api", {}))
42
- logger.info("Loaded API configuration from api.yml")
43
- except Exception as e:
44
- logger.warning(f"Could not load api.yml: {e}")
45
-
46
- # Override with environment variables
47
- config["title"] = os.getenv("API_TITLE", config["title"])
48
- config["description"] = os.getenv("API_DESCRIPTION", config["description"])
49
- config["version"] = os.getenv("API_VERSION", config["version"])
50
-
51
- # CORS configuration from environment
52
- cors_origins = os.getenv("CORS_ORIGINS")
53
- if cors_origins is not None:
54
- config["cors_origins"] = cors_origins.split(",")
55
- cors_methods = os.getenv("CORS_METHODS")
56
- if cors_methods is not None:
57
- config["cors_methods"] = cors_methods.split(",")
58
- cors_headers = os.getenv("CORS_HEADERS")
59
- if cors_headers is not None:
60
- config["cors_headers"] = cors_headers.split(",")
61
-
62
- return config
63
-
64
-
65
- def create_app(container: ServiceContainer) -> FastAPI:
66
- """Create and configure the FastAPI application.
67
-
68
- Args:
69
- container: Optional ServiceContainer instance. If not provided, a new one will be created.
70
-
71
- Returns:
72
- Configured FastAPI application instance.
73
- """
74
- config = load_api_config()
75
-
76
- fastapi = FastAPI(
77
- title=config["title"],
78
- description=config["description"],
79
- version=config["version"],
80
- docs_url="/docs",
81
- redoc_url="/redoc",
82
- )
83
-
84
- # Add CORS middleware
85
- fastapi.add_middleware(
86
- CORSMiddleware,
87
- allow_origins=config["cors_origins"],
88
- allow_credentials=True,
89
- allow_methods=config["cors_methods"],
90
- allow_headers=config["cors_headers"],
91
- )
92
-
93
- # Initialize service container
94
- fastapi.state.container = container
95
-
96
- # Include routers
97
- fastapi.include_router(conbus.router)
98
-
99
- # Health check endpoint
100
- @fastapi.get("/health")
101
- async def health_check() -> dict[str, str]:
102
- """Return health status of the API.
103
-
104
- Returns:
105
- Dictionary containing status and service information.
106
- """
107
- return {"status": "healthy", "service": "xp-api"}
108
-
109
- # Root endpoint
110
- @fastapi.get("/")
111
- async def root() -> dict[str, str]:
112
- """Return API information and available endpoints.
113
-
114
- Returns:
115
- Dictionary containing API metadata and endpoint links.
116
- """
117
- return {
118
- "message": "XP Protocol API",
119
- "version": config["version"],
120
- "docs": "/docs",
121
- "health": "/health",
122
- }
123
-
124
- logger.info(f"FastAPI application created: {config['title']} v{config['version']}")
125
- return fastapi
xp/api/models/__init__.py DELETED
@@ -1 +0,0 @@
1
- """API models for request and response validation."""
xp/api/models/api.py DELETED
@@ -1,31 +0,0 @@
1
- """Pydantic models for Input API endpoints."""
2
-
3
- from typing import Optional
4
-
5
- from pydantic import BaseModel, Field
6
-
7
-
8
- class ApiResponse(BaseModel):
9
- """Response model for successful Input operation.
10
-
11
- Attributes:
12
- success: Operation success status.
13
- result: Result value.
14
- description: Description of the result.
15
- """
16
-
17
- success: bool = Field(default=True, description="Operation success status")
18
- result: Optional[str] = Field(default=None, description="Result")
19
- description: Optional[str] = Field(default=None, description="Description")
20
-
21
-
22
- class ApiErrorResponse(BaseModel):
23
- """Response model for failed Input operation.
24
-
25
- Attributes:
26
- success: Operation success status (always False).
27
- error: Error message describing what went wrong.
28
- """
29
-
30
- success: bool = Field(default=False, description="Operation success status")
31
- error: str = Field(..., description="Error message")
xp/api/models/discover.py DELETED
@@ -1,31 +0,0 @@
1
- """Pydantic models for discover API endpoints."""
2
-
3
- from typing import List
4
-
5
- from pydantic import BaseModel, Field
6
-
7
-
8
- class DiscoverResponse(BaseModel):
9
- """Response model for successful discover operation.
10
-
11
- Attributes:
12
- success: Operation success status.
13
- devices: List of discovered device information strings.
14
- """
15
-
16
- success: bool = Field(default=True, description="Operation success status")
17
- devices: List[str] = Field(
18
- default_factory=list, description="Parsed device information"
19
- )
20
-
21
-
22
- class DiscoverErrorResponse(BaseModel):
23
- """Response model for failed discover operation.
24
-
25
- Attributes:
26
- success: Operation success status (always False).
27
- error: Error message describing what went wrong.
28
- """
29
-
30
- success: bool = Field(default=False, description="Operation success status")
31
- error: str = Field(..., description="Error message")
@@ -1,17 +0,0 @@
1
- """API routers for FastAPI endpoints."""
2
-
3
- from xp.api.routers import (
4
- conbus_blink,
5
- conbus_custom,
6
- conbus_datapoint,
7
- conbus_output,
8
- )
9
- from xp.api.routers.conbus import router
10
-
11
- __all__ = [
12
- "router",
13
- "conbus_blink",
14
- "conbus_custom",
15
- "conbus_datapoint",
16
- "conbus_output",
17
- ]
xp/api/routers/conbus.py DELETED
@@ -1,5 +0,0 @@
1
- """FastAPI router for Conbus operations."""
2
-
3
- from fastapi import APIRouter
4
-
5
- router = APIRouter(prefix="/api/conbus", tags=["conbus"])
@@ -1,117 +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.services.conbus.conbus_blink_service import ConbusBlinkService
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- @router.get(
19
- "/blink/on/{serial_number}",
20
- response_model=Union[ApiResponse, ApiErrorResponse],
21
- responses={
22
- 200: {"model": ApiResponse, "description": "Input completed successfully"},
23
- 400: {"model": ApiErrorResponse, "description": "Connection or request error"},
24
- 408: {"model": ApiErrorResponse, "description": "Request timeout"},
25
- 500: {"model": ApiErrorResponse, "description": "Internal server error"},
26
- },
27
- )
28
- async def blink_on(
29
- request: Request,
30
- serial_number: str = "1702033007",
31
- ) -> Union[ApiResponse, ApiErrorResponse, JSONResponse]:
32
- """Turn on device blinking.
33
-
34
- Sends a blink on telegram to make the device blink.
35
-
36
- Args:
37
- request: FastAPI request object.
38
- serial_number: Serial number of the device.
39
-
40
- Returns:
41
- API response with blink result or error.
42
- """
43
- service = request.app.state.container.get_container().resolve(ConbusBlinkService)
44
-
45
- # SendInput telegram and receive responses
46
- with service:
47
- response = service.send_blink_telegram(
48
- serial_number=serial_number, on_or_off="on"
49
- )
50
-
51
- if not response.success:
52
- return handle_service_error(response.error or "Unknown error")
53
-
54
- logger.debug(json.dumps(response.to_dict(), indent=2))
55
-
56
- # Build successful response
57
- return ApiResponse(
58
- success=True,
59
- result=response.system_function.name,
60
- description=(
61
- response.reply_telegram.system_function.get_description()
62
- if response.reply_telegram and response.reply_telegram.system_function
63
- else None
64
- ),
65
- # raw_telegram = response.output_telegram.raw_telegram,
66
- )
67
-
68
-
69
- @router.get(
70
- "/blink/off/{serial_number}",
71
- response_model=Union[ApiResponse, ApiErrorResponse],
72
- responses={
73
- 200: {"model": ApiResponse, "description": "Input completed successfully"},
74
- 400: {"model": ApiErrorResponse, "description": "Connection or request error"},
75
- 408: {"model": ApiErrorResponse, "description": "Request timeout"},
76
- 500: {"model": ApiErrorResponse, "description": "Internal server error"},
77
- },
78
- )
79
- async def blink_off(
80
- request: Request,
81
- serial_number: str = "1702033007",
82
- ) -> Union[ApiResponse, ApiErrorResponse, JSONResponse]:
83
- """Turn off device blinking.
84
-
85
- Sends a blink off telegram to stop the device from blinking.
86
-
87
- Args:
88
- request: FastAPI request object.
89
- serial_number: Serial number of the device.
90
-
91
- Returns:
92
- API response with blink result or error.
93
- """
94
- service = request.app.state.container.get_container().resolve(ConbusBlinkService)
95
-
96
- # SendInput telegram and receive responses
97
- with service:
98
- response = service.send_blink_telegram(
99
- serial_number=serial_number, on_or_off="off"
100
- )
101
-
102
- if not response.success:
103
- return handle_service_error(response.error or "Unknown error")
104
-
105
- logger.debug(json.dumps(response.to_dict(), indent=2))
106
-
107
- # Build successful response
108
- return ApiResponse(
109
- success=True,
110
- result=response.system_function.name,
111
- description=(
112
- response.reply_telegram.system_function.get_description()
113
- if response.reply_telegram and response.reply_telegram.system_function
114
- else None
115
- ),
116
- # raw_telegram = response.output_telegram.raw_telegram,
117
- )
@@ -1,71 +0,0 @@
1
- """FastAPI router for Conbus operations."""
2
-
3
- import logging
4
- from typing import Union
5
-
6
- from fastapi import Request
7
- from fastapi.responses import JSONResponse
8
-
9
- from xp.api.models.api import ApiErrorResponse, ApiResponse
10
- from xp.api.routers.conbus import router
11
- from xp.api.routers.errors import handle_service_error
12
- from xp.services.conbus.conbus_custom_service import ConbusCustomService
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
-
17
- @router.get(
18
- "/custom/{serial_number}/{function_code}/{data}",
19
- response_model=Union[ApiResponse, ApiErrorResponse],
20
- responses={
21
- 200: {"model": ApiResponse, "description": "Datapoint completed successfully"},
22
- 400: {"model": ApiErrorResponse, "description": "Connection or request error"},
23
- 408: {"model": ApiErrorResponse, "description": "Request timeout"},
24
- 500: {"model": ApiErrorResponse, "description": "Internal server error"},
25
- },
26
- )
27
- async def custom_function(
28
- request: Request,
29
- serial_number: str = "1702033007",
30
- function_code: str = "02",
31
- data: str = "00",
32
- ) -> Union[ApiResponse, ApiErrorResponse, JSONResponse]:
33
- """Execute a custom function on a device.
34
-
35
- Sends a custom telegram with specified function code and data.
36
-
37
- Args:
38
- request: FastAPI request object.
39
- serial_number: Serial number of the device.
40
- function_code: Function code to execute.
41
- data: Data to send with the function.
42
-
43
- Returns:
44
- API response with custom function result or error.
45
- """
46
- service = request.app.state.container.get_container().resolve(ConbusCustomService)
47
- # SendDatapoint telegram and receive responses
48
- with service:
49
- response = service.send_custom_telegram(serial_number, function_code, data)
50
-
51
- if not response.success:
52
- return handle_service_error(response.error or "Unknown error")
53
-
54
- if response.reply_telegram is None:
55
- return ApiErrorResponse(
56
- success=False,
57
- error=response.error or "Unknown error",
58
- )
59
-
60
- # Build successful response
61
- if response.reply_telegram and response.reply_telegram.datapoint_type:
62
- return ApiResponse(
63
- success=True,
64
- result=response.reply_telegram.data_value,
65
- description=response.reply_telegram.datapoint_type.name,
66
- )
67
- return ApiResponse(
68
- success=True,
69
- result=response.reply_telegram.data_value,
70
- description="Custom command executed successfully",
71
- )
@@ -1,74 +0,0 @@
1
- """FastAPI router for Conbus operations."""
2
-
3
- import logging
4
- from typing import Union
5
-
6
- from fastapi import Request
7
- from fastapi.responses import JSONResponse
8
-
9
- from xp.api.models.api import ApiErrorResponse, ApiResponse
10
- from xp.api.routers.conbus import router
11
- from xp.api.routers.errors import handle_service_error
12
- from xp.models.telegram.datapoint_type import DataPointType
13
- from xp.services.conbus.conbus_datapoint_service import ConbusDatapointService
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- @router.get(
19
- "/datapoint/{datapoint}/{serial_number}",
20
- response_model=Union[ApiResponse, ApiErrorResponse],
21
- responses={
22
- 200: {"model": ApiResponse, "description": "Datapoint completed successfully"},
23
- 400: {"model": ApiErrorResponse, "description": "Connection or request error"},
24
- 408: {"model": ApiErrorResponse, "description": "Request timeout"},
25
- 500: {"model": ApiErrorResponse, "description": "Internal server error"},
26
- },
27
- )
28
- async def datapoint_devices(
29
- request: Request,
30
- datapoint: DataPointType = DataPointType.SW_VERSION,
31
- serial_number: str = "1702033007",
32
- ) -> Union[ApiResponse, ApiErrorResponse, JSONResponse]:
33
- """Query a datapoint value from a device.
34
-
35
- Sends a datapoint query telegram and retrieves the requested datapoint value.
36
-
37
- Args:
38
- request: FastAPI request object.
39
- datapoint: Type of datapoint to query (default: SW_VERSION).
40
- serial_number: Serial number of the device.
41
-
42
- Returns:
43
- API response with datapoint value or error.
44
- """
45
- service = request.app.state.container.get_container().resolve(
46
- ConbusDatapointService
47
- )
48
- # SendDatapoint telegram and receive responses
49
- with service:
50
- response = service.query_datapoint(
51
- datapoint_type=datapoint, serial_number=serial_number
52
- )
53
-
54
- if not response.success:
55
- return handle_service_error(response.error or "Unknown error")
56
-
57
- if response.datapoint_telegram is None:
58
- return ApiErrorResponse(
59
- success=False,
60
- error=response.error or "Unknown error",
61
- )
62
-
63
- # Build successful response
64
- if response.datapoint_telegram and response.datapoint_telegram.datapoint_type:
65
- return ApiResponse(
66
- success=True,
67
- result=response.datapoint_telegram.data_value,
68
- description=response.datapoint_telegram.datapoint_type.name,
69
- )
70
- return ApiResponse(
71
- success=True,
72
- result=response.datapoint_telegram.data_value,
73
- description="Datapoint value retrieved",
74
- )