From 288a3d1aefba69f480d6a4a7b0c19ddad35eba8b Mon Sep 17 00:00:00 2001 From: Keilin Date: Sun, 14 Jan 2024 14:17:46 -0500 Subject: [PATCH 1/2] Add foot warmer support for Climate360 beds --- asyncsleepiq/consts.py | 5 +++++ asyncsleepiq/fuzion/foot_warmer.py | 25 +++++++++++++++++++++++++ asyncsleepiq/fuzion/foundation.py | 14 ++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 asyncsleepiq/fuzion/foot_warmer.py diff --git a/asyncsleepiq/consts.py b/asyncsleepiq/consts.py index 61f4513..0bcc918 100644 --- a/asyncsleepiq/consts.py +++ b/asyncsleepiq/consts.py @@ -14,12 +14,14 @@ BED_LIGHTS = [RIGHT_NIGHT_STAND, LEFT_NIGHT_STAND, RIGHT_NIGHT_LIGHT, LEFT_NIGHT_LIGHT] + class FootWarmingTemps(int, enum.Enum): OFF = 0 LOW = 31 MEDIUM = 57 HIGH = 72 + FAVORITE = 1 READ = 2 WATCH_TV = 3 @@ -101,4 +103,7 @@ class End(str, enum.Enum): "SetActuatorTargetPosition": "ACTS", "SetTargetPresetWithoutTimer": "ASTP", "GetCurrentPreset": "AGCP", + "GetFootwarmingPresence": "FWPG", + "SetFootwarmingSettings": "FWTS", + "GetFootwarmingSettings": "FWTG", } diff --git a/asyncsleepiq/fuzion/foot_warmer.py b/asyncsleepiq/fuzion/foot_warmer.py new file mode 100644 index 0000000..1cb2600 --- /dev/null +++ b/asyncsleepiq/fuzion/foot_warmer.py @@ -0,0 +1,25 @@ +"""Foundation foor warmer for Fuzion SleepIQ API.""" +from __future__ import annotations + +from typing import Any + +from ..consts import SIDES_FULL, FootWarmingTemps +from ..foot_warmer import SleepIQFootWarmer + + +class SleepIQFuzionFootWarmer(SleepIQFootWarmer): + """Foot warmer representation for SleepIQ API.""" + + async def set_foot_warming(self, temperature: FootWarmingTemps, time: int) -> None: + """Set foot warmer state through API.""" + if time <= 0 or time > 360: + raise ValueError("Invalid Time, must be between 0 and 360") + + args = [SIDES_FULL[self.side].lower(), temperature.name.lower(), time] + await self._api.bamkey(self.bed_id, "SetFootwarmingSettings", args) + await self.update({}) + + async def update(self, data: dict[str, Any]) -> None: + """Update the foot warmer through the API.""" + args = [SIDES_FULL[self.side].lower()] + self.preset = await self._api.bamkey(self.bed_id, "GetFootwarmingSettings", args) diff --git a/asyncsleepiq/fuzion/foundation.py b/asyncsleepiq/fuzion/foundation.py index 29b60a4..d54b4cb 100644 --- a/asyncsleepiq/fuzion/foundation.py +++ b/asyncsleepiq/fuzion/foundation.py @@ -11,18 +11,20 @@ PRESET_SNORE, PRESET_TV, PRESET_ZERO_G, + SIDES_FULL, End, Mode, Side, Speed, ) from ..foundation import SleepIQFoundation -from .preset import SleepIQFuzionPreset from .actuator import SleepIQFuzionActuator +from .foot_warmer import SleepIQFuzionFootWarmer from .light import SleepIQFuzionLight +from .preset import SleepIQFuzionPreset FEATURE_NAMES = [ - "bedType", # Not sure what best to call this, but there's one flag at the start of the list that's (from testing) always "dual". + "bedType", # Not sure what best to call this, but there's one flag at the start of the list that's (from testing) always "dual". "pressureControlEnabledFlag", "articulationEnableFlag", "underbedLightEnableFlag", @@ -51,6 +53,7 @@ async def init_features(self) -> None: if self.features["articulationEnableFlag"]: await self.init_actuators() await self.init_presets({}) + await self.init_foot_warmers() async def update_foundation_status(self) -> None: """Update all foundation data from API.""" @@ -101,6 +104,13 @@ async def init_presets(self, data: dict[str, Any]) -> None: await self.update_presets({}) + async def init_foot_warmers(self) -> None: + """Initialize list of foot warmers available on foundation.""" + for side in [Side.LEFT, Side.RIGHT]: + result = await self._api.bamkey(self.bed_id, "GetFootwarmingPresence", args=[SIDES_FULL[side].lower()]) + if result == "1": + self.foot_warmers.append(SleepIQFuzionFootWarmer(self._api, self.bed_id, side, 0, 0)) + async def fetch_features(self) -> None: """Update list of features available for foundation from API.""" vals = await self._api.bamkey(self.bed_id, "GetSystemConfiguration") From 14bc4c1cfd0cf337e0575159c0c6064a9963ce00 Mon Sep 17 00:00:00 2001 From: Keilin Date: Sun, 14 Jan 2024 16:25:25 -0500 Subject: [PATCH 2/2] Fix time passed in as int instead of str --- asyncsleepiq/fuzion/foot_warmer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyncsleepiq/fuzion/foot_warmer.py b/asyncsleepiq/fuzion/foot_warmer.py index 1cb2600..2e6a461 100644 --- a/asyncsleepiq/fuzion/foot_warmer.py +++ b/asyncsleepiq/fuzion/foot_warmer.py @@ -15,7 +15,7 @@ async def set_foot_warming(self, temperature: FootWarmingTemps, time: int) -> No if time <= 0 or time > 360: raise ValueError("Invalid Time, must be between 0 and 360") - args = [SIDES_FULL[self.side].lower(), temperature.name.lower(), time] + args = [SIDES_FULL[self.side].lower(), temperature.name.lower(), str(time)] await self._api.bamkey(self.bed_id, "SetFootwarmingSettings", args) await self.update({})