diff options
author | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2022-07-15 12:24:07 +0300 |
---|---|---|
committer | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2022-07-15 12:24:07 +0300 |
commit | 1b2f7314e6fae14ff301ece7763269c17d113ed3 (patch) | |
tree | 97c9ee43b5d7b3d2cad213f7c4086357e2697b8d | |
parent | 2f03dbc403370863b8a851c38262dd06f1bbbd53 (diff) |
Model specific methods
-rw-r--r-- | custom_components/skykettle/light.py | 1 | ||||
-rw-r--r-- | custom_components/skykettle/skykettle.py | 192 | ||||
-rw-r--r-- | custom_components/skykettle/water_heater.py | 17 |
3 files changed, 140 insertions, 70 deletions
diff --git a/custom_components/skykettle/light.py b/custom_components/skykettle/light.py index b42e3b6..368dfd5 100644 --- a/custom_components/skykettle/light.py +++ b/custom_components/skykettle/light.py @@ -112,6 +112,7 @@ class KettleLight(LightEntity): @property def available(self): + if self.kettle.model_code != 1: return False # Not sure if self.light_type == LIGHT_GAME: return self.kettle.available else: diff --git a/custom_components/skykettle/skykettle.py b/custom_components/skykettle/skykettle.py index 2f48a99..595a720 100644 --- a/custom_components/skykettle/skykettle.py +++ b/custom_components/skykettle/skykettle.py @@ -75,6 +75,7 @@ class SkyKettle(): "temp_high", "unknown2", "r_high", "g_high", "b_high"]) Status = namedtuple("Status", ["mode", "target_temp", "sound_enabled", "current_temp", "color_interval", "is_on", "boil_time"]) + StatusSimple = namedtuple("StatusSimple", ["mode", "target_temp", "is_on", "current_temp"]) Stats = namedtuple("Stats", ["ontime", "energy_wh", "heater_on_count", "user_on_count"]) FreshWaterInfo = namedtuple("FreshWaterInfo", ["is_on", "unknown1", "water_freshness_hours"]) @@ -86,8 +87,7 @@ class SkyKettle(): self.model_code = SkyKettle.SUPPORTED_DEVICES[model] _LOGGER.debug(f"Kettle model code: {self.model_code}") else: - self.model_code = 1 - _LOGGER.warn(f"Unknown kettle model") + raise SkyKettleError("Unknown kettle model") @abstractmethod async def command(self, command, params=[]): @@ -117,111 +117,165 @@ class SkyKettle(): _LOGGER.debug(f"Turned off") async def set_main_mode(self, mode, target_temp = 0, boil_time = 0): - data = pack("BxBxxxxxxxxxxBxx", int(mode), int(target_temp), int(0x80 + boil_time)) + if self.model_code in [0]: + data = pack("BxBx", int(mode), int(target_temp)) + elif self.model_code in [1, 2]: + data = pack("BxBxxxxxxxxxxBxx", int(mode), int(target_temp), int(0x80 + boil_time)) r = await self.command(SkyKettle.COMMAND_SET_MAIN_MODE, data) if r[0] != 1: raise SkyKettleError("can't set mode") _LOGGER.debug(f"Mode set: mode={mode} ({SkyKettle.MODE_NAMES[mode]}), target_temp={target_temp}, boil_time={boil_time}") async def get_status(self): r = await self.command(SkyKettle.COMMAND_GET_STATUS) - status = SkyKettle.Status(*unpack("<BxBx?BHBxxxxBxx", r)) - status = status._replace( - is_on = status.is_on == 2, - boil_time = status.boil_time - 0x80 - ) + if self.model_code in [0]: + # Old models + mode, target_temp, is_on, current_temp = unpack("<BxBxxxxxBxBxxxxx", r) + status = Status(mode=mode, + target_temp=target_temp, + is_on=is_on==2, + current_temp=current_temp, + sound_enabled=None, + boil_time=None, + color_interval=None) + elif self.model_code in [1, 2]: + # New models + status = SkyKettle.Status(*unpack("<BxBx?BHBxxxxBxx", r)) + status = status._replace( + is_on = status.is_on == 2, + boil_time = status.boil_time - 0x80 + ) _LOGGER.debug(f"Status: mode={status.mode} ({SkyKettle.MODE_NAMES[status.mode]}), is_on={status.is_on}, "+ f"target_temp={status.target_temp}, current_temp={status.current_temp}, sound_enabled={status.sound_enabled}, "+ f"color_interval={status.color_interval}, boil_time={status.boil_time}") return status async def sync_time(self): - t = time.localtime() - offset = calendar.timegm(t) - calendar.timegm(time.gmtime(time.mktime(t))) - now = int(time.time()) - data = pack("<ii", now, offset) - r = await self.command(SkyKettle.COMMAND_SYNC_TIME, data) - # r = await self.command(SkyKettle.COMMAND_SYNC_TIME, - # list(now.to_bytes(4, byteorder='little')) + - # list(offset.to_bytes(4, byteorder='little', signed=True))) - if r[0] != 0: raise SkyKettleError("can't sync time") - _LOGGER.debug(f"Writed time={now} ({datetime.fromtimestamp(now).strftime('%Y-%m-%d %H:%M:%S')}), offset={offset} (GMT{offset/60/60:+.2f})") + if self.model_code in [1, 2]: + t = time.localtime() + offset = calendar.timegm(t) - calendar.timegm(time.gmtime(time.mktime(t))) + now = int(time.time()) + data = pack("<ii", now, offset) + r = await self.command(SkyKettle.COMMAND_SYNC_TIME, data) + if r[0] != 0: raise SkyKettleError("can't sync time") + _LOGGER.debug(f"Writed time={now} ({datetime.fromtimestamp(now).strftime('%Y-%m-%d %H:%M:%S')}), offset={offset} (GMT{offset/60/60:+.2f})") + else: + _LOGGER.debug(f"sync_time is not supported by this model") async def get_time(self): - r = await self.command(SkyKettle.COMMAND_GET_TIME) - t, offset = unpack("<ii", r) - _LOGGER.debug(f"time={t} ({datetime.fromtimestamp(t).strftime('%Y-%m-%d %H:%M:%S')}), offset={offset} (GMT{offset/60/60:+.2f})") - return t, offset + if self.model_code in [1, 2]: + r = await self.command(SkyKettle.COMMAND_GET_TIME) + t, offset = unpack("<ii", r) + _LOGGER.debug(f"time={t} ({datetime.fromtimestamp(t).strftime('%Y-%m-%d %H:%M:%S')}), offset={offset} (GMT{offset/60/60:+.2f})") + return t, offset + else: + _LOGGER.debug(f"get_time is not supported by this model") async def set_lamp_auto_off_hours(self, hours): - data = pack("<H", int(hours)) - r = await self.command(SkyKettle.COMMAND_SET_AUTO_OFF_HOURS, data) - if r[0] != 0: raise SkyKettleError("can't set lamp auto off hours") - _LOGGER.debug(f"Updated lamp auto off hours={hours}") + if self.model_code in [1]: # Not sure + data = pack("<H", int(hours)) + r = await self.command(SkyKettle.COMMAND_SET_AUTO_OFF_HOURS, data) + if r[0] != 0: raise SkyKettleError("can't set lamp auto off hours") + _LOGGER.debug(f"Updated lamp auto off hours={hours}") + else: + _LOGGER.debug(f"set_lamp_auto_off_hours is not supported by this model") async def get_lamp_auto_off_hours(self): - r = await self.command(SkyKettle.COMMAND_GET_AUTO_OFF_HOURS) - hours, = unpack("<H", r) - _LOGGER.debug(f"Lamp auto off hours={hours}") - return hours + if self.model_code in [1]: # Not sure + r = await self.command(SkyKettle.COMMAND_GET_AUTO_OFF_HOURS) + hours, = unpack("<H", r) + _LOGGER.debug(f"Lamp auto off hours={hours}") + return hours + else: + _LOGGER.debug(f"get_lamp_auto_off_hours is not supported by this model") async def get_colors(self, light_type): - r = await self.command(SkyKettle.COMMAND_GET_COLORS, [light_type]) - colors_set = SkyKettle.ColorsSet(*unpack("BBBBBBBBBBBBBBBB", r)) - _LOGGER.debug(f"{colors_set}") - return colors_set + if self.model_code in [1]: # Not sure + r = await self.command(SkyKettle.COMMAND_GET_COLORS, [light_type]) + colors_set = SkyKettle.ColorsSet(*unpack("BBBBBBBBBBBBBBBB", r)) + _LOGGER.debug(f"{colors_set}") + return colors_set + else: + _LOGGER.debug(f"get_colors is not supported by this model") async def set_colors(self, colors_set): - data = pack("BBBBBBBBBBBBBBBB", *colors_set) - r = await self.command(SkyKettle.COMMAND_SET_COLORS, data) - if r[0] != 0: raise SkyKettleError("can't set colors") - _LOGGER.debug(f"Updated colors set: {colors_set}") + if self.model_code in [1]: # Not sure + data = pack("BBBBBBBBBBBBBBBB", *colors_set) + r = await self.command(SkyKettle.COMMAND_SET_COLORS, data) + if r[0] != 0: raise SkyKettleError("can't set colors") + _LOGGER.debug(f"Updated colors set: {colors_set}") + else: + _LOGGER.debug(f"set_colors is not supported by this model") async def commit(self): - r = await self.command(SkyKettle.COMMAND_COMMIT_SETTINGS) - if r[0] != 1: raise SkyKettleError("can't commit settings") - _LOGGER.debug(f"Settings commited") + if self.model_code in [1]: # Not sure + r = await self.command(SkyKettle.COMMAND_COMMIT_SETTINGS) + if r[0] != 1: raise SkyKettleError("can't commit settings") + _LOGGER.debug(f"Settings commited") + else: + _LOGGER.debug(f"commit is not supported by this model") async def set_lamp_color_interval(self, secs): - data = pack("<H", int(secs)) - r = await self.command(SkyKettle.COMMAND_SET_COLOR_INTERVAL, data) - if r[0] != 0: raise SkyKettleError("can't set lamp color change interval") - _LOGGER.debug(f"Updated lamp color interval secs={secs}") + if self.model_code in [1]: # Not sure + data = pack("<H", int(secs)) + r = await self.command(SkyKettle.COMMAND_SET_COLOR_INTERVAL, data) + if r[0] != 0: raise SkyKettleError("can't set lamp color change interval") + _LOGGER.debug(f"Updated lamp color interval secs={secs}") + else: + _LOGGER.debug(f"set_lamp_color_interval is not supported by this model") async def impulse_color(self, r, g, b, brightness=0xff, interval=0): - data = pack("<BBBBH", r, g, b, brightness, interval) - r = await self.command(SkyKettle.COMMAND_IMPULSE_COLOR, data) - if r[0] != 1: raise SkyKettleError("can't fire color impulse") - _LOGGER.debug(f"Impulse! r={r}, g={g}, b={b}, brightness={brightness}, interval={interval}") + if self.model_code in [1]: # Not sure + data = pack("<BBBBH", r, g, b, brightness, interval) + r = await self.command(SkyKettle.COMMAND_IMPULSE_COLOR, data) + if r[0] != 1: raise SkyKettleError("can't fire color impulse") + _LOGGER.debug(f"Impulse! r={r}, g={g}, b={b}, brightness={brightness}, interval={interval}") + else: + _LOGGER.debug(f"impulse_color is not supported by this model") async def set_light_switch(self, light_type, on): - data = pack("BB?", light_type, light_type, on) - r = await self.command(SkyKettle.COMMAND_SET_LIGHT_SWITCH, data) - if r[0] != 0: raise SkyKettleError("can't switch light") - _LOGGER.debug(f"Light with type={light_type} ({SkyKettle.LIGHT_NAMES[light_type]}) switched {'on' if on else 'off'}") + if self.model_code in [1, 2]: + data = pack("BB?", light_type, light_type, on) + r = await self.command(SkyKettle.COMMAND_SET_LIGHT_SWITCH, data) + if r[0] != 0: raise SkyKettleError("can't switch light") + _LOGGER.debug(f"Light with type={light_type} ({SkyKettle.LIGHT_NAMES[light_type]}) switched {'on' if on else 'off'}") + else: + _LOGGER.debug(f"set_light_switch is not supported by this model") async def get_light_switch(self, light_type): - data = pack("B", light_type) - r = await self.command(SkyKettle.COMMAND_GET_LIGHT_SWITCH, data) - is_on, = unpack("xx?xx", r) - _LOGGER.debug(f"Light with type={light_type} ({SkyKettle.LIGHT_NAMES[light_type]}) is {'on' if is_on else 'off'}") - return is_on + if self.model_code in [1, 2]: + data = pack("B", light_type) + r = await self.command(SkyKettle.COMMAND_GET_LIGHT_SWITCH, data) + is_on, = unpack("xx?xx", r) + _LOGGER.debug(f"Light with type={light_type} ({SkyKettle.LIGHT_NAMES[light_type]}) is {'on' if is_on else 'off'}") + return is_on + else: + _LOGGER.debug(f"get_light_switch is not supported by this model") async def set_sound(self, on): - data = pack("?", on) - r = await self.command(SkyKettle.COMMAND_SET_SOUND, data) - if r[0] != 1: raise SkyKettleError("can't switch sound") - _LOGGER.debug(f"Sound switched {'on' if on else 'off'}") + if self.model_code in [1, 2]: # Not sure + data = pack("?", on) + r = await self.command(SkyKettle.COMMAND_SET_SOUND, data) + if r[0] != 1: raise SkyKettleError("can't switch sound") + _LOGGER.debug(f"Sound switched {'on' if on else 'off'}") + else: + _LOGGER.debug(f"set_sound is not supported by this model") async def set_fresh_water(self, on, unknown1=48): - data = pack("<x?Hxxxxxxxxxxxx", on, int(unknown1)) - r = await self.command(SkyKettle.COMMAND_SET_FRESH_WATER, data) - _LOGGER.debug(f"Fresh water notification switched {'on' if on else 'off'}") + if self.model_code in [1]: # Not sure + data = pack("<x?Hxxxxxxxxxxxx", on, int(unknown1)) + r = await self.command(SkyKettle.COMMAND_SET_FRESH_WATER, data) + _LOGGER.debug(f"Fresh water notification switched {'on' if on else 'off'}") + else: + _LOGGER.debug(f"set_fresh_water is not supported by this model") async def get_fresh_water(self): - r = await self.command(SkyKettle.COMMAND_GET_FRESH_WATER, [0x00]) - info = SkyKettle.FreshWaterInfo(*unpack("<x?HHxxxxxxxxxx", r)) - _LOGGER.debug(f"Fresh water notification is {'on' if info.is_on else 'off'}, unknown1={info.unknown1}, water_freshness_hours={info.water_freshness_hours}") - return info + if self.model_code in [1]: # Not sure + r = await self.command(SkyKettle.COMMAND_GET_FRESH_WATER, [0x00]) + info = SkyKettle.FreshWaterInfo(*unpack("<x?HHxxxxxxxxxx", r)) + _LOGGER.debug(f"Fresh water notification is {'on' if info.is_on else 'off'}, unknown1={info.unknown1}, water_freshness_hours={info.water_freshness_hours}") + return info + else: + _LOGGER.debug(f"get_fresh_water is not supported by this model") async def get_stats(self): r1 = await self.command(SkyKettle.COMMAND_GET_STATS1, [0x00]) diff --git a/custom_components/skykettle/water_heater.py b/custom_components/skykettle/water_heater.py index 966db86..84c36d6 100644 --- a/custom_components/skykettle/water_heater.py +++ b/custom_components/skykettle/water_heater.py @@ -93,7 +93,22 @@ class SkyWaterHeater(WaterHeaterEntity): @property def operation_list(self): - return [STATE_OFF] + list(SkyKettle.MODE_NAMES.values()) + if self.kettle.model_code == 1: # Not sure + return [ + STATE_OFF, + SkyKettle.MODE_NAMES[SkyKettle.MODE_HEAT], + SkyKettle.MODE_NAMES[SkyKettle.MODE_BOIL], + SkyKettle.MODE_NAMES[SkyKettle.MODE_BOIL_HEAT], + SkyKettle.MODE_NAMES[SkyKettle.MODE_LAMP], + SkyKettle.MODE_NAMES[SkyKettle.MODE_GAME] + ] + else: + return [ + STATE_OFF, + SkyKettle.MODE_NAMES[SkyKettle.MODE_HEAT], + SkyKettle.MODE_NAMES[SkyKettle.MODE_BOIL], + SkyKettle.MODE_NAMES[SkyKettle.MODE_BOIL_HEAT] + ] @property def extra_state_attributes(self): |