make SmartBulb use asyncio

This commit is contained in:
Bas Nijholt 2019-11-11 17:32:44 +01:00
parent 904bbe5c1a
commit 7c69d3c03a

View File

@ -74,69 +74,68 @@ class SmartBulb(SmartDevice):
self.emeter_type = "smartlife.iot.common.emeter" self.emeter_type = "smartlife.iot.common.emeter"
self._device_type = DeviceType.Bulb self._device_type = DeviceType.Bulb
@property async def is_color(self) -> bool:
def is_color(self) -> bool:
"""Whether the bulb supports color changes. """Whether the bulb supports color changes.
:return: True if the bulb supports color changes, False otherwise :return: True if the bulb supports color changes, False otherwise
:rtype: bool :rtype: bool
""" """
return bool(self.sys_info["is_color"]) sys_info = await self.get_sys_info()
return bool(sys_info["is_color"])
@property async def is_dimmable(self) -> bool:
def is_dimmable(self) -> bool:
"""Whether the bulb supports brightness changes. """Whether the bulb supports brightness changes.
:return: True if the bulb supports brightness changes, False otherwise :return: True if the bulb supports brightness changes, False otherwise
:rtype: bool :rtype: bool
""" """
return bool(self.sys_info["is_dimmable"]) sys_info = await self.get_sys_info()
return bool(sys_info["is_dimmable"])
@property async def is_variable_color_temp(self) -> bool:
def is_variable_color_temp(self) -> bool:
"""Whether the bulb supports color temperature changes. """Whether the bulb supports color temperature changes.
:return: True if the bulb supports color temperature changes, False :return: True if the bulb supports color temperature changes, False
otherwise otherwise
:rtype: bool :rtype: bool
""" """
return bool(self.sys_info["is_variable_color_temp"]) sys_info = await self.get_sys_info()
return bool(sys_info["is_variable_color_temp"])
@property async def get_valid_temperature_range(self) -> Tuple[int, int]:
def valid_temperature_range(self) -> Tuple[int, int]:
"""Return the device-specific white temperature range (in Kelvin). """Return the device-specific white temperature range (in Kelvin).
:return: White temperature range in Kelvin (minimun, maximum) :return: White temperature range in Kelvin (minimun, maximum)
:rtype: tuple :rtype: tuple
""" """
if not self.is_variable_color_temp: if not await self.is_variable_color_temp():
return (0, 0) return (0, 0)
for model, temp_range in TPLINK_KELVIN.items(): for model, temp_range in TPLINK_KELVIN.items():
if re.match(model, self.sys_info["model"]): sys_info = await self.get_sys_info()
if re.match(model, sys_info["model"]):
return temp_range return temp_range
return (0, 0) return (0, 0)
def get_light_state(self) -> Dict: async def get_light_state(self) -> Dict:
"""Query the light state.""" """Query the light state."""
return self._query_helper(self.LIGHT_SERVICE, "get_light_state") return await self._query_helper(self.LIGHT_SERVICE, "get_light_state")
def set_light_state(self, state: Dict) -> Dict: async def set_light_state(self, state: Dict) -> Dict:
"""Set the light state.""" """Set the light state."""
return self._query_helper(self.LIGHT_SERVICE, "transition_light_state", state) return await self._query_helper(self.LIGHT_SERVICE, "transition_light_state", state)
@property async def get_hsv(self) -> Tuple[int, int, int]:
def hsv(self) -> Tuple[int, int, int]:
"""Return the current HSV state of the bulb. """Return the current HSV state of the bulb.
:return: hue, saturation and value (degrees, %, %) :return: hue, saturation and value (degrees, %, %)
:rtype: tuple :rtype: tuple
""" """
if not self.is_color: if not await self.is_color():
raise SmartDeviceException("Bulb does not support color.") raise SmartDeviceException("Bulb does not support color.")
light_state = self.get_light_state() light_state = await self.get_light_state()
if not self.is_on: if not await self.is_on():
hue = light_state["dft_on_state"]["hue"] hue = light_state["dft_on_state"]["hue"]
saturation = light_state["dft_on_state"]["saturation"] saturation = light_state["dft_on_state"]["saturation"]
value = light_state["dft_on_state"]["brightness"] value = light_state["dft_on_state"]["brightness"]
@ -147,23 +146,18 @@ class SmartBulb(SmartDevice):
return hue, saturation, value return hue, saturation, value
@hsv.setter # type: ignore
@deprecated(details="Use set_hsv()")
def hsv(self, state: Tuple[int, int, int]):
return self.set_hsv(state[0], state[1], state[2])
def _raise_for_invalid_brightness(self, value): def _raise_for_invalid_brightness(self, value):
if not isinstance(value, int) or not (0 <= value <= 100): if not isinstance(value, int) or not (0 <= value <= 100):
raise ValueError( raise ValueError(
"Invalid brightness value: {} " "(valid range: 0-100%)".format(value) "Invalid brightness value: {} " "(valid range: 0-100%)".format(value)
) )
def set_hsv(self, hue: int, saturation: int, value: int): async def set_hsv(self, hue: int, saturation: int, value: int):
"""Set new HSV. """Set new HSV.
:param tuple state: hue, saturation and value (degrees, %, %) :param tuple state: hue, saturation and value (degrees, %, %)
""" """
if not self.is_color: if not await self.is_color():
raise SmartDeviceException("Bulb does not support color.") raise SmartDeviceException("Bulb does not support color.")
if not isinstance(hue, int) or not (0 <= hue <= 360): if not isinstance(hue, int) or not (0 <= hue <= 360):
@ -185,150 +179,102 @@ class SmartBulb(SmartDevice):
"brightness": value, "brightness": value,
"color_temp": 0, "color_temp": 0,
} }
self.set_light_state(light_state) await self.set_light_state(light_state)
@property async def get_color_temp(self) -> int:
def color_temp(self) -> int:
"""Return color temperature of the device. """Return color temperature of the device.
:return: Color temperature in Kelvin :return: Color temperature in Kelvin
:rtype: int :rtype: int
""" """
if not self.is_variable_color_temp: if not await self.is_variable_color_temp():
raise SmartDeviceException("Bulb does not support colortemp.") raise SmartDeviceException("Bulb does not support colortemp.")
light_state = self.get_light_state() light_state = await self.get_light_state()
if not self.is_on: if not await self.is_on():
return int(light_state["dft_on_state"]["color_temp"]) return int(light_state["dft_on_state"]["color_temp"])
else: else:
return int(light_state["color_temp"]) return int(light_state["color_temp"])
@color_temp.setter # type: ignore async def set_color_temp(self, temp: int) -> None:
@deprecated(details="use set_color_temp")
def color_temp(self, temp: int) -> None:
self.set_color_temp(temp)
def set_color_temp(self, temp: int) -> None:
"""Set the color temperature of the device. """Set the color temperature of the device.
:param int temp: The new color temperature, in Kelvin :param int temp: The new color temperature, in Kelvin
""" """
if not self.is_variable_color_temp: if not await self.is_variable_color_temp():
raise SmartDeviceException("Bulb does not support colortemp.") raise SmartDeviceException("Bulb does not support colortemp.")
valid_temperature_range = await self.get_valid_temperature_range()
if ( if (
temp < self.valid_temperature_range[0] temp < valid_temperature_range[0]
or temp > self.valid_temperature_range[1] or temp > valid_temperature_range[1]
): ):
raise ValueError( raise ValueError(
"Temperature should be between {} " "Temperature should be between {} "
"and {}".format(*self.valid_temperature_range) "and {}".format(*valid_temperature_range)
) )
light_state = {"color_temp": temp} light_state = {"color_temp": temp}
self.set_light_state(light_state) await self.set_light_state(light_state)
@property async def get_brightness(self) -> int:
def brightness(self) -> int:
"""Current brightness of the device. """Current brightness of the device.
:return: brightness in percent :return: brightness in percent
:rtype: int :rtype: int
""" """
if not self.is_dimmable: # pragma: no cover if not await self.is_dimmable(): # pragma: no cover
raise SmartDeviceException("Bulb is not dimmable.") raise SmartDeviceException("Bulb is not dimmable.")
light_state = self.get_light_state() light_state = await self.get_light_state()
if not self.is_on: if not await self.is_on():
return int(light_state["dft_on_state"]["brightness"]) return int(light_state["dft_on_state"]["brightness"])
else: else:
return int(light_state["brightness"]) return int(light_state["brightness"])
@brightness.setter # type: ignore async def set_brightness(self, brightness: int) -> None:
@deprecated(details="use set_brightness")
def brightness(self, brightness: int) -> None:
self.set_brightness(brightness)
def set_brightness(self, brightness: int) -> None:
"""Set the current brightness of the device. """Set the current brightness of the device.
:param int brightness: brightness in percent :param int brightness: brightness in percent
""" """
if not self.is_dimmable: # pragma: no cover if not await self.is_dimmable(): # pragma: no cover
raise SmartDeviceException("Bulb is not dimmable.") raise SmartDeviceException("Bulb is not dimmable.")
self._raise_for_invalid_brightness(brightness) self._raise_for_invalid_brightness(brightness)
light_state = {"brightness": brightness} light_state = {"brightness": brightness}
self.set_light_state(light_state) await self.set_light_state(light_state)
@property # type: ignore async def get_state_information(self) -> Dict[str, Any]:
@deprecated(details="use is_on() and is_off()")
def state(self) -> str:
"""Retrieve the bulb state.
:returns: one of
STATE_ON
STATE_OFF
:rtype: str
"""
if self.is_on:
return self.STATE_ON
return self.STATE_OFF
@state.setter # type: ignore
@deprecated(details="use turn_on() and turn_off()")
def state(self, bulb_state: str) -> None:
"""Set the new bulb state.
:param bulb_state: one of
STATE_ON
STATE_OFF
"""
if bulb_state == self.STATE_ON:
new_state = 1
elif bulb_state == self.STATE_OFF:
new_state = 0
else:
raise ValueError
light_state = {"on_off": new_state}
self.set_light_state(light_state)
@property
def state_information(self) -> Dict[str, Any]:
"""Return bulb-specific state information. """Return bulb-specific state information.
:return: Bulb information dict, keys in user-presentable form. :return: Bulb information dict, keys in user-presentable form.
:rtype: dict :rtype: dict
""" """
info = { info = {
"Brightness": self.brightness, "Brightness": await self.get_brightness(),
"Is dimmable": self.is_dimmable, "Is dimmable": await self.is_dimmable(),
} # type: Dict[str, Any] } # type: Dict[str, Any]
if self.is_variable_color_temp: if await self.is_variable_color_temp():
info["Color temperature"] = self.color_temp info["Color temperature"] = await self.get_color_temp()
info["Valid temperature range"] = self.valid_temperature_range info["Valid temperature range"] = await self.get_valid_temperature_range()
if self.is_color: if await self.is_color():
info["HSV"] = self.hsv info["HSV"] = await self.get_hsv()
return info return info
@property async def is_on(self) -> bool:
def is_on(self) -> bool:
"""Return whether the device is on.""" """Return whether the device is on."""
light_state = self.get_light_state() light_state = await self.get_light_state()
return bool(light_state["on_off"]) return bool(light_state["on_off"])
def turn_off(self) -> None: async def turn_off(self) -> None:
"""Turn the bulb off.""" """Turn the bulb off."""
self.set_light_state({"on_off": 0}) await self.set_light_state({"on_off": 0})
def turn_on(self) -> None: async def turn_on(self) -> None:
"""Turn the bulb on.""" """Turn the bulb on."""
self.set_light_state({"on_off": 1}) await self.set_light_state({"on_off": 1})
@property async def get_has_emeter(self) -> bool:
def has_emeter(self) -> bool:
return True return True