Skip to content

Commit f6ff7c0

Browse files
committed
feat: implement new omnitype data
BREAKING CHANGE: Many items that previously returned a raw int value now parse a proper enum value. Specifically Chlorinator operating_state, ColorLogic Light special_effect, Heater why_on, Pump why_on
1 parent 9b85cfd commit f6ff7c0

9 files changed

Lines changed: 60 additions & 27 deletions

File tree

pyomnilogic_local/chlorinator.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@
88
from pyomnilogic_local.decorators import control_method
99
from pyomnilogic_local.models.mspconfig import MSPChlorinator
1010
from pyomnilogic_local.models.telemetry import TelemetryChlorinator
11-
from pyomnilogic_local.omnitypes import ChlorinatorMSPConfigMode, ChlorinatorStatus
11+
from pyomnilogic_local.omnitypes import ChlorinatorMode, ChlorinatorStatus
1212
from pyomnilogic_local.util import OmniEquipmentNotInitializedError
1313

1414
if TYPE_CHECKING:
1515
from pyomnilogic_local.models.telemetry import Telemetry
1616
from pyomnilogic_local.omnilogic import OmniLogic
17-
from pyomnilogic_local.omnitypes import ChlorinatorCellType, ChlorinatorDispenserType, ChlorinatorOperatingMode
17+
from pyomnilogic_local.omnitypes import (
18+
ChlorinatorCellType,
19+
ChlorinatorDispenserType,
20+
ChlorinatorOperatingMode,
21+
ChlorinatorOperatingState,
22+
)
1823

1924

2025
class Chlorinator(OmniEquipment[MSPChlorinator, TelemetryChlorinator]):
@@ -94,12 +99,12 @@ def cell_type(self) -> ChlorinatorCellType:
9499

95100
# Expose Telemetry attributes
96101
@property
97-
def operating_state(self) -> int:
102+
def operating_state(self) -> ChlorinatorOperatingState:
98103
"""Current operational state of the chlorinator (raw value)."""
99104
return self.telemetry.operating_state
100105

101106
@property
102-
def mode(self) -> ChlorinatorMSPConfigMode:
107+
def mode(self) -> ChlorinatorMode:
103108
"""Current operating mode from MSP Config (NOT_CONFIGURED, TIMED, ORP_AUTO).
104109
105110
TThis data appears to have some discrepancies with the mode reported in the Telemetry.
@@ -421,7 +426,7 @@ async def set_timed_percent(self, percent: int) -> None:
421426
)
422427

423428
@control_method
424-
async def set_op_mode(self, op_mode: ChlorinatorMSPConfigMode) -> None:
429+
async def set_op_mode(self, op_mode: ChlorinatorMode) -> None:
425430
"""Set the operating mode for chlorine generation.
426431
427432
Args:
@@ -453,9 +458,9 @@ async def set_op_mode(self, op_mode: ChlorinatorMSPConfigMode) -> None:
453458

454459
new_op_mode: int
455460
match op_mode:
456-
case ChlorinatorMSPConfigMode.TIMED:
461+
case ChlorinatorMode.TIMED:
457462
new_op_mode = 1
458-
case ChlorinatorMSPConfigMode.ORP_AUTO:
463+
case ChlorinatorMode.ORP_AUTO:
459464
new_op_mode = 2
460465
case _:
461466
msg = f"Unsupported operating mode: {op_mode}"

pyomnilogic_local/colorlogiclight.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
if TYPE_CHECKING:
1515
from pyomnilogic_local.models.telemetry import Telemetry
1616
from pyomnilogic_local.omnilogic import OmniLogic
17-
from pyomnilogic_local.omnitypes import LightShows
17+
from pyomnilogic_local.omnitypes import ColorLogicSpecialEffect, LightShows
1818

1919
_LOGGER = logging.getLogger(__name__)
2020

@@ -197,7 +197,7 @@ def brightness(self) -> ColorLogicBrightness:
197197
return ColorLogicBrightness.ONE_HUNDRED_PERCENT
198198

199199
@property
200-
def special_effect(self) -> int:
200+
def special_effect(self) -> ColorLogicSpecialEffect:
201201
"""Returns the current special effect."""
202202
return self.telemetry.special_effect
203203

pyomnilogic_local/heater.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
if TYPE_CHECKING:
1414
from pyomnilogic_local.models.telemetry import Telemetry
1515
from pyomnilogic_local.omnilogic import OmniLogic
16-
from pyomnilogic_local.omnitypes import HeaterMode
16+
from pyomnilogic_local.omnitypes import HeaterMode, HeaterWhyOn
1717

1818

1919
class Heater(OmniEquipment[MSPVirtualHeater, TelemetryVirtualHeater]):
@@ -173,7 +173,7 @@ def silent_mode(self) -> int:
173173
return self.telemetry.silent_mode
174174

175175
@property
176-
def why_on(self) -> int:
176+
def why_on(self) -> HeaterWhyOn:
177177
"""Returns the reason why the heater is on from telemetry.
178178
179179
We don't have a good understanding of what these values mean yet

pyomnilogic_local/models/mspconfig.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
BodyOfWaterType,
2121
ChlorinatorCellType,
2222
ChlorinatorDispenserType,
23-
ChlorinatorMSPConfigMode,
23+
ChlorinatorMode,
2424
ChlorinatorType,
2525
ColorLogicLightType,
2626
ColorLogicShow25,
@@ -218,7 +218,7 @@ class MSPChlorinator(OmniBase):
218218
omni_type: OmniType = OmniType.CHLORINATOR
219219

220220
enabled: bool = Field(alias="Enabled")
221-
mode: ChlorinatorMSPConfigMode = Field(alias="Mode")
221+
mode: ChlorinatorMode = Field(alias="Mode")
222222
timed_percent: int = Field(alias="Timed-Percent")
223223
superchlor_timeout: int = Field(alias="SuperChlor-Timeout")
224224
orp_timeout: int = Field(alias="ORP-Timeout")
@@ -377,7 +377,7 @@ class MSPSchedule(OmniBase):
377377
bow_id: int = Field(alias="bow-system-id") # pyright: ignore[reportGeneralTypeIssues]
378378
equipment_id: int = Field(alias="equipment-id")
379379
system_id: int = Field(alias="schedule-system-id")
380-
event: MessageType = Field(alias="event")
380+
event: MessageType | int = Field(alias="event")
381381
data: int = Field(alias="data")
382382
enabled: bool = Field()
383383
start_minute: int = Field(alias="start-minute")

pyomnilogic_local/models/telemetry.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
ChlorinatorAlert,
1212
ChlorinatorError,
1313
ChlorinatorOperatingMode,
14+
ChlorinatorOperatingState,
1415
ChlorinatorStatus,
1516
ColorLogicBrightness,
1617
ColorLogicLightType,
@@ -19,6 +20,7 @@
1920
ColorLogicShow40,
2021
ColorLogicShowUCL,
2122
ColorLogicShowUCLV2,
23+
ColorLogicSpecialEffect,
2224
ColorLogicSpeed,
2325
CSADMode,
2426
CSADStatus,
@@ -28,10 +30,12 @@
2830
GroupState,
2931
HeaterMode,
3032
HeaterState,
33+
HeaterWhyOn,
3134
LightShows,
3235
OmniType,
3336
PentairShow,
3437
PumpState,
38+
PumpWhyOn,
3539
RelayState,
3640
RelayWhyOn,
3741
ValveActuatorState,
@@ -127,7 +131,7 @@ class TelemetryChlorinator(BaseModel):
127131
chlr_alert_raw: int = Field(alias="@chlrAlert")
128132
chlr_error_raw: int = Field(alias="@chlrError")
129133
sc_mode: int = Field(alias="@scMode")
130-
operating_state: int = Field(alias="@operatingState")
134+
operating_state: ChlorinatorOperatingState = Field(alias="@operatingState")
131135
timed_percent: int | None = Field(alias="@Timed-Percent", default=None)
132136
operating_mode: ChlorinatorOperatingMode = Field(alias="@operatingMode")
133137
enable: bool = Field(alias="@enable")
@@ -263,7 +267,7 @@ class TelemetryColorLogicLight(BaseModel):
263267
show: LightShows = Field(alias="@currentShow")
264268
speed: ColorLogicSpeed = Field(alias="@speed")
265269
brightness: ColorLogicBrightness = Field(alias="@brightness")
266-
special_effect: int = Field(alias="@specialEffect")
270+
special_effect: ColorLogicSpecialEffect = Field(alias="@specialEffect")
267271

268272
def show_name(
269273
self, model: ColorLogicLightType, v2: bool
@@ -381,7 +385,7 @@ class TelemetryPump(BaseModel):
381385
state: PumpState = Field(alias="@pumpState")
382386
speed: int = Field(alias="@pumpSpeed")
383387
last_speed: int = Field(alias="@lastSpeed")
384-
why_on: int = Field(alias="@whyOn")
388+
why_on: PumpWhyOn = Field(alias="@whyOn")
385389

386390

387391
class TelemetryRelay(BaseModel):
@@ -447,7 +451,7 @@ class TelemetryVirtualHeater(BaseModel):
447451
solar_set_point: int = Field(alias="@SolarSetPoint")
448452
mode: HeaterMode = Field(alias="@Mode")
449453
silent_mode: int = Field(alias="@SilentMode")
450-
why_on: int = Field(alias="@whyHeaterIsOn")
454+
why_on: HeaterWhyOn = Field(alias="@whyHeaterIsOn")
451455

452456

453457
type TelemetryType = (

pyomnilogic_local/omnitypes.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,14 @@ class ChlorinatorError(PrettyEnum, Flag):
151151
AQUARITE_PCB_ERROR = 1 << 14
152152

153153

154-
class ChlorinatorMSPConfigMode(PrettyEnum, StrEnum):
154+
# Chlorinator Mode is used in the MSPConfig to represent the desired mode
155+
class ChlorinatorMode(PrettyEnum, StrEnum):
155156
DISABLED = "CHLOR_OP_MODE_NOT_CONFIG_R"
156157
TIMED = "CHLOR_OP_MODE_TIMED"
157158
ORP_AUTO = "CHLOR_OP_MODE_ORP_AUTO"
158159

159160

161+
# Chlorinator Operating Mode is used in the Telemetry to represent the current mode
160162
class ChlorinatorOperatingMode(PrettyEnum, IntEnum):
161163
DISABLED = 0
162164
TIMED = 1
@@ -487,6 +489,25 @@ class HeaterMode(PrettyEnum, IntEnum):
487489
OFF = 3 # https://github.com/cryptk/haomnilogic-local/issues/172
488490

489491

492+
class HeaterWhyOn(PrettyEnum, IntEnum):
493+
NO_MESSAGE = 0
494+
STOP_HEATER = 1
495+
BOOST = 2
496+
MANUAL_ON = 3
497+
ON_EVENT = 4
498+
COOLING = 5
499+
SET_CUR_SET_POINT = 6
500+
PAUSE = 7
501+
RESUME = 8
502+
SET_HEATER_SCHEDULE = 9
503+
RESTORE_HEATER_SETPOINT = 10
504+
STOP_COOL_DOWN = 11
505+
SET_SOLAR_SET_POINT = 12
506+
SET_SOLAR_SCHEDULE = 13
507+
RESTORE_SOLAR_SETPOINT = 14
508+
SET_HEATER_MODE = 15
509+
510+
490511
# Pumps
491512
class PumpState(PrettyEnum, IntEnum):
492513
OFF = 0

pyomnilogic_local/pump.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from pyomnilogic_local.util import OmniEquipmentNotInitializedError
1111

1212
if TYPE_CHECKING:
13-
from pyomnilogic_local.omnitypes import PumpFunction
13+
from pyomnilogic_local.omnitypes import PumpFunction, PumpWhyOn
1414

1515

1616
class Pump(OmniEquipment[MSPPump, TelemetryPump]):
@@ -151,7 +151,7 @@ def last_speed(self) -> int:
151151
return self.telemetry.last_speed
152152

153153
@property
154-
def why_on(self) -> int:
154+
def why_on(self) -> PumpWhyOn:
155155
"""Reason why the pump is on.
156156
157157
We don't have a confirmation that these are the same as the FilterWhyOn states yet.

pyomnilogic_local/schedule.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
if TYPE_CHECKING:
1111
from pyomnilogic_local.models.telemetry import Telemetry
1212
from pyomnilogic_local.omnilogic import OmniLogic
13+
from pyomnilogic_local.omnitypes import MessageType
1314

1415

1516
class Schedule(OmniEquipment[MSPSchedule, None]):
@@ -78,9 +79,9 @@ def equipment_id(self) -> int:
7879
return self.mspconfig.equipment_id
7980

8081
@property
81-
def event(self) -> int:
82+
def event(self) -> MessageType | int:
8283
"""Returns the event/action ID that will be executed."""
83-
return self.mspconfig.event.value
84+
return self.mspconfig.event
8485

8586
@property
8687
def data(self) -> int:

tests/test_filter_pump.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
FilterSpeedPresets,
1414
FilterState,
1515
FilterType,
16+
FilterWhyOn,
1617
PumpFunction,
1718
PumpState,
1819
PumpType,
20+
PumpWhyOn,
1921
)
2022
from pyomnilogic_local.pump import Pump
2123

@@ -57,7 +59,7 @@ def sample_filter_telemetry() -> TelemetryFilter:
5759
"@filterState": FilterState.ON,
5860
"@filterSpeed": 60,
5961
"@valvePosition": 1,
60-
"@whyFilterIsOn": 14,
62+
"@whyFilterIsOn": FilterWhyOn.TIMED_EVENT,
6163
"@reportedFilterSpeed": 60,
6264
"@power": 500,
6365
"@lastSpeed": 50,
@@ -95,7 +97,7 @@ def sample_pump_telemetry() -> TelemetryPump:
9597
"@pumpState": PumpState.ON,
9698
"@pumpSpeed": 60,
9799
"@lastSpeed": 50,
98-
"@whyOn": 11,
100+
"@whyOn": PumpWhyOn.MANUAL_ON,
99101
},
100102
)
101103

@@ -142,7 +144,7 @@ def test_filter_properties_telemetry(self, mock_omni: Mock, sample_filter_config
142144
assert filter_obj.state == FilterState.ON
143145
assert filter_obj.speed == 60
144146
assert filter_obj.valve_position == 1
145-
assert filter_obj.why_on == 14
147+
assert filter_obj.why_on == FilterWhyOn.TIMED_EVENT
146148
assert filter_obj.reported_speed == 60
147149
assert filter_obj.power == 500
148150
assert filter_obj.last_speed == 50
@@ -291,7 +293,7 @@ def test_pump_properties_telemetry(self, mock_omni: Mock, sample_pump_config: MS
291293
assert pump_obj.state == PumpState.ON
292294
assert pump_obj.speed == 60
293295
assert pump_obj.last_speed == 50
294-
assert pump_obj.why_on == 11
296+
assert pump_obj.why_on == PumpWhyOn.MANUAL_ON
295297

296298
def test_pump_is_on_true(self, mock_omni: Mock, sample_pump_config: MSPPump, mock_telemetry: Mock) -> None:
297299
"""Test is_on returns True when pump is on."""

0 commit comments

Comments
 (0)