conson-xp 1.18.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 (176) hide show
  1. conson_xp-1.18.0.dist-info/METADATA +412 -0
  2. conson_xp-1.18.0.dist-info/RECORD +176 -0
  3. conson_xp-1.18.0.dist-info/WHEEL +4 -0
  4. conson_xp-1.18.0.dist-info/entry_points.txt +5 -0
  5. conson_xp-1.18.0.dist-info/licenses/LICENSE +29 -0
  6. xp/__init__.py +9 -0
  7. xp/cli/__init__.py +5 -0
  8. xp/cli/__main__.py +6 -0
  9. xp/cli/commands/__init__.py +153 -0
  10. xp/cli/commands/conbus/__init__.py +25 -0
  11. xp/cli/commands/conbus/conbus.py +128 -0
  12. xp/cli/commands/conbus/conbus_actiontable_commands.py +233 -0
  13. xp/cli/commands/conbus/conbus_autoreport_commands.py +108 -0
  14. xp/cli/commands/conbus/conbus_blink_commands.py +163 -0
  15. xp/cli/commands/conbus/conbus_config_commands.py +29 -0
  16. xp/cli/commands/conbus/conbus_custom_commands.py +57 -0
  17. xp/cli/commands/conbus/conbus_datapoint_commands.py +113 -0
  18. xp/cli/commands/conbus/conbus_discover_commands.py +61 -0
  19. xp/cli/commands/conbus/conbus_event_commands.py +81 -0
  20. xp/cli/commands/conbus/conbus_lightlevel_commands.py +207 -0
  21. xp/cli/commands/conbus/conbus_linknumber_commands.py +102 -0
  22. xp/cli/commands/conbus/conbus_modulenumber_commands.py +104 -0
  23. xp/cli/commands/conbus/conbus_msactiontable_commands.py +94 -0
  24. xp/cli/commands/conbus/conbus_output_commands.py +163 -0
  25. xp/cli/commands/conbus/conbus_raw_commands.py +62 -0
  26. xp/cli/commands/conbus/conbus_receive_commands.py +59 -0
  27. xp/cli/commands/conbus/conbus_scan_commands.py +58 -0
  28. xp/cli/commands/file_commands.py +186 -0
  29. xp/cli/commands/homekit/__init__.py +3 -0
  30. xp/cli/commands/homekit/homekit.py +118 -0
  31. xp/cli/commands/homekit/homekit_start_commands.py +43 -0
  32. xp/cli/commands/module_commands.py +187 -0
  33. xp/cli/commands/reverse_proxy_commands.py +178 -0
  34. xp/cli/commands/server/__init__.py +3 -0
  35. xp/cli/commands/server/server_commands.py +135 -0
  36. xp/cli/commands/telegram/__init__.py +5 -0
  37. xp/cli/commands/telegram/telegram.py +41 -0
  38. xp/cli/commands/telegram/telegram_blink_commands.py +79 -0
  39. xp/cli/commands/telegram/telegram_checksum_commands.py +112 -0
  40. xp/cli/commands/telegram/telegram_discover_commands.py +41 -0
  41. xp/cli/commands/telegram/telegram_linknumber_commands.py +86 -0
  42. xp/cli/commands/telegram/telegram_parse_commands.py +75 -0
  43. xp/cli/commands/telegram/telegram_version_commands.py +52 -0
  44. xp/cli/main.py +87 -0
  45. xp/cli/utils/__init__.py +1 -0
  46. xp/cli/utils/click_tree.py +57 -0
  47. xp/cli/utils/datapoint_type_choice.py +57 -0
  48. xp/cli/utils/decorators.py +351 -0
  49. xp/cli/utils/error_handlers.py +201 -0
  50. xp/cli/utils/formatters.py +312 -0
  51. xp/cli/utils/module_type_choice.py +56 -0
  52. xp/cli/utils/serial_number_type.py +52 -0
  53. xp/cli/utils/system_function_choice.py +57 -0
  54. xp/cli/utils/xp_module_type.py +53 -0
  55. xp/connection/__init__.py +13 -0
  56. xp/connection/exceptions.py +22 -0
  57. xp/models/__init__.py +36 -0
  58. xp/models/actiontable/__init__.py +1 -0
  59. xp/models/actiontable/actiontable.py +43 -0
  60. xp/models/actiontable/msactiontable_xp20.py +53 -0
  61. xp/models/actiontable/msactiontable_xp24.py +58 -0
  62. xp/models/actiontable/msactiontable_xp33.py +65 -0
  63. xp/models/conbus/__init__.py +1 -0
  64. xp/models/conbus/conbus.py +87 -0
  65. xp/models/conbus/conbus_autoreport.py +67 -0
  66. xp/models/conbus/conbus_blink.py +80 -0
  67. xp/models/conbus/conbus_client_config.py +55 -0
  68. xp/models/conbus/conbus_connection_status.py +40 -0
  69. xp/models/conbus/conbus_custom.py +58 -0
  70. xp/models/conbus/conbus_datapoint.py +89 -0
  71. xp/models/conbus/conbus_discover.py +64 -0
  72. xp/models/conbus/conbus_event_raw.py +47 -0
  73. xp/models/conbus/conbus_lightlevel.py +52 -0
  74. xp/models/conbus/conbus_linknumber.py +54 -0
  75. xp/models/conbus/conbus_output.py +57 -0
  76. xp/models/conbus/conbus_raw.py +45 -0
  77. xp/models/conbus/conbus_receive.py +42 -0
  78. xp/models/conbus/conbus_writeconfig.py +60 -0
  79. xp/models/homekit/__init__.py +1 -0
  80. xp/models/homekit/homekit_accessory.py +35 -0
  81. xp/models/homekit/homekit_config.py +106 -0
  82. xp/models/homekit/homekit_conson_config.py +86 -0
  83. xp/models/log_entry.py +130 -0
  84. xp/models/protocol/__init__.py +1 -0
  85. xp/models/protocol/conbus_protocol.py +312 -0
  86. xp/models/response.py +42 -0
  87. xp/models/telegram/__init__.py +1 -0
  88. xp/models/telegram/action_type.py +31 -0
  89. xp/models/telegram/datapoint_type.py +82 -0
  90. xp/models/telegram/event_telegram.py +140 -0
  91. xp/models/telegram/event_type.py +15 -0
  92. xp/models/telegram/input_action_type.py +69 -0
  93. xp/models/telegram/input_type.py +17 -0
  94. xp/models/telegram/module_type.py +188 -0
  95. xp/models/telegram/module_type_code.py +205 -0
  96. xp/models/telegram/output_telegram.py +103 -0
  97. xp/models/telegram/reply_telegram.py +297 -0
  98. xp/models/telegram/system_function.py +116 -0
  99. xp/models/telegram/system_telegram.py +94 -0
  100. xp/models/telegram/telegram.py +28 -0
  101. xp/models/telegram/telegram_type.py +19 -0
  102. xp/models/telegram/timeparam_type.py +51 -0
  103. xp/models/write_config_type.py +33 -0
  104. xp/services/__init__.py +26 -0
  105. xp/services/actiontable/__init__.py +1 -0
  106. xp/services/actiontable/actiontable_serializer.py +273 -0
  107. xp/services/actiontable/msactiontable_serializer.py +7 -0
  108. xp/services/actiontable/msactiontable_xp20_serializer.py +169 -0
  109. xp/services/actiontable/msactiontable_xp24_serializer.py +120 -0
  110. xp/services/actiontable/msactiontable_xp33_serializer.py +239 -0
  111. xp/services/conbus/__init__.py +1 -0
  112. xp/services/conbus/actiontable/__init__.py +1 -0
  113. xp/services/conbus/actiontable/actiontable_download_service.py +158 -0
  114. xp/services/conbus/actiontable/actiontable_list_service.py +91 -0
  115. xp/services/conbus/actiontable/actiontable_show_service.py +89 -0
  116. xp/services/conbus/actiontable/actiontable_upload_service.py +211 -0
  117. xp/services/conbus/actiontable/msactiontable_service.py +232 -0
  118. xp/services/conbus/conbus_blink_all_service.py +181 -0
  119. xp/services/conbus/conbus_blink_service.py +158 -0
  120. xp/services/conbus/conbus_custom_service.py +156 -0
  121. xp/services/conbus/conbus_datapoint_queryall_service.py +182 -0
  122. xp/services/conbus/conbus_datapoint_service.py +170 -0
  123. xp/services/conbus/conbus_discover_service.py +312 -0
  124. xp/services/conbus/conbus_event_raw_service.py +181 -0
  125. xp/services/conbus/conbus_output_service.py +194 -0
  126. xp/services/conbus/conbus_raw_service.py +122 -0
  127. xp/services/conbus/conbus_receive_service.py +115 -0
  128. xp/services/conbus/conbus_scan_service.py +150 -0
  129. xp/services/conbus/write_config_service.py +194 -0
  130. xp/services/homekit/__init__.py +1 -0
  131. xp/services/homekit/homekit_cache_service.py +307 -0
  132. xp/services/homekit/homekit_conbus_service.py +93 -0
  133. xp/services/homekit/homekit_config_validator.py +310 -0
  134. xp/services/homekit/homekit_conson_validator.py +121 -0
  135. xp/services/homekit/homekit_dimminglight.py +182 -0
  136. xp/services/homekit/homekit_dimminglight_service.py +148 -0
  137. xp/services/homekit/homekit_hap_service.py +342 -0
  138. xp/services/homekit/homekit_lightbulb.py +120 -0
  139. xp/services/homekit/homekit_lightbulb_service.py +86 -0
  140. xp/services/homekit/homekit_module_service.py +56 -0
  141. xp/services/homekit/homekit_outlet.py +168 -0
  142. xp/services/homekit/homekit_outlet_service.py +121 -0
  143. xp/services/homekit/homekit_service.py +359 -0
  144. xp/services/log_file_service.py +309 -0
  145. xp/services/module_type_service.py +257 -0
  146. xp/services/protocol/__init__.py +21 -0
  147. xp/services/protocol/conbus_event_protocol.py +360 -0
  148. xp/services/protocol/conbus_protocol.py +318 -0
  149. xp/services/protocol/protocol_factory.py +78 -0
  150. xp/services/protocol/telegram_protocol.py +264 -0
  151. xp/services/reverse_proxy_service.py +435 -0
  152. xp/services/server/__init__.py +1 -0
  153. xp/services/server/base_server_service.py +366 -0
  154. xp/services/server/cp20_server_service.py +65 -0
  155. xp/services/server/device_service_factory.py +94 -0
  156. xp/services/server/server_service.py +428 -0
  157. xp/services/server/xp130_server_service.py +67 -0
  158. xp/services/server/xp20_server_service.py +92 -0
  159. xp/services/server/xp230_server_service.py +58 -0
  160. xp/services/server/xp24_server_service.py +245 -0
  161. xp/services/server/xp33_server_service.py +535 -0
  162. xp/services/telegram/__init__.py +1 -0
  163. xp/services/telegram/telegram_blink_service.py +138 -0
  164. xp/services/telegram/telegram_checksum_service.py +149 -0
  165. xp/services/telegram/telegram_datapoint_service.py +82 -0
  166. xp/services/telegram/telegram_discover_service.py +277 -0
  167. xp/services/telegram/telegram_link_number_service.py +216 -0
  168. xp/services/telegram/telegram_output_service.py +322 -0
  169. xp/services/telegram/telegram_service.py +380 -0
  170. xp/services/telegram/telegram_version_service.py +288 -0
  171. xp/utils/__init__.py +12 -0
  172. xp/utils/checksum.py +61 -0
  173. xp/utils/dependencies.py +531 -0
  174. xp/utils/event_helper.py +31 -0
  175. xp/utils/serialization.py +205 -0
  176. xp/utils/time_utils.py +134 -0
@@ -0,0 +1,140 @@
1
+ """Event telegram model for console bus communication."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Optional
6
+
7
+ from xp.models.telegram.event_type import EventType
8
+ from xp.models.telegram.input_type import InputType
9
+ from xp.models.telegram.module_type import ModuleType
10
+ from xp.models.telegram.telegram import Telegram
11
+ from xp.models.telegram.telegram_type import TelegramType
12
+
13
+
14
+ @dataclass
15
+ class EventTelegram(Telegram):
16
+ r"""Represent a parsed event telegram from the console bus.
17
+
18
+ Format: <[EO]{module_type}L{link_number}I{input_number}{event_type}{checksum}>
19
+
20
+ Examples:
21
+ <E14L00I02MAK>
22
+
23
+ Attributes:
24
+ event_telegram_type: Event telegram type (E or O).
25
+ module_type: Module type code.
26
+ link_number: Link number.
27
+ input_number: Input number.
28
+ event_type: Type of event (press or release).
29
+ module_info: Module type information if found.
30
+ input_type: Input type based on input number.
31
+ is_button_press: True if this is a button press event.
32
+ is_button_release: True if this is a button release event.
33
+ """
34
+
35
+ event_telegram_type: str = "E" # E or O
36
+ module_type: int = 0
37
+ link_number: int = 0
38
+ input_number: int = 0
39
+ event_type: Optional[EventType] = None
40
+
41
+ def __post_init__(self) -> None:
42
+ """Initialize timestamp and telegram type."""
43
+ if self.timestamp is None:
44
+ self.timestamp = datetime.now()
45
+ self.telegram_type = TelegramType.EVENT
46
+
47
+ @property
48
+ def module_info(self) -> Optional[ModuleType]:
49
+ """Get module type information for this telegram.
50
+
51
+ Returns:
52
+ ModuleType instance if found, None otherwise.
53
+ """
54
+ return ModuleType.from_code(self.module_type)
55
+
56
+ @property
57
+ def input_type(self) -> InputType:
58
+ """Determines the input type based on input number.
59
+
60
+ Returns:
61
+ InputType enum value.
62
+ """
63
+ if 0 <= self.input_number <= 9:
64
+ return InputType.PUSH_BUTTON
65
+ elif 10 <= self.input_number <= 89:
66
+ return InputType.IR_REMOTE
67
+ elif self.input_number == 90:
68
+ return InputType.PROXIMITY_SENSOR
69
+ else:
70
+ raise ValueError(f"Invalid input number: {self.input_number}")
71
+
72
+ @property
73
+ def is_button_press(self) -> bool:
74
+ """True if this is a button press event.
75
+
76
+ Returns:
77
+ True if event is a button press, False otherwise.
78
+ """
79
+ return self.event_type == EventType.BUTTON_PRESS
80
+
81
+ @property
82
+ def is_button_release(self) -> bool:
83
+ """True if this is a button release event.
84
+
85
+ Returns:
86
+ True if event is a button release, False otherwise.
87
+ """
88
+ return self.event_type == EventType.BUTTON_RELEASE
89
+
90
+ def to_dict(self) -> dict[str, Any]:
91
+ """Convert to dictionary for JSON serialization.
92
+
93
+ Returns:
94
+ Dictionary representation of the event telegram.
95
+ """
96
+ result: dict[str, Any] = {
97
+ "module_type": self.module_type,
98
+ "link_number": self.link_number,
99
+ "output_number": self.input_number,
100
+ "event_type": self.event_type.value if self.event_type else None,
101
+ "event_type_name": (
102
+ "button_press" if self.is_button_press else "button_release"
103
+ ),
104
+ "input_type": self.input_type.value,
105
+ "checksum": self.checksum,
106
+ "checksum_validated": self.checksum_validated,
107
+ "raw_telegram": self.raw_telegram,
108
+ "timestamp": self.timestamp.isoformat() if self.timestamp else None,
109
+ "telegram_type": self.telegram_type.value,
110
+ }
111
+
112
+ # Add module information if available
113
+ if self.module_info:
114
+ result["module_info"] = {
115
+ "name": self.module_info.name,
116
+ "description": self.module_info.description,
117
+ "category": self.module_info.category,
118
+ }
119
+ else:
120
+ result["module_info"] = None
121
+
122
+ return result
123
+
124
+ def __str__(self) -> str:
125
+ """Human-readable string representation.
126
+
127
+ Returns:
128
+ Formatted string representation.
129
+ """
130
+ event_desc = "pressed" if self.is_button_press else "released"
131
+
132
+ # Include module name if available
133
+ module_desc = f"Module {self.module_type}"
134
+ if self.module_info:
135
+ module_desc = f"{self.module_info.name} (Type {self.module_type})"
136
+
137
+ return (
138
+ f"{module_desc} Link {self.link_number:02d} "
139
+ f"Input {self.input_number:02d} ({self.input_type.value}) {event_desc}"
140
+ )
@@ -0,0 +1,15 @@
1
+ """Event type enumeration for telegram events."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class EventType(Enum):
7
+ """Event types for telegraph events.
8
+
9
+ Attributes:
10
+ BUTTON_PRESS: Button make (press) event.
11
+ BUTTON_RELEASE: Button break (release) event.
12
+ """
13
+
14
+ BUTTON_PRESS = "M" # Make
15
+ BUTTON_RELEASE = "B" # Break
@@ -0,0 +1,69 @@
1
+ """Input action types for XP24 module based on Feature-Action-Table.md."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class InputActionType(Enum):
7
+ """Input action types for XP24 module (based on Feature-Action-Table.md).
8
+
9
+ Attributes:
10
+ VOID: No action.
11
+ ON: Turn on action.
12
+ OFF: Turn off action.
13
+ TOGGLE: Toggle action.
14
+ BLOCK: Block action.
15
+ AUXRELAY: Auxiliary relay action.
16
+ MUTUALEX: Mutual exclusion action.
17
+ LEVELUP: Level up action.
18
+ LEVELDOWN: Level down action.
19
+ LEVELINC: Level increment action.
20
+ LEVELDEC: Level decrement action.
21
+ LEVELSET: Level set action.
22
+ FADETIME: Fade time action.
23
+ SCENESET: Scene set action.
24
+ SCENENEXT: Scene next action.
25
+ SCENEPREV: Scene previous action.
26
+ CTRLMETHOD: Control method action.
27
+ RETURNDATA: Return data action.
28
+ DELAYEDON: Delayed on action.
29
+ EVENTTIMER1: Event timer 1 action.
30
+ EVENTTIMER2: Event timer 2 action.
31
+ EVENTTIMER3: Event timer 3 action.
32
+ EVENTTIMER4: Event timer 4 action.
33
+ STEPCTRL: Step control action.
34
+ STEPCTRLUP: Step control up action.
35
+ STEPCTRLDOWN: Step control down action.
36
+ LEVELSETINTERN: Level set internal action.
37
+ FADE: Fade action.
38
+ LEARN: Learn action.
39
+ """
40
+
41
+ VOID = 0
42
+ ON = 1
43
+ OFF = 2
44
+ TOGGLE = 3
45
+ BLOCK = 4
46
+ AUXRELAY = 5
47
+ MUTUALEX = 6
48
+ LEVELUP = 7
49
+ LEVELDOWN = 8
50
+ LEVELINC = 9
51
+ LEVELDEC = 10
52
+ LEVELSET = 11
53
+ FADETIME = 12
54
+ SCENESET = 13
55
+ SCENENEXT = 14
56
+ SCENEPREV = 15
57
+ CTRLMETHOD = 16
58
+ RETURNDATA = 17
59
+ DELAYEDON = 18
60
+ EVENTTIMER1 = 19
61
+ EVENTTIMER2 = 20
62
+ EVENTTIMER3 = 21
63
+ EVENTTIMER4 = 22
64
+ STEPCTRL = 23
65
+ STEPCTRLUP = 24
66
+ STEPCTRLDOWN = 25
67
+ LEVELSETINTERN = 29
68
+ FADE = 30
69
+ LEARN = 31
@@ -0,0 +1,17 @@
1
+ """Input type enumeration based on input number ranges."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class InputType(Enum):
7
+ """Input types based on input number ranges.
8
+
9
+ Attributes:
10
+ PUSH_BUTTON: Push button input (range 00-09).
11
+ IR_REMOTE: IR remote input (range 10-89).
12
+ PROXIMITY_SENSOR: Proximity sensor input (input 90).
13
+ """
14
+
15
+ PUSH_BUTTON = "push_button" # Input 00-09
16
+ IR_REMOTE = "ir_remote" # Input 10-89
17
+ PROXIMITY_SENSOR = "proximity_sensor" # Input 90
@@ -0,0 +1,188 @@
1
+ """Module type models for the XP system."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Dict, List, Optional
5
+
6
+ from xp.models.telegram.module_type_code import MODULE_TYPE_REGISTRY
7
+
8
+
9
+ @dataclass
10
+ class ModuleType:
11
+ """Represents a module type in the XP system.
12
+
13
+ Contains the module code, name, and description.
14
+
15
+ Attributes:
16
+ code: Numeric module type code.
17
+ name: Module name.
18
+ description: Module description.
19
+ module_category: Module category.
20
+ is_reserved: True if module type is reserved.
21
+ is_push_button_panel: True if module is a push button panel.
22
+ is_ir_capable: True if module has IR capabilities.
23
+ category: Module category based on its type.
24
+ """
25
+
26
+ code: int
27
+ name: str
28
+ description: str
29
+ module_category: str = ""
30
+
31
+ @classmethod
32
+ def from_code(cls, code: int) -> Optional["ModuleType"]:
33
+ """Create ModuleType from a numeric code.
34
+
35
+ Args:
36
+ code: The numeric module type code.
37
+
38
+ Returns:
39
+ ModuleType instance or None if code is invalid.
40
+ """
41
+ module_info = MODULE_TYPE_REGISTRY.get(code)
42
+ if module_info:
43
+ return cls(code=code, **module_info)
44
+ return None
45
+
46
+ @classmethod
47
+ def from_name(cls, name: str) -> Optional["ModuleType"]:
48
+ """Create ModuleType from a module name.
49
+
50
+ Args:
51
+ name: The module name (case-insensitive).
52
+
53
+ Returns:
54
+ ModuleType instance or None if name is invalid.
55
+ """
56
+ name_upper = name.upper()
57
+ for code, info in MODULE_TYPE_REGISTRY.items():
58
+ if info["name"].upper() == name_upper:
59
+ return cls(code=code, **info)
60
+ return None
61
+
62
+ @property
63
+ def is_reserved(self) -> bool:
64
+ """Check if this module type is reserved.
65
+
66
+ Returns:
67
+ True if module type is reserved, False otherwise.
68
+ """
69
+ return self.name in ("XP26X1", "XP26X2")
70
+
71
+ @property
72
+ def is_push_button_panel(self) -> bool:
73
+ """Check if this module type is a push button panel.
74
+
75
+ Returns:
76
+ True if module is a push button panel, False otherwise.
77
+ """
78
+ return self.name in (
79
+ "XP2606",
80
+ "XP2606A",
81
+ "XP2606B",
82
+ "XP2506",
83
+ "XP2506A",
84
+ "XP2506B",
85
+ "XPX1_8",
86
+ )
87
+
88
+ @property
89
+ def is_ir_capable(self) -> bool:
90
+ """Check if this module type has IR capabilities.
91
+
92
+ Returns:
93
+ True if module has IR capabilities, False otherwise.
94
+ """
95
+ return any(ir_type in self.name for ir_type in ("38kHz", "B&O")) or any(
96
+ ir_code in self.name
97
+ for ir_code in (
98
+ "CP70A",
99
+ "CP70B",
100
+ "XP2606A",
101
+ "XP2606B",
102
+ "XP2506A",
103
+ "XP2506B",
104
+ )
105
+ )
106
+
107
+ @property
108
+ def category(self) -> str:
109
+ """Get the module category based on its type.
110
+
111
+ Returns:
112
+ Module category string.
113
+ """
114
+ if self.code <= 1:
115
+ return "System"
116
+ elif 2 <= self.code <= 6:
117
+ return "CP Link Modules"
118
+ elif 7 <= self.code <= 13:
119
+ return "XP Control Modules"
120
+ elif 14 <= self.code <= 24:
121
+ return "Interface Panels"
122
+ return "Unknown"
123
+
124
+ def to_dict(self) -> Dict:
125
+ """Convert to dictionary for JSON serialization.
126
+
127
+ Returns:
128
+ Dictionary representation of the module type.
129
+ """
130
+ return {
131
+ "code": self.code,
132
+ "name": self.name,
133
+ "description": self.description,
134
+ "category": self.category,
135
+ "is_reserved": self.is_reserved,
136
+ "is_push_button_panel": self.is_push_button_panel,
137
+ "is_ir_capable": self.is_ir_capable,
138
+ }
139
+
140
+ def __str__(self) -> str:
141
+ """Return human-readable string representation.
142
+
143
+ Returns:
144
+ Formatted string representation.
145
+ """
146
+ return f"{self.name} (Code {self.code}): {self.description}"
147
+
148
+
149
+ def get_all_module_types() -> List[ModuleType]:
150
+ """Get all available module types.
151
+
152
+ Returns:
153
+ List of all ModuleType instances.
154
+ """
155
+ return [
156
+ module_type
157
+ for module_type in [
158
+ ModuleType.from_code(code) for code in sorted(MODULE_TYPE_REGISTRY.keys())
159
+ ]
160
+ if module_type is not None
161
+ ]
162
+
163
+
164
+ def get_module_types_by_category() -> Dict[str, List[ModuleType]]:
165
+ """Get module types grouped by category.
166
+
167
+ Returns:
168
+ Dictionary mapping category names to lists of ModuleType instances.
169
+ """
170
+ categories: Dict[str, List[ModuleType]] = {}
171
+ for module_type in get_all_module_types():
172
+ category = module_type.category
173
+ if category not in categories:
174
+ categories[category] = []
175
+ categories[category].append(module_type)
176
+ return categories
177
+
178
+
179
+ def is_valid_module_code(code: int) -> bool:
180
+ """Check if a module code is valid.
181
+
182
+ Args:
183
+ code: Module code to validate.
184
+
185
+ Returns:
186
+ True if code is valid, False otherwise.
187
+ """
188
+ return code in MODULE_TYPE_REGISTRY
@@ -0,0 +1,205 @@
1
+ """Module type code enumeration for XP system modules."""
2
+
3
+ from enum import Enum
4
+ from typing import Dict
5
+
6
+
7
+ class ModuleTypeCode(Enum):
8
+ """Enum representing all XP system module type codes.
9
+
10
+ Attributes:
11
+ NOMOD: No module (code 0).
12
+ ALLMOD: Matches every module type (code 1).
13
+ CP20: CP switch link module (code 2).
14
+ CP70A: CP 38kHz IR link module (code 3).
15
+ CP70B: CP B&O IR link module (code 4).
16
+ CP70C: CP UHF link module (code 5).
17
+ CP70D: CP timer link module (code 6).
18
+ XP24: XP relay module (code 7).
19
+ XP31UNI: XP universal load light dimmer (code 8).
20
+ XP31BCU: XP ballast controller 0-10V (code 9).
21
+ XP31DD: XP ballast controller DSI/DALI (code 10).
22
+ XP33: XP 3-channel light dimmer (code 11).
23
+ CP485: CP RS485 interface module (code 12).
24
+ XP130: Ethernet/TCP/IP interface module (code 13).
25
+ XP2606: 5-way push button panel with sesam (code 14).
26
+ XP2606A: 5-way push button with IR receiver (code 15).
27
+ XP2606B: 5-way push button with B&O IR (code 16).
28
+ XP26X1: Reserved (code 17).
29
+ XP26X2: Reserved (code 18).
30
+ XP2506: 5-way push button panel with sesam Conson design (code 19).
31
+ XP2506A: 5-way push button panel with sesam and 38kHz IR Conson design (code 20).
32
+ XP2506B: 5-way push button panel with sesam and B&O IR Conson design (code 21).
33
+ XPX1_8: 8-way push button panel interface (code 22).
34
+ XP134: Junctionbox interlink (code 23).
35
+ XP24P: XP24P module (code 24).
36
+ XP28A: XP28A module (code 25).
37
+ XP28B: XP28B module (code 26).
38
+ CONTOOL: CONTOOL module (code 27).
39
+ XP28: XP28 module (code 28).
40
+ XP31LR: XP 1-channel lightdimmer (code 29).
41
+ XP33LR: XP 33 3-channel lightdimmer (code 30).
42
+ XP31CR: XP 31 1-channel dimmer (code 31).
43
+ XP31BC: XP 31 1-channel dimmer (code 32).
44
+ XP20: XP switch link module (code 33).
45
+ XP230: Ethernet/TCPIP interface module (code 34).
46
+ XP33LED: XP 3-channel LED dimmer (code 35).
47
+ XP31LED: XP 1-channel LED dimmer (code 36).
48
+ """
49
+
50
+ NOMOD = 0 # No module
51
+ ALLMOD = 1 # Code matching every moduletype
52
+ CP20 = 2 # CP switch link module
53
+ CP70A = 3 # CP 38kHz IR link module
54
+ CP70B = 4 # CP B&O IR link module
55
+ CP70C = 5 # CP UHF link module
56
+ CP70D = 6 # CP timer link module
57
+ XP24 = 7 # XP relay module
58
+ XP31UNI = 8 # XP universal load light dimmer
59
+ XP31BCU = 9 # XP ballast controller, 0-10VActions
60
+ XP31DD = 10 # XP ballast controller DSI/DALI
61
+ XP33 = 11 # XP 33 3 channel lightdimmer
62
+ CP485 = 12 # CP RS485 interface module
63
+ XP130 = 13 # Ethernet/TCPIP interface module
64
+ XP2606 = 14 # 5 way push button panel with sesam, L-Team design
65
+ XP2606A = 15 # 5 way push button panel with sesam,
66
+ # L-Team design and 38kHz IR receiver
67
+ XP2606B = 16 # 5 way push button panel with sesam,
68
+ # L-Team design and B&O IR receiver
69
+ XP26X1 = 17 # Reserved
70
+ XP26X2 = 18 # Reserved
71
+ XP2506 = 19 # 5 way push button panel with sesam, Conson design
72
+ XP2506A = 20 # 5 way push button panel with sesam and 38kHz IR, Conson design
73
+ XP2506B = 21 # 5 way push button panel with sesam and B&O IR, Conson design
74
+ XPX1_8 = 22 # 8 way push button panel interface
75
+ XP134 = 23 # Junctionbox interlink
76
+ XP24P = 24 # XP24P module
77
+ XP28A = 25 #
78
+ XP28B = 26 #
79
+ CONTOOL = 27 #
80
+ XP28 = 28 #
81
+ XP31LR = 29 # XP 1 channel lightdimmer
82
+ XP33LR = 30 # XP 33 3 channel lightdimmer
83
+ XP31CR = 31 # XP 31 1 channel dimmer
84
+ XP31BC = 32 # XP 31 1 channel dimmer
85
+ XP20 = 33 # XP switch link module
86
+ XP230 = 34 # Ethernet/TCPIP interface module
87
+ XP33LED = 35 # XP 3 channel LED dimmer
88
+ XP31LED = 36 # XP 1 channel LED dimmer
89
+
90
+
91
+ # Registry mapping module codes to their information
92
+ MODULE_TYPE_REGISTRY: Dict[int, Dict[str, str]] = {
93
+ ModuleTypeCode.NOMOD.value: {"name": "NOMOD", "description": "No module"},
94
+ ModuleTypeCode.ALLMOD.value: {
95
+ "name": "ALLMOD",
96
+ "description": "Code matching every moduletype",
97
+ },
98
+ ModuleTypeCode.CP20.value: {"name": "CP20", "description": "CP switch link module"},
99
+ ModuleTypeCode.CP70A.value: {
100
+ "name": "CP70A",
101
+ "description": "CP 38kHz IR link module",
102
+ },
103
+ ModuleTypeCode.CP70B.value: {
104
+ "name": "CP70B",
105
+ "description": "CP B&O IR link module",
106
+ },
107
+ ModuleTypeCode.CP70C.value: {"name": "CP70C", "description": "CP UHF link module"},
108
+ ModuleTypeCode.CP70D.value: {
109
+ "name": "CP70D",
110
+ "description": "CP timer link module",
111
+ },
112
+ ModuleTypeCode.XP24.value: {"name": "XP24", "description": "XP relay module"},
113
+ ModuleTypeCode.XP31UNI.value: {
114
+ "name": "XP31UNI",
115
+ "description": "XP universal load light dimmer",
116
+ },
117
+ ModuleTypeCode.XP31BCU.value: {
118
+ "name": "XP31BC",
119
+ "description": "XP ballast controller, 0-10VActions",
120
+ },
121
+ ModuleTypeCode.XP31DD.value: {
122
+ "name": "XP31DD",
123
+ "description": "XP ballast controller DSI/DALI",
124
+ },
125
+ ModuleTypeCode.XP33.value: {
126
+ "name": "XP33",
127
+ "description": "XP 33 3 channel lightdimmer",
128
+ },
129
+ ModuleTypeCode.CP485.value: {
130
+ "name": "CP485",
131
+ "description": "CP RS485 interface module",
132
+ },
133
+ ModuleTypeCode.XP130.value: {
134
+ "name": "XP130",
135
+ "description": "Ethernet/TCPIP interface module",
136
+ },
137
+ ModuleTypeCode.XP2606.value: {
138
+ "name": "XP2606",
139
+ "description": "5 way push button panel with sesam, L-Team design",
140
+ },
141
+ ModuleTypeCode.XP2606A.value: {
142
+ "name": "XP2606A",
143
+ "description": "5 way push button panel with sesam, L-Team design and 38kHz IR receiver",
144
+ },
145
+ ModuleTypeCode.XP2606B.value: {
146
+ "name": "XP2606B",
147
+ "description": "5 way push button panel with sesam, L-Team design and B&O IR receiver",
148
+ },
149
+ ModuleTypeCode.XP26X1.value: {"name": "XP26X1", "description": "Reserved"},
150
+ ModuleTypeCode.XP26X2.value: {"name": "XP26X2", "description": "Reserved"},
151
+ ModuleTypeCode.XP2506.value: {
152
+ "name": "XP2506",
153
+ "description": "5 way push button panel with sesam, Conson design",
154
+ },
155
+ ModuleTypeCode.XP2506A.value: {
156
+ "name": "XP2506A",
157
+ "description": "5 way push button panel with sesam and 38kHz IR, Conson design",
158
+ },
159
+ ModuleTypeCode.XP2506B.value: {
160
+ "name": "XP2506B",
161
+ "description": "5 way push button panel with sesam and B&O IR, Conson design",
162
+ },
163
+ ModuleTypeCode.XPX1_8.value: {
164
+ "name": "XPX1_8",
165
+ "description": "8 way push button panel interface",
166
+ },
167
+ ModuleTypeCode.XP134.value: {
168
+ "name": "XP134",
169
+ "description": "Junctionbox interlink",
170
+ },
171
+ ModuleTypeCode.XP24P.value: {"name": "XP24P", "description": "XP24P module"},
172
+ ModuleTypeCode.XP28A.value: {"name": "XP28A", "description": "XP28A module"},
173
+ ModuleTypeCode.XP28B.value: {"name": "XP28B", "description": "XP28B module"},
174
+ ModuleTypeCode.CONTOOL.value: {"name": "CONTOOL", "description": "CONTOOL module"},
175
+ ModuleTypeCode.XP28.value: {"name": "XP28", "description": "XP28 module"},
176
+ ModuleTypeCode.XP31LR.value: {
177
+ "name": "XP31LR",
178
+ "description": "XP 1 channel lightdimmer",
179
+ },
180
+ ModuleTypeCode.XP33LR.value: {
181
+ "name": "XP33LR",
182
+ "description": "XP 33 3 channel lightdimmer",
183
+ },
184
+ ModuleTypeCode.XP31CR.value: {
185
+ "name": "XP31CR",
186
+ "description": "XP 31 1 channel dimmer",
187
+ },
188
+ ModuleTypeCode.XP31BC.value: {
189
+ "name": "XP31BC",
190
+ "description": "XP 31 1 channel dimmer",
191
+ },
192
+ ModuleTypeCode.XP20.value: {"name": "XP20", "description": "XP switch link module"},
193
+ ModuleTypeCode.XP230.value: {
194
+ "name": "XP230",
195
+ "description": "Ethernet/TCPIP interface module",
196
+ },
197
+ ModuleTypeCode.XP33LED.value: {
198
+ "name": "XP33LED",
199
+ "description": "XP 3 channel LED dimmer",
200
+ },
201
+ ModuleTypeCode.XP31LED.value: {
202
+ "name": "XP31LED",
203
+ "description": "XP 1 channel LED dimmer",
204
+ },
205
+ }