python-hotspring 2.0.1__py3-none-any.whl → 3.0.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.
hotspring/__init__.py CHANGED
@@ -2,8 +2,11 @@
2
2
 
3
3
  from .const import (
4
4
  BrightnessLevel,
5
+ DeviceType,
6
+ EnergySavingMode,
5
7
  HeatingMode,
6
8
  JetSpeed,
9
+ JetSpeedType,
7
10
  LightColor,
8
11
  LightWheelMode,
9
12
  SpaBrand,
@@ -15,7 +18,9 @@ from .exceptions import (
15
18
  HotSpringConnectionError,
16
19
  HotSpringConnectionTimeoutError,
17
20
  HotSpringError,
21
+ HotSpringInvalidDeviceError,
18
22
  HotSpringNotReadyError,
23
+ HotSpringSNADetectedError,
19
24
  )
20
25
  from .hotspring import HotSpring
21
26
  from .models import (
@@ -32,6 +37,7 @@ from .models import (
32
37
  Spa,
33
38
  SpaInfo,
34
39
  SpaLock,
40
+ SpaTestData,
35
41
  Versions,
36
42
  WaterCare,
37
43
  )
@@ -41,8 +47,10 @@ __all__ = [
41
47
  "BrightnessLevel",
42
48
  "CleanCycle",
43
49
  "ConnectionStatus",
50
+ "DeviceType",
44
51
  "Diagnostics",
45
52
  "EnergySaving",
53
+ "EnergySavingMode",
46
54
  "FreshWaterIQ",
47
55
  "Heater",
48
56
  "HeatingMode",
@@ -51,9 +59,12 @@ __all__ = [
51
59
  "HotSpringConnectionError",
52
60
  "HotSpringConnectionTimeoutError",
53
61
  "HotSpringError",
62
+ "HotSpringInvalidDeviceError",
54
63
  "HotSpringNotReadyError",
64
+ "HotSpringSNADetectedError",
55
65
  "Jet",
56
66
  "JetSpeed",
67
+ "JetSpeedType",
57
68
  "LightColor",
58
69
  "LightWheelMode",
59
70
  "LightZone",
@@ -63,6 +74,7 @@ __all__ = [
63
74
  "SpaFailureState",
64
75
  "SpaInfo",
65
76
  "SpaLock",
77
+ "SpaTestData",
66
78
  "TemperatureUnit",
67
79
  "Versions",
68
80
  "WaterCare",
hotspring/const.py CHANGED
@@ -75,6 +75,35 @@ class JetSpeed(Enum):
75
75
  _JET_SPEED_MAP: dict[str, JetSpeed] = {s.value: s for s in JetSpeed}
76
76
 
77
77
 
78
+ class JetSpeedType(Enum):
79
+ """Configured speed capability of a jet pump."""
80
+
81
+ UNKNOWN = "unknown"
82
+ SINGLE_SPEED = "singleSpeed"
83
+ DUAL_SPEED = "dualSpeed"
84
+
85
+ @classmethod
86
+ def build(cls, value: str | None) -> JetSpeedType:
87
+ """Parse a raw API string into a JetSpeedType.
88
+
89
+ Args:
90
+ ----
91
+ value: The raw speed configuration string from the API, or None.
92
+
93
+ Returns:
94
+ -------
95
+ The matching JetSpeedType, or JetSpeedType.UNKNOWN for
96
+ unrecognized values.
97
+
98
+ """
99
+ if value is None:
100
+ return cls.UNKNOWN
101
+ return _JET_SPEED_TYPE_MAP.get(value, cls.UNKNOWN)
102
+
103
+
104
+ _JET_SPEED_TYPE_MAP: dict[str, JetSpeedType] = {t.value: t for t in JetSpeedType}
105
+
106
+
78
107
  class LightColor(Enum):
79
108
  """Color setting for a spa light zone.
80
109
 
@@ -153,12 +182,13 @@ class BrightnessLevel(Enum):
153
182
  """
154
183
 
155
184
  UNKNOWN = "unknown"
185
+ AUTO = "auto"
156
186
  LEVEL_1 = "brightness_level_1"
157
187
  LEVEL_2 = "brightness_level_2"
158
188
  LEVEL_3 = "brightness_level_3"
159
189
 
160
190
  @classmethod
161
- def build(cls, value: str | None) -> BrightnessLevel:
191
+ def build(cls, value: str | int | None) -> BrightnessLevel:
162
192
  """Parse a raw API string into a BrightnessLevel.
163
193
 
164
194
  Args:
@@ -173,10 +203,49 @@ class BrightnessLevel(Enum):
173
203
  """
174
204
  if value is None:
175
205
  return cls.UNKNOWN
176
- return _BRIGHTNESS_MAP.get(value, cls.UNKNOWN)
206
+ val_str = str(value).strip().lower()
207
+ return _BRIGHTNESS_MAP.get(val_str, cls.UNKNOWN)
177
208
 
178
209
 
179
210
  _BRIGHTNESS_MAP: dict[str, BrightnessLevel] = {b.value: b for b in BrightnessLevel}
211
+ _BRIGHTNESS_MAP.update(
212
+ {
213
+ "1": BrightnessLevel.LEVEL_1,
214
+ "2": BrightnessLevel.LEVEL_2,
215
+ "3": BrightnessLevel.LEVEL_3,
216
+ "auto": BrightnessLevel.AUTO,
217
+ }
218
+ )
219
+
220
+ _BRIGHTNESS_TO_WIRE: dict[BrightnessLevel, str] = {
221
+ BrightnessLevel.LEVEL_1: "1",
222
+ BrightnessLevel.LEVEL_2: "2",
223
+ BrightnessLevel.LEVEL_3: "3",
224
+ BrightnessLevel.AUTO: "auto",
225
+ }
226
+
227
+ MAX_ENERGY_SAVING_SCHEDULES = 2
228
+ VALID_ENERGY_SAVING_SCHEDULE_IDS = (1, 2)
229
+
230
+
231
+ class EnergySavingMode(Enum):
232
+ """Energy saving schedule mode."""
233
+
234
+ UNKNOWN = "unknown"
235
+ OFF = "off"
236
+ ON = "on"
237
+
238
+ @classmethod
239
+ def build(cls, value: object) -> EnergySavingMode:
240
+ """Parse raw mode from API into EnergySavingMode."""
241
+ if value is None:
242
+ return cls.UNKNOWN
243
+ val_str = str(value).strip().lower()
244
+ if val_str in ("1", "on", "enable", "true"):
245
+ return cls.ON
246
+ if val_str in ("0", "off", "disable", "false"):
247
+ return cls.OFF
248
+ return cls.UNKNOWN
180
249
 
181
250
 
182
251
  class TemperatureUnit(Enum):
@@ -408,3 +477,36 @@ def resolve_spa_model(
408
477
  model_name = SPA_MODEL_MAP.get((brand_id, collection_id, model_id), "Unknown")
409
478
 
410
479
  return (brand, collection, model_name)
480
+
481
+
482
+ class DeviceType(Enum):
483
+ """Connected Spa kit adapter device type.
484
+
485
+ The Connected Spa Kit 2 consists of two modules:
486
+ - HNA (Home Network Adapter): Connected to home network, acts as API bridge.
487
+ - SNA (Spa Network Adapter): Located in the tub, physically wired to controller.
488
+ """
489
+
490
+ UNKNOWN = "unknown"
491
+ HNA = "hna"
492
+ SNA = "sna"
493
+
494
+ @classmethod
495
+ def build(cls, value: str | None) -> DeviceType:
496
+ """Parse a raw string into a DeviceType.
497
+
498
+ Args:
499
+ ----
500
+ value: The raw device type string, or None.
501
+
502
+ Returns:
503
+ -------
504
+ The matching DeviceType, or DeviceType.UNKNOWN for unrecognized values.
505
+
506
+ """
507
+ if value is None:
508
+ return cls.UNKNOWN
509
+ return _DEVICE_TYPE_MAP.get(value.lower(), cls.UNKNOWN)
510
+
511
+
512
+ _DEVICE_TYPE_MAP: dict[str, DeviceType] = {d.value: d for d in DeviceType}
hotspring/exceptions.py CHANGED
@@ -26,3 +26,18 @@ class HotSpringCommandError(HotSpringError):
26
26
 
27
27
  Raised when a command sent to the spa is rejected or fails.
28
28
  """
29
+
30
+
31
+ class HotSpringInvalidDeviceError(HotSpringError):
32
+ """Hot Spring invalid device exception.
33
+
34
+ Raised when attempting to connect to or command an unsupported device.
35
+ """
36
+
37
+
38
+ class HotSpringSNADetectedError(HotSpringInvalidDeviceError):
39
+ """Hot Spring SNA detected exception.
40
+
41
+ Raised when connecting to a Spa Network Adapter (SNA) instead of
42
+ the Home Network Adapter (HNA). The HNA must be used as the API bridge.
43
+ """