conson-xp 1.2.0__py3-none-any.whl → 1.4.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 (62) hide show
  1. {conson_xp-1.2.0.dist-info → conson_xp-1.4.0.dist-info}/METADATA +1 -5
  2. {conson_xp-1.2.0.dist-info → conson_xp-1.4.0.dist-info}/RECORD +43 -60
  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_discover.py +19 -3
  24. xp/models/conbus/conbus_writeconfig.py +60 -0
  25. xp/models/telegram/system_telegram.py +4 -4
  26. xp/services/conbus/conbus_datapoint_service.py +9 -6
  27. xp/services/conbus/conbus_discover_service.py +120 -2
  28. xp/services/conbus/conbus_scan_service.py +1 -1
  29. xp/services/conbus/{conbus_linknumber_set_service.py → write_config_service.py} +78 -66
  30. xp/services/protocol/telegram_protocol.py +4 -4
  31. xp/services/server/base_server_service.py +9 -4
  32. xp/services/server/cp20_server_service.py +2 -1
  33. xp/services/server/server_service.py +75 -4
  34. xp/services/server/xp130_server_service.py +2 -1
  35. xp/services/server/xp20_server_service.py +2 -1
  36. xp/services/server/xp230_server_service.py +2 -1
  37. xp/services/server/xp24_server_service.py +123 -50
  38. xp/services/server/xp33_server_service.py +150 -20
  39. xp/services/telegram/telegram_datapoint_service.py +70 -0
  40. xp/utils/dependencies.py +4 -46
  41. xp/api/__init__.py +0 -1
  42. xp/api/main.py +0 -125
  43. xp/api/models/__init__.py +0 -1
  44. xp/api/models/api.py +0 -31
  45. xp/api/models/discover.py +0 -31
  46. xp/api/routers/__init__.py +0 -17
  47. xp/api/routers/conbus.py +0 -5
  48. xp/api/routers/conbus_blink.py +0 -117
  49. xp/api/routers/conbus_custom.py +0 -71
  50. xp/api/routers/conbus_datapoint.py +0 -74
  51. xp/api/routers/conbus_output.py +0 -167
  52. xp/api/routers/errors.py +0 -38
  53. xp/cli/commands/api.py +0 -12
  54. xp/cli/commands/api_start_commands.py +0 -132
  55. xp/services/conbus/conbus_autoreport_get_service.py +0 -94
  56. xp/services/conbus/conbus_autoreport_set_service.py +0 -141
  57. xp/services/conbus/conbus_lightlevel_get_service.py +0 -109
  58. xp/services/conbus/conbus_lightlevel_set_service.py +0 -225
  59. xp/services/conbus/conbus_linknumber_get_service.py +0 -94
  60. {conson_xp-1.2.0.dist-info → conson_xp-1.4.0.dist-info}/WHEEL +0 -0
  61. {conson_xp-1.2.0.dist-info → conson_xp-1.4.0.dist-info}/entry_points.txt +0 -0
  62. {conson_xp-1.2.0.dist-info → conson_xp-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -7,14 +7,14 @@ import click
7
7
  from xp.cli.commands.conbus.conbus import conbus_lightlevel
8
8
  from xp.cli.utils.decorators import (
9
9
  connection_command,
10
- handle_service_errors,
11
10
  )
12
11
  from xp.cli.utils.serial_number_type import SERIAL
13
- from xp.models.conbus.conbus_lightlevel import ConbusLightlevelResponse
14
- from xp.services.conbus.conbus_lightlevel_set_service import (
15
- ConbusLightlevelError,
16
- ConbusLightlevelSetService,
17
- )
12
+ from xp.models import ConbusDatapointResponse
13
+ from xp.models.conbus.conbus_writeconfig import ConbusWriteConfigResponse
14
+ from xp.models.telegram.datapoint_type import DataPointType
15
+ from xp.services.conbus.conbus_datapoint_service import ConbusDatapointService
16
+ from xp.services.conbus.write_config_service import WriteConfigService
17
+ from xp.services.telegram.telegram_datapoint_service import TelegramDatapointService
18
18
 
19
19
 
20
20
  @conbus_lightlevel.command("set")
@@ -23,7 +23,6 @@ from xp.services.conbus.conbus_lightlevel_set_service import (
23
23
  @click.argument("level", type=click.IntRange(0, 100))
24
24
  @click.pass_context
25
25
  @connection_command()
26
- @handle_service_errors(ConbusLightlevelError)
27
26
  def xp_lightlevel_set(
28
27
  ctx: click.Context, serial_number: str, output_number: int, level: int
29
28
  ) -> None:
@@ -41,20 +40,28 @@ def xp_lightlevel_set(
41
40
  xp conbus lightlevel set 0011223344 0 100 # Set output 0 to 100%
42
41
  """
43
42
 
44
- def finish(response: "ConbusLightlevelResponse") -> None:
45
- """Handle successful completion of light level set command.
43
+ def on_finish(response: "ConbusWriteConfigResponse") -> None:
44
+ """Handle successful completion of light level on command.
46
45
 
47
46
  Args:
48
47
  response: Light level response object.
49
48
  """
50
49
  click.echo(json.dumps(response.to_dict(), indent=2))
51
50
 
52
- service = (
53
- ctx.obj.get("container").get_container().resolve(ConbusLightlevelSetService)
51
+ service: WriteConfigService = (
52
+ ctx.obj.get("container").get_container().resolve(WriteConfigService)
54
53
  )
55
54
 
55
+ data_value = f"{output_number:02d}:{level:03d}"
56
+
56
57
  with service:
57
- service.set_lightlevel(serial_number, output_number, level, finish, 0.5)
58
+ service.write_config(
59
+ serial_number=serial_number,
60
+ datapoint_type=DataPointType.MODULE_LIGHT_LEVEL,
61
+ data_value=data_value,
62
+ finish_callback=on_finish,
63
+ timeout_seconds=0.5,
64
+ )
58
65
 
59
66
 
60
67
  @conbus_lightlevel.command("off")
@@ -62,7 +69,6 @@ def xp_lightlevel_set(
62
69
  @click.argument("output_number", type=click.IntRange(0, 8))
63
70
  @click.pass_context
64
71
  @connection_command()
65
- @handle_service_errors(ConbusLightlevelError)
66
72
  def xp_lightlevel_off(
67
73
  ctx: click.Context, serial_number: str, output_number: int
68
74
  ) -> None:
@@ -79,20 +85,29 @@ def xp_lightlevel_off(
79
85
  xp conbus lightlevel off 0011223344 0 # Turn off output 0
80
86
  """
81
87
 
82
- def finish(response: "ConbusLightlevelResponse") -> None:
83
- """Handle successful completion of light level off command.
88
+ def on_finish(response: "ConbusWriteConfigResponse") -> None:
89
+ """Handle successful completion of light level on command.
84
90
 
85
91
  Args:
86
92
  response: Light level response object.
87
93
  """
88
94
  click.echo(json.dumps(response.to_dict(), indent=2))
89
95
 
90
- service = (
91
- ctx.obj.get("container").get_container().resolve(ConbusLightlevelSetService)
96
+ service: WriteConfigService = (
97
+ ctx.obj.get("container").get_container().resolve(WriteConfigService)
92
98
  )
93
99
 
100
+ level = 0
101
+ data_value = f"{output_number:02d}:{level:03d}"
102
+
94
103
  with service:
95
- service.turn_off(serial_number, output_number, finish, 0.5)
104
+ service.write_config(
105
+ serial_number=serial_number,
106
+ datapoint_type=DataPointType.MODULE_LIGHT_LEVEL,
107
+ data_value=data_value,
108
+ finish_callback=on_finish,
109
+ timeout_seconds=0.5,
110
+ )
96
111
 
97
112
 
98
113
  @conbus_lightlevel.command("on")
@@ -100,7 +115,6 @@ def xp_lightlevel_off(
100
115
  @click.argument("output_number", type=click.IntRange(0, 8))
101
116
  @click.pass_context
102
117
  @connection_command()
103
- @handle_service_errors(ConbusLightlevelError)
104
118
  def xp_lightlevel_on(
105
119
  ctx: click.Context, serial_number: str, output_number: int
106
120
  ) -> None:
@@ -117,7 +131,7 @@ def xp_lightlevel_on(
117
131
  xp conbus lightlevel on 0011223344 0 # Turn on output 0 (80%)
118
132
  """
119
133
 
120
- def finish(response: "ConbusLightlevelResponse") -> None:
134
+ def on_finish(response: "ConbusWriteConfigResponse") -> None:
121
135
  """Handle successful completion of light level on command.
122
136
 
123
137
  Args:
@@ -125,12 +139,21 @@ def xp_lightlevel_on(
125
139
  """
126
140
  click.echo(json.dumps(response.to_dict(), indent=2))
127
141
 
128
- service = (
129
- ctx.obj.get("container").get_container().resolve(ConbusLightlevelSetService)
142
+ service: WriteConfigService = (
143
+ ctx.obj.get("container").get_container().resolve(WriteConfigService)
130
144
  )
131
145
 
146
+ level = 60
147
+ data_value = f"{output_number:02d}:{level:03d}"
148
+
132
149
  with service:
133
- service.turn_on(serial_number, output_number, finish, 0.5)
150
+ service.write_config(
151
+ serial_number=serial_number,
152
+ datapoint_type=DataPointType.MODULE_LIGHT_LEVEL,
153
+ data_value=data_value,
154
+ finish_callback=on_finish,
155
+ timeout_seconds=0.5,
156
+ )
134
157
 
135
158
 
136
159
  @conbus_lightlevel.command("get")
@@ -138,7 +161,6 @@ def xp_lightlevel_on(
138
161
  @click.argument("output_number", type=click.IntRange(0, 8))
139
162
  @click.pass_context
140
163
  @connection_command()
141
- @handle_service_errors(ConbusLightlevelError)
142
164
  def xp_lightlevel_get(
143
165
  ctx: click.Context, serial_number: str, output_number: int
144
166
  ) -> None:
@@ -154,18 +176,32 @@ def xp_lightlevel_get(
154
176
  xp conbus lightlevel get 0123450001 2 # Get light level for output 2
155
177
  xp conbus lightlevel get 0011223344 0 # Get light level for output 0
156
178
  """
179
+ # Get service from container
180
+ service: ConbusDatapointService = (
181
+ ctx.obj.get("container").get_container().resolve(ConbusDatapointService)
182
+ )
183
+ telegram_service: TelegramDatapointService = (
184
+ ctx.obj.get("container").get_container().resolve(TelegramDatapointService)
185
+ )
157
186
 
158
- def finish(response: "ConbusLightlevelResponse") -> None:
187
+ def on_finish(service_response: "ConbusDatapointResponse") -> None:
159
188
  """Handle successful completion of light level get command.
160
189
 
161
190
  Args:
162
- response: Light level response object.
191
+ service_response: Light level response object.
163
192
  """
164
- click.echo(json.dumps(response.to_dict(), indent=2))
165
-
166
- service = (
167
- ctx.obj.get("container").get_container().resolve(ConbusLightlevelSetService)
168
- )
193
+ lightlevel_level = telegram_service.get_lightlevel(
194
+ service_response.data_value, output_number
195
+ )
196
+ result = service_response.to_dict()
197
+ result["output_number"] = output_number
198
+ result["lightlevel_level"] = lightlevel_level
199
+ click.echo(json.dumps(result, indent=2))
169
200
 
170
201
  with service:
171
- service.get_lightlevel(serial_number, output_number, finish, 0.5)
202
+ service.query_datapoint(
203
+ serial_number=serial_number,
204
+ datapoint_type=DataPointType.MODULE_LIGHT_LEVEL,
205
+ finish_callback=on_finish,
206
+ timeout_seconds=0.5,
207
+ )
@@ -9,9 +9,12 @@ from xp.cli.utils.decorators import (
9
9
  connection_command,
10
10
  )
11
11
  from xp.cli.utils.serial_number_type import SERIAL
12
- from xp.models.conbus.conbus_linknumber import ConbusLinknumberResponse
13
- from xp.services.conbus.conbus_linknumber_get_service import ConbusLinknumberGetService
14
- from xp.services.conbus.conbus_linknumber_set_service import ConbusLinknumberSetService
12
+ from xp.models import ConbusDatapointResponse
13
+ from xp.models.conbus.conbus_writeconfig import ConbusWriteConfigResponse
14
+ from xp.models.telegram.datapoint_type import DataPointType
15
+ from xp.services.conbus.conbus_datapoint_service import ConbusDatapointService
16
+ from xp.services.conbus.write_config_service import WriteConfigService
17
+ from xp.services.telegram.telegram_datapoint_service import TelegramDatapointService
15
18
 
16
19
 
17
20
  @conbus_linknumber.command("set", short_help="Set link number for a module")
@@ -33,23 +36,27 @@ def set_linknumber_command(
33
36
  \b
34
37
  xp conbus linknumber set 0123450001 25
35
38
  """
36
- service = (
37
- ctx.obj.get("container").get_container().resolve(ConbusLinknumberSetService)
38
- )
39
39
 
40
- def on_finish(response: ConbusLinknumberResponse) -> None:
41
- """Handle successful completion of link number set command.
40
+ def on_finish(response: "ConbusWriteConfigResponse") -> None:
41
+ """Handle successful completion of light level on command.
42
42
 
43
43
  Args:
44
- response: Link number response object.
44
+ response: Light level response object.
45
45
  """
46
46
  click.echo(json.dumps(response.to_dict(), indent=2))
47
47
 
48
+ service: WriteConfigService = (
49
+ ctx.obj.get("container").get_container().resolve(WriteConfigService)
50
+ )
51
+
52
+ data_value = f"{link_number: 02d}"
48
53
  with service:
49
- service.set_linknumber(
54
+ service.write_config(
50
55
  serial_number=serial_number,
51
- link_number=link_number,
56
+ datapoint_type=DataPointType.LINK_NUMBER,
57
+ data_value=data_value,
52
58
  finish_callback=on_finish,
59
+ timeout_seconds=0.5,
53
60
  )
54
61
 
55
62
 
@@ -68,20 +75,28 @@ def get_linknumber_command(ctx: click.Context, serial_number: str) -> None:
68
75
  \b
69
76
  xp conbus linknumber get 0123450001
70
77
  """
71
- service = (
72
- ctx.obj.get("container").get_container().resolve(ConbusLinknumberGetService)
78
+ service: ConbusDatapointService = (
79
+ ctx.obj.get("container").get_container().resolve(ConbusDatapointService)
80
+ )
81
+ telegram_service: TelegramDatapointService = (
82
+ ctx.obj.get("container").get_container().resolve(TelegramDatapointService)
73
83
  )
74
84
 
75
- def on_finish(response: ConbusLinknumberResponse) -> None:
85
+ def on_finish(service_response: ConbusDatapointResponse) -> None:
76
86
  """Handle successful completion of link number get command.
77
87
 
78
88
  Args:
79
- response: Link number response object.
89
+ service_response: Link number response object.
80
90
  """
81
- click.echo(json.dumps(response.to_dict(), indent=2))
91
+ linknumber_value = telegram_service.get_linknumber(service_response.data_value)
92
+ result = service_response.to_dict()
93
+ result["linknumber_value"] = linknumber_value
94
+ click.echo(json.dumps(result, indent=2))
82
95
 
83
96
  with service:
84
- service.get_linknumber(
97
+ service.query_datapoint(
85
98
  serial_number=serial_number,
99
+ datapoint_type=DataPointType.LINK_NUMBER,
86
100
  finish_callback=on_finish,
101
+ timeout_seconds=0.5,
87
102
  )
@@ -2,6 +2,7 @@
2
2
 
3
3
  import json
4
4
  from dataclasses import asdict
5
+ from typing import Union
5
6
 
6
7
  import click
7
8
  from click import Context
@@ -12,7 +13,9 @@ from xp.cli.utils.decorators import (
12
13
  )
13
14
  from xp.cli.utils.serial_number_type import SERIAL
14
15
  from xp.cli.utils.xp_module_type import XP_MODULE_TYPE
15
- from xp.models.actiontable.actiontable import ActionTable
16
+ from xp.models.actiontable.msactiontable_xp20 import Xp20MsActionTable
17
+ from xp.models.actiontable.msactiontable_xp24 import Xp24MsActionTable
18
+ from xp.models.actiontable.msactiontable_xp33 import Xp33MsActionTable
16
19
  from xp.services.conbus.actiontable.msactiontable_service import (
17
20
  MsActionTableService,
18
21
  )
@@ -33,7 +36,9 @@ def conbus_download_msactiontable(
33
36
  serial_number: 10-digit module serial number.
34
37
  xpmoduletype: XP module type.
35
38
  """
36
- service = ctx.obj.get("container").get_container().resolve(MsActionTableService)
39
+ service: MsActionTableService = (
40
+ ctx.obj.get("container").get_container().resolve(MsActionTableService)
41
+ )
37
42
 
38
43
  def progress_callback(progress: str) -> None:
39
44
  """Handle progress updates during MS action table download.
@@ -43,7 +48,9 @@ def conbus_download_msactiontable(
43
48
  """
44
49
  click.echo(progress, nl=False)
45
50
 
46
- def finish_callback(action_table: ActionTable) -> None:
51
+ def on_finish(
52
+ action_table: Union[Xp20MsActionTable | Xp24MsActionTable | Xp33MsActionTable],
53
+ ) -> None:
47
54
  """Handle successful completion of MS action table download.
48
55
 
49
56
  Args:
@@ -73,6 +80,6 @@ def conbus_download_msactiontable(
73
80
  serial_number=serial_number,
74
81
  xpmoduletype=xpmoduletype,
75
82
  progress_callback=progress_callback,
76
- finish_callback=finish_callback,
83
+ finish_callback=on_finish,
77
84
  error_callback=error_callback,
78
85
  )
@@ -34,7 +34,9 @@ def xp_output_on(ctx: click.Context, serial_number: str, output_number: int) ->
34
34
  \b
35
35
  xp conbus output on 0011223344 0 # Turn on output 0
36
36
  """
37
- service = ctx.obj.get("container").get_container().resolve(ConbusOutputService)
37
+ service: ConbusOutputService = (
38
+ ctx.obj.get("container").get_container().resolve(ConbusOutputService)
39
+ )
38
40
 
39
41
  def on_finish(response: ConbusOutputResponse) -> None:
40
42
  """Handle successful completion of output on command.
@@ -70,7 +72,9 @@ def xp_output_off(ctx: click.Context, serial_number: str, output_number: int) ->
70
72
  \b
71
73
  xp conbus output off 0011223344 1 # Turn off output 1
72
74
  """
73
- service = ctx.obj.get("container").get_container().resolve(ConbusOutputService)
75
+ service: ConbusOutputService = (
76
+ ctx.obj.get("container").get_container().resolve(ConbusOutputService)
77
+ )
74
78
 
75
79
  def on_finish(response: ConbusOutputResponse) -> None:
76
80
  """Handle successful completion of output off command.
@@ -36,7 +36,7 @@ def receive_telegrams(ctx: Context, timeout: float) -> None:
36
36
  xp conbus receive 5.0
37
37
  """
38
38
 
39
- def finish(response_received: ConbusReceiveResponse) -> None:
39
+ def on_finish(response_received: ConbusReceiveResponse) -> None:
40
40
  """Handle successful completion of telegram receive operation.
41
41
 
42
42
  Args:
@@ -52,6 +52,8 @@ def receive_telegrams(ctx: Context, timeout: float) -> None:
52
52
  """
53
53
  click.echo(telegram_received)
54
54
 
55
- service = ctx.obj.get("container").get_container().resolve(ConbusReceiveService)
55
+ service: ConbusReceiveService = (
56
+ ctx.obj.get("container").get_container().resolve(ConbusReceiveService)
57
+ )
56
58
  with service:
57
- service.start(progress, finish, timeout)
59
+ service.start(progress, on_finish, timeout)
@@ -56,7 +56,9 @@ def decode_log_file(
56
56
  from xp.services.log_file_service import LogFileService
57
57
  from xp.utils.time_utils import TimeParsingError, parse_time_range
58
58
 
59
- service = ctx.obj.get("container").get_container().resolve(LogFileService)
59
+ service: LogFileService = (
60
+ ctx.obj.get("container").get_container().resolve(LogFileService)
61
+ )
60
62
  StatisticsFormatter(True)
61
63
 
62
64
  try:
@@ -124,7 +126,9 @@ def analyze_log_file(ctx: Context, log_file_path: str) -> None:
124
126
  """
125
127
  from xp.services.log_file_service import LogFileService
126
128
 
127
- service = ctx.obj.get("container").get_container().resolve(LogFileService)
129
+ service: LogFileService = (
130
+ ctx.obj.get("container").get_container().resolve(LogFileService)
131
+ )
128
132
  StatisticsFormatter(True)
129
133
 
130
134
  try:
@@ -156,7 +160,9 @@ def validate_log_file(ctx: Context, log_file_path: str) -> None:
156
160
  """
157
161
  from xp.services.log_file_service import LogFileService
158
162
 
159
- service = ctx.obj.get("container").get_container().resolve(LogFileService)
163
+ service: LogFileService = (
164
+ ctx.obj.get("container").get_container().resolve(LogFileService)
165
+ )
160
166
  OutputFormatter(True)
161
167
 
162
168
  try:
@@ -28,7 +28,9 @@ def homekit_start(ctx: Context) -> None:
28
28
  click.echo("Starting XP Protocol HomeKit server...")
29
29
 
30
30
  try:
31
- service = ctx.obj.get("container").get_container().resolve(HomeKitService)
31
+ service: HomeKitService = (
32
+ ctx.obj.get("container").get_container().resolve(HomeKitService)
33
+ )
32
34
  service.start() # Blocking call - reactor.run() never returns
33
35
 
34
36
  except KeyboardInterrupt:
@@ -37,7 +37,9 @@ def module_info(ctx: Context, identifier: str) -> None:
37
37
  xp module info 14
38
38
  xp module info XP2606
39
39
  """
40
- service = ctx.obj.get("container").get_container().resolve(ModuleTypeService)
40
+ service: ModuleTypeService = (
41
+ ctx.obj.get("container").get_container().resolve(ModuleTypeService)
42
+ )
41
43
  OutputFormatter(True)
42
44
 
43
45
  try:
@@ -76,7 +78,9 @@ def module_list(ctx: Context, category: str, group_by_category: bool) -> None:
76
78
  xp module list --category "Interface Panels"
77
79
  xp module list --group-by-category
78
80
  """
79
- service = ctx.obj.get("container").get_container().resolve(ModuleTypeService)
81
+ service: ModuleTypeService = (
82
+ ctx.obj.get("container").get_container().resolve(ModuleTypeService)
83
+ )
80
84
  ListFormatter(True)
81
85
 
82
86
  try:
@@ -130,7 +134,9 @@ def module_search(ctx: Context, query: str, field: tuple) -> None:
130
134
  xp module search "push button"
131
135
  xp module search --field name "XP"
132
136
  """
133
- service = ctx.obj.get("container").get_container().resolve(ModuleTypeService)
137
+ service: ModuleTypeService = (
138
+ ctx.obj.get("container").get_container().resolve(ModuleTypeService)
139
+ )
134
140
  ListFormatter(True)
135
141
 
136
142
  try:
@@ -162,7 +168,9 @@ def module_categories(ctx: Context) -> None:
162
168
  \b
163
169
  xp module categories
164
170
  """
165
- service = ctx.obj.get("container").get_container().resolve(ModuleTypeService)
171
+ service: ModuleTypeService = (
172
+ ctx.obj.get("container").get_container().resolve(ModuleTypeService)
173
+ )
166
174
  OutputFormatter(True)
167
175
 
168
176
  try:
@@ -73,7 +73,9 @@ def start_proxy(ctx: Context, port: int, config: str) -> None:
73
73
  raise SystemExit(1)
74
74
 
75
75
  # Load configuration and create proxy instance
76
- service = ctx.obj.get("container").get_container().resolve(ReverseProxyService)
76
+ service: ReverseProxyService = (
77
+ ctx.obj.get("container").get_container().resolve(ReverseProxyService)
78
+ )
77
79
  global_proxy_instance = service
78
80
 
79
81
  # Handle graceful shutdown on SIGINT
xp/cli/main.py CHANGED
@@ -6,7 +6,6 @@ import click
6
6
  from click_help_colors import HelpColorsGroup
7
7
 
8
8
  from xp.cli.commands import homekit
9
- from xp.cli.commands.api import api
10
9
  from xp.cli.commands.conbus.conbus import conbus
11
10
  from xp.cli.commands.file_commands import file
12
11
  from xp.cli.commands.module_commands import module
@@ -79,7 +78,6 @@ cli.add_command(telegram)
79
78
  cli.add_command(module)
80
79
  cli.add_command(file)
81
80
  cli.add_command(server)
82
- cli.add_command(api)
83
81
  cli.add_command(reverse_proxy)
84
82
 
85
83
  # Add the tree command
@@ -21,6 +21,7 @@ class ConbusDatapointResponse:
21
21
  sent_telegram: Telegram sent to device.
22
22
  received_telegrams: List of telegrams received.
23
23
  datapoint_telegram: Parsed datapoint telegram.
24
+ data_value: Value of the datapoint telegram.
24
25
  datapoints: List of datapoint values.
25
26
  error: Error message if operation failed.
26
27
  timestamp: Timestamp of the response.
@@ -33,6 +34,7 @@ class ConbusDatapointResponse:
33
34
  sent_telegram: Optional[str] = None
34
35
  received_telegrams: Optional[list] = None
35
36
  datapoint_telegram: Optional[ReplyTelegram] = None
37
+ data_value: str = ""
36
38
  datapoints: Optional[List[Dict[str, str]]] = None
37
39
  error: Optional[str] = None
38
40
  timestamp: Optional[datetime] = None
@@ -55,6 +57,7 @@ class ConbusDatapointResponse:
55
57
  result: Dict[str, Any] = {
56
58
  "success": self.success,
57
59
  "serial_number": self.serial_number,
60
+ "data_value": self.data_value,
58
61
  "error": self.error,
59
62
  "timestamp": self.timestamp.isoformat() if self.timestamp else None,
60
63
  }
@@ -2,7 +2,23 @@
2
2
 
3
3
  from dataclasses import dataclass
4
4
  from datetime import datetime
5
- from typing import Any, Dict, Optional
5
+ from typing import Any, Dict, Optional, TypedDict
6
+
7
+
8
+ class DiscoveredDevice(TypedDict):
9
+ """Discovered device information.
10
+
11
+ Attributes:
12
+ serial_number: Serial number of the device.
13
+ module_type: Module type name (e.g., "XP24", "XP230"), None if not yet retrieved.
14
+ module_type_code: Module type code (e.g., "13", "10"), None if not yet retrieved.
15
+ module_type_name: Module type name converted from module_type_code, None if not yet retrieved.
16
+ """
17
+
18
+ serial_number: str
19
+ module_type: Optional[str]
20
+ module_type_code: Optional[int]
21
+ module_type_name: Optional[str]
6
22
 
7
23
 
8
24
  @dataclass
@@ -13,7 +29,7 @@ class ConbusDiscoverResponse:
13
29
  success: Whether the operation was successful.
14
30
  sent_telegram: Telegram sent to discover devices.
15
31
  received_telegrams: List of telegrams received.
16
- discovered_devices: List of discovered device serial numbers.
32
+ discovered_devices: List of discovered devices with their module types.
17
33
  error: Error message if operation failed.
18
34
  timestamp: Timestamp of the response.
19
35
  """
@@ -21,7 +37,7 @@ class ConbusDiscoverResponse:
21
37
  success: bool
22
38
  sent_telegram: Optional[str] = None
23
39
  received_telegrams: Optional[list[str]] = None
24
- discovered_devices: Optional[list[str]] = None
40
+ discovered_devices: Optional[list[DiscoveredDevice]] = None
25
41
  error: Optional[str] = None
26
42
  timestamp: Optional[datetime] = None
27
43
 
@@ -0,0 +1,60 @@
1
+ """Conbus link number response model."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Optional
6
+
7
+ from xp.models.telegram.datapoint_type import DataPointType
8
+ from xp.models.telegram.system_function import SystemFunction
9
+
10
+
11
+ @dataclass
12
+ class ConbusWriteConfigResponse:
13
+ """Represents a response from Conbus write config operations (set/get).
14
+
15
+ Attributes:
16
+ success: Whether the operation was successful.
17
+ serial_number: Serial number of the device.
18
+ datapoint_type: the datapoint to write.
19
+ system_function: ACK or NAK received.
20
+ sent_telegram: Telegram sent to device.
21
+ received_telegrams: List of telegrams received.
22
+ data_value: written value.
23
+ error: Error message if operation failed.
24
+ timestamp: Timestamp of the response.
25
+ """
26
+
27
+ success: bool
28
+ serial_number: str
29
+ datapoint_type: Optional[DataPointType] = None
30
+ system_function: Optional[SystemFunction] = None
31
+ sent_telegram: Optional[str] = None
32
+ received_telegrams: Optional[list] = None
33
+ data_value: Optional[str] = None
34
+ error: Optional[str] = None
35
+ timestamp: Optional[datetime] = None
36
+
37
+ def __post_init__(self) -> None:
38
+ """Initialize timestamp and received_telegrams if not provided."""
39
+ if self.timestamp is None:
40
+ self.timestamp = datetime.now()
41
+ if self.received_telegrams is None:
42
+ self.received_telegrams = []
43
+
44
+ def to_dict(self) -> Dict[str, Any]:
45
+ """Convert to dictionary for JSON serialization.
46
+
47
+ Returns:
48
+ Dictionary representation of the response.
49
+ """
50
+ return {
51
+ "success": self.success,
52
+ "system_function": self.system_function,
53
+ "datapoint_type": self.datapoint_type,
54
+ "data_value": self.data_value,
55
+ "serial_number": self.serial_number,
56
+ "sent_telegram": self.sent_telegram,
57
+ "received_telegrams": self.received_telegrams,
58
+ "error": self.error,
59
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
60
+ }
@@ -22,10 +22,10 @@ class SystemTelegram(Telegram):
22
22
  Examples: <S0020012521F02D18FN>
23
23
 
24
24
  Attributes:
25
- serial_number: Serial number of the device.
26
- system_function: System function code.
27
- data: Data payload.
28
- datapoint_type: Type of datapoint.
25
+ serial_number: Serial number of the device (0020012521)
26
+ system_function: System function code (02).
27
+ data: Data payload (18)
28
+ datapoint_type: Type of datapoint (18).
29
29
  """
30
30
 
31
31
  serial_number: str = ""