python-hotspring 1.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 ADDED
@@ -0,0 +1,67 @@
1
+ """Asynchronous Python client for Hot Spring Connected Spa Kit 2."""
2
+
3
+ from .const import (
4
+ BrightnessLevel,
5
+ HeatingMode,
6
+ JetSpeed,
7
+ LightColor,
8
+ LightWheelMode,
9
+ SpaFailureState,
10
+ TemperatureUnit,
11
+ )
12
+ from .exceptions import (
13
+ HotSpringCommandError,
14
+ HotSpringConnectionError,
15
+ HotSpringConnectionTimeoutError,
16
+ HotSpringError,
17
+ HotSpringNotReadyError,
18
+ )
19
+ from .hotspring import HotSpring
20
+ from .models import (
21
+ Blower,
22
+ CleanCycle,
23
+ ConnectionStatus,
24
+ Diagnostics,
25
+ EnergySaving,
26
+ FreshWaterIQ,
27
+ Heater,
28
+ Jet,
29
+ LightZone,
30
+ LogoLight,
31
+ Spa,
32
+ SpaInfo,
33
+ SpaLock,
34
+ Versions,
35
+ WaterCare,
36
+ )
37
+
38
+ __all__ = [
39
+ "Blower",
40
+ "BrightnessLevel",
41
+ "CleanCycle",
42
+ "ConnectionStatus",
43
+ "Diagnostics",
44
+ "EnergySaving",
45
+ "FreshWaterIQ",
46
+ "Heater",
47
+ "HeatingMode",
48
+ "HotSpring",
49
+ "HotSpringCommandError",
50
+ "HotSpringConnectionError",
51
+ "HotSpringConnectionTimeoutError",
52
+ "HotSpringError",
53
+ "HotSpringNotReadyError",
54
+ "Jet",
55
+ "JetSpeed",
56
+ "LightColor",
57
+ "LightWheelMode",
58
+ "LightZone",
59
+ "LogoLight",
60
+ "Spa",
61
+ "SpaFailureState",
62
+ "SpaInfo",
63
+ "SpaLock",
64
+ "TemperatureUnit",
65
+ "Versions",
66
+ "WaterCare",
67
+ ]
hotspring/const.py ADDED
@@ -0,0 +1,237 @@
1
+ """Constants and enumerations for Hot Spring Connected Spa Kit 2."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import Enum
6
+
7
+
8
+ class HeatingMode(Enum):
9
+ """Heating mode for the spa heater.
10
+
11
+ Controls how the spa manages water temperature regulation.
12
+ """
13
+
14
+ UNKNOWN = "unknown"
15
+ INVALID = "invalid"
16
+ HEAT_SAVER = "heatSaver"
17
+ HEAT_WITH_BOOST = "heatWithBoost"
18
+ CHILL = "chill"
19
+ AUTO_WITH_BOOST = "autoWithBoost"
20
+ AUTO_SAVER = "autoSaver"
21
+
22
+ @classmethod
23
+ def build(cls, value: str | None) -> HeatingMode:
24
+ """Parse a raw API string into a HeatingMode.
25
+
26
+ Args:
27
+ ----
28
+ value: The raw heating mode string from the API, or None.
29
+
30
+ Returns:
31
+ -------
32
+ The matching HeatingMode, or HeatingMode.UNKNOWN for
33
+ unrecognised values.
34
+
35
+ """
36
+ if value is None:
37
+ return cls.UNKNOWN
38
+ return _HEATING_MODE_MAP.get(value, cls.UNKNOWN)
39
+
40
+
41
+ _HEATING_MODE_MAP: dict[str, HeatingMode] = {m.value: m for m in HeatingMode}
42
+
43
+
44
+ class JetSpeed(Enum):
45
+ """Speed setting for a spa jet pump.
46
+
47
+ Jets can be single-speed or multi-speed depending on the spa model.
48
+ """
49
+
50
+ UNKNOWN = "unknown"
51
+ OFF = "off"
52
+ LOW_SPEED = "lowSpeed"
53
+ HIGH_SPEED = "highSpeed"
54
+ SINGLE_SPEED = "singleSpeed"
55
+
56
+ @classmethod
57
+ def build(cls, value: str | None) -> JetSpeed:
58
+ """Parse a raw API string into a JetSpeed.
59
+
60
+ Args:
61
+ ----
62
+ value: The raw jet speed string from the API, or None.
63
+
64
+ Returns:
65
+ -------
66
+ The matching JetSpeed, or JetSpeed.UNKNOWN for
67
+ unrecognised values.
68
+
69
+ """
70
+ if value is None:
71
+ return cls.UNKNOWN
72
+ return _JET_SPEED_MAP.get(value, cls.UNKNOWN)
73
+
74
+
75
+ _JET_SPEED_MAP: dict[str, JetSpeed] = {s.value: s for s in JetSpeed}
76
+
77
+
78
+ class LightColor(Enum):
79
+ """Color setting for a spa light zone.
80
+
81
+ Represents the available color options for multi-zone LED lighting.
82
+ """
83
+
84
+ UNKNOWN = "unknown"
85
+ OFF = "WHEEL_OFF"
86
+ ON = "WHEEL_ON"
87
+ RED = "RED"
88
+ BLUE = "BLUE"
89
+ GREEN = "GREEN"
90
+ YELLOW = "YELLOW"
91
+ WHITE = "WHITE"
92
+ AQUA = "AQUA"
93
+ MAGENTA = "MAGENTA"
94
+
95
+ @classmethod
96
+ def build(cls, value: str | None) -> LightColor:
97
+ """Parse a raw API string into a LightColor.
98
+
99
+ Case-insensitive matching (real API returns e.g. "BLUE").
100
+
101
+ Args:
102
+ ----
103
+ value: The raw color string from the API, or None.
104
+
105
+ Returns:
106
+ -------
107
+ The matching LightColor, or LightColor.UNKNOWN for
108
+ unrecognised values.
109
+
110
+ """
111
+ if value is None:
112
+ return cls.UNKNOWN
113
+ return _LIGHT_COLOR_MAP.get(value.upper(), cls.UNKNOWN)
114
+
115
+
116
+ _LIGHT_COLOR_MAP: dict[str, LightColor] = {c.value.upper(): c for c in LightColor}
117
+
118
+
119
+ class LightWheelMode(Enum):
120
+ """Mode for the color light wheel loop."""
121
+
122
+ UNKNOWN = "unknown"
123
+ OFF = "off"
124
+ ON = "on"
125
+ LOOP_UP = "loopUp"
126
+ LOOP_DOWN = "loopDown"
127
+
128
+ @classmethod
129
+ def build(cls, value: str | None) -> LightWheelMode:
130
+ """Parse a raw API string into a LightWheelMode.
131
+
132
+ Args:
133
+ ----
134
+ value: The raw light wheel string from the API, or None.
135
+
136
+ Returns:
137
+ -------
138
+ The matching LightWheelMode, or LightWheelMode.UNKNOWN for
139
+ unrecognised values.
140
+
141
+ """
142
+ if value is None:
143
+ return cls.UNKNOWN
144
+ return _LIGHT_WHEEL_MAP.get(value, cls.UNKNOWN)
145
+
146
+
147
+ _LIGHT_WHEEL_MAP: dict[str, LightWheelMode] = {w.value: w for w in LightWheelMode}
148
+
149
+
150
+ class BrightnessLevel(Enum):
151
+ """Brightness level for the spa logo light.
152
+
153
+ The logo light supports a limited set of discrete brightness levels.
154
+ """
155
+
156
+ UNKNOWN = "unknown"
157
+ LEVEL_1 = "brightness_level_1"
158
+ LEVEL_2 = "brightness_level_2"
159
+ LEVEL_3 = "brightness_level_3"
160
+
161
+ @classmethod
162
+ def build(cls, value: str | None) -> BrightnessLevel:
163
+ """Parse a raw API string into a BrightnessLevel.
164
+
165
+ Args:
166
+ ----
167
+ value: The raw brightness string from the API, or None.
168
+
169
+ Returns:
170
+ -------
171
+ The matching BrightnessLevel, or BrightnessLevel.UNKNOWN for
172
+ unrecognised values.
173
+
174
+ """
175
+ if value is None:
176
+ return cls.UNKNOWN
177
+ return _BRIGHTNESS_MAP.get(value, cls.UNKNOWN)
178
+
179
+
180
+ _BRIGHTNESS_MAP: dict[str, BrightnessLevel] = {b.value: b for b in BrightnessLevel}
181
+
182
+
183
+ class TemperatureUnit(Enum):
184
+ """Unit of temperature measurement used by the spa."""
185
+
186
+ UNKNOWN = "unknown"
187
+ FAHRENHEIT = "DegF"
188
+ CELSIUS = "DegC"
189
+
190
+ @classmethod
191
+ def build(cls, value: str | None) -> TemperatureUnit:
192
+ """Parse a raw API string into a TemperatureUnit.
193
+
194
+ Args:
195
+ ----
196
+ value: The raw temperature unit string from the API, or None.
197
+
198
+ Returns:
199
+ -------
200
+ The matching TemperatureUnit, or TemperatureUnit.UNKNOWN for
201
+ unrecognised values.
202
+
203
+ """
204
+ if value is None:
205
+ return cls.UNKNOWN
206
+ return _TEMP_UNIT_MAP.get(value, cls.UNKNOWN)
207
+
208
+
209
+ _TEMP_UNIT_MAP: dict[str, TemperatureUnit] = {t.value: t for t in TemperatureUnit}
210
+
211
+
212
+ class SpaFailureState(Enum):
213
+ """Failure state of the spa as reported by diagnostics."""
214
+
215
+ UNKNOWN = "unknown"
216
+ OK = "Spa_Ok"
217
+
218
+ @classmethod
219
+ def build(cls, value: str | None) -> SpaFailureState:
220
+ """Parse a raw API string into a SpaFailureState.
221
+
222
+ Args:
223
+ ----
224
+ value: The raw failure state string from the API, or None.
225
+
226
+ Returns:
227
+ -------
228
+ The matching SpaFailureState, or SpaFailureState.UNKNOWN for
229
+ unrecognised values.
230
+
231
+ """
232
+ if value is None:
233
+ return cls.UNKNOWN
234
+ return _FAILURE_STATE_MAP.get(value, cls.UNKNOWN)
235
+
236
+
237
+ _FAILURE_STATE_MAP: dict[str, SpaFailureState] = {s.value: s for s in SpaFailureState}
@@ -0,0 +1,28 @@
1
+ """Exceptions for Hot Spring Connected Spa Kit 2."""
2
+
3
+
4
+ class HotSpringError(Exception):
5
+ """Generic Hot Spring exception."""
6
+
7
+
8
+ class HotSpringConnectionError(HotSpringError):
9
+ """Hot Spring connection exception."""
10
+
11
+
12
+ class HotSpringConnectionTimeoutError(HotSpringConnectionError):
13
+ """Hot Spring connection timeout exception."""
14
+
15
+
16
+ class HotSpringNotReadyError(HotSpringError):
17
+ """Hot Spring SNA not ready exception.
18
+
19
+ Raised when the LoRA bridge between the HNA (house) and SNA (spa)
20
+ is not connected. Commands will fail and status data may be stale.
21
+ """
22
+
23
+
24
+ class HotSpringCommandError(HotSpringError):
25
+ """Hot Spring command error exception.
26
+
27
+ Raised when a command sent to the spa is rejected or fails.
28
+ """