1 """Support for Xiaomi Philips Lights."""
3 from __future__
import annotations
7 from datetime
import timedelta
8 from functools
import partial
11 from typing
import Any
21 from miio.gateway.gateway
import (
27 import voluptuous
as vol
60 SERVICE_EYECARE_MODE_OFF,
61 SERVICE_EYECARE_MODE_ON,
62 SERVICE_NIGHT_LIGHT_MODE_OFF,
63 SERVICE_NIGHT_LIGHT_MODE_ON,
66 SERVICE_SET_DELAYED_TURN_OFF,
69 from .entity
import XiaomiGatewayDevice, XiaomiMiioEntity
70 from .typing
import ServiceMethodDetails
72 _LOGGER = logging.getLogger(__name__)
74 DEFAULT_NAME =
"Xiaomi Philips Light"
75 DATA_KEY =
"light.xiaomi_miio"
81 DELAYED_TURN_OFF_MAX_DEVIATION_SECONDS = 4
82 DELAYED_TURN_OFF_MAX_DEVIATION_MINUTES = 1
86 ATTR_DELAYED_TURN_OFF =
"delayed_turn_off"
87 ATTR_TIME_PERIOD =
"time_period"
88 ATTR_NIGHT_LIGHT_MODE =
"night_light_mode"
89 ATTR_AUTOMATIC_COLOR_TEMPERATURE =
"automatic_color_temperature"
90 ATTR_REMINDER =
"reminder"
91 ATTR_EYECARE_MODE =
"eyecare_mode"
94 ATTR_SLEEP_ASSISTANT =
"sleep_assistant"
95 ATTR_SLEEP_OFF_TIME =
"sleep_off_time"
96 ATTR_TOTAL_ASSISTANT_SLEEP_TIME =
"total_assistant_sleep_time"
97 ATTR_BAND_SLEEP =
"band_sleep"
100 XIAOMI_MIIO_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids})
102 SERVICE_SCHEMA_SET_SCENE = XIAOMI_MIIO_SERVICE_SCHEMA.extend(
103 {vol.Required(ATTR_SCENE): vol.All(vol.Coerce(int), vol.Clamp(min=1, max=6))}
106 SERVICE_SCHEMA_SET_DELAYED_TURN_OFF = XIAOMI_MIIO_SERVICE_SCHEMA.extend(
107 {vol.Required(ATTR_TIME_PERIOD): cv.positive_time_period}
110 SERVICE_TO_METHOD = {
112 method=
"async_set_delayed_turn_off",
113 schema=SERVICE_SCHEMA_SET_DELAYED_TURN_OFF,
116 method=
"async_set_scene",
117 schema=SERVICE_SCHEMA_SET_SCENE,
122 method=
"async_night_light_mode_on"
125 method=
"async_night_light_mode_off"
134 config_entry: ConfigEntry,
135 async_add_entities: AddEntitiesCallback,
137 """Set up the Xiaomi light from a config entry."""
138 entities: list[LightEntity] = []
142 if config_entry.data[CONF_FLOW_TYPE] == CONF_GATEWAY:
143 gateway = hass.data[DOMAIN][config_entry.entry_id][CONF_GATEWAY]
145 if gateway.model
not in [
154 sub_devices = gateway.devices
155 for sub_device
in sub_devices.values():
156 if sub_device.device_type ==
"LightBulb":
157 coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR][
164 if config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE:
165 if DATA_KEY
not in hass.data:
166 hass.data[DATA_KEY] = {}
168 host = config_entry.data[CONF_HOST]
169 token = config_entry.data[CONF_TOKEN]
170 name = config_entry.title
171 model = config_entry.data[CONF_MODEL]
172 unique_id = config_entry.unique_id
174 _LOGGER.debug(
"Initializing with host %s (token %s...)", host, token[:5])
176 if model
in MODELS_LIGHT_EYECARE:
177 light = PhilipsEyecare(host, token)
179 entities.append(entity)
180 hass.data[DATA_KEY][host] = entity
184 name, light, config_entry, unique_id
189 elif model
in MODELS_LIGHT_CEILING:
190 light = Ceil(host, token)
192 entities.append(entity)
193 hass.data[DATA_KEY][host] = entity
194 elif model
in MODELS_LIGHT_MOON:
195 light = PhilipsMoonlight(host, token)
197 entities.append(entity)
198 hass.data[DATA_KEY][host] = entity
199 elif model
in MODELS_LIGHT_BULB:
200 light = PhilipsBulb(host, token)
202 entities.append(entity)
203 hass.data[DATA_KEY][host] = entity
204 elif model
in MODELS_LIGHT_MONO:
205 light = PhilipsBulb(host, token)
207 entities.append(entity)
208 hass.data[DATA_KEY][host] = entity
212 "Unsupported device found! Please create an issue at "
213 "https://github.com/syssi/philipslight/issues "
214 "and provide the following data: %s"
220 async
def async_service_handler(service: ServiceCall) ->
None:
221 """Map services to methods on Xiaomi Philips Lights."""
222 method = SERVICE_TO_METHOD[service.service]
225 for key, value
in service.data.items()
226 if key != ATTR_ENTITY_ID
228 if entity_ids := service.data.get(ATTR_ENTITY_ID):
231 for dev
in hass.data[DATA_KEY].values()
232 if dev.entity_id
in entity_ids
235 target_devices = hass.data[DATA_KEY].values()
238 for target_device
in target_devices:
239 if not hasattr(target_device, method.method):
241 await getattr(target_device, method.method)(**params)
243 asyncio.create_task(target_device.async_update_ha_state(
True))
247 await asyncio.wait(update_tasks)
249 for xiaomi_miio_service, method
in SERVICE_TO_METHOD.items():
250 schema = method.schema
or XIAOMI_MIIO_SERVICE_SCHEMA
251 hass.services.async_register(
252 DOMAIN, xiaomi_miio_service, async_service_handler, schema=schema
259 """Representation of a Abstract Xiaomi Philips Light."""
261 _attr_color_mode = ColorMode.BRIGHTNESS
262 _attr_supported_color_modes = {ColorMode.BRIGHTNESS}
264 def __init__(self, name, device, entry, unique_id):
265 """Initialize the light device."""
266 super().
__init__(name, device, entry, unique_id)
275 """Return true when state is known."""
280 """Return the state attributes of the device."""
285 """Return true if light is on."""
290 """Return the brightness of this light between 0..255."""
294 """Call a light command handling error messages."""
296 result = await self.
hasshass.async_add_executor_job(
297 partial(func, *args, **kwargs)
299 except DeviceException
as exc:
301 _LOGGER.error(mask_error, exc)
306 _LOGGER.debug(
"Response received from light: %s", result)
307 return result == SUCCESS
310 """Turn the light on."""
311 if ATTR_BRIGHTNESS
in kwargs:
312 brightness = kwargs[ATTR_BRIGHTNESS]
313 percent_brightness = ceil(100 * brightness / 255.0)
315 _LOGGER.debug(
"Setting brightness: %s %s%%", brightness, percent_brightness)
318 "Setting brightness failed: %s",
319 self.
_device_device.set_brightness,
326 await self.
_try_command_try_command(
"Turning the light on failed.", self.
_device_device.on)
329 """Turn the light off."""
330 await self.
_try_command_try_command(
"Turning the light off failed.", self.
_device_device.off)
333 """Fetch state from the device."""
335 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
336 except DeviceException
as ex:
339 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
343 _LOGGER.debug(
"Got new state: %s", state)
345 self.
_state_state = state.is_on
346 self.
_brightness_brightness = ceil((255 / 100.0) * state.brightness)
350 """Representation of a Generic Xiaomi Philips Light."""
352 def __init__(self, name, device, entry, unique_id):
353 """Initialize the light device."""
354 super().
__init__(name, device, entry, unique_id)
359 """Fetch state from the device."""
361 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
362 except DeviceException
as ex:
365 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
369 _LOGGER.debug(
"Got new state: %s", state)
375 state.delay_off_countdown,
381 {ATTR_SCENE: state.scene, ATTR_DELAYED_TURN_OFF: delayed_turn_off}
385 """Set the fixed scene."""
387 "Setting a fixed scene failed.", self.
_device_device.set_scene, scene
391 """Set delayed turn off."""
393 "Setting the turn off delay failed.",
395 time_period.total_seconds(),
400 countdown: int, current: datetime.datetime, previous: datetime.datetime
402 """Update the turn off timestamp only if necessary."""
403 if countdown
is not None and countdown > 0:
404 new = current.replace(microsecond=0) +
timedelta(seconds=countdown)
409 lower =
timedelta(seconds=-DELAYED_TURN_OFF_MAX_DEVIATION_SECONDS)
410 upper =
timedelta(seconds=DELAYED_TURN_OFF_MAX_DEVIATION_SECONDS)
411 diff = previous - new
412 if lower < diff < upper:
421 """Representation of a Xiaomi Philips Bulb."""
423 _attr_color_mode = ColorMode.COLOR_TEMP
424 _attr_supported_color_modes = {ColorMode.COLOR_TEMP}
426 def __init__(self, name, device, entry, unique_id):
427 """Initialize the light device."""
428 super().
__init__(name, device, entry, unique_id)
434 """Return the color temperature."""
439 """Return the coldest color_temp that this light supports."""
444 """Return the warmest color_temp that this light supports."""
448 """Turn the light on."""
449 if ATTR_COLOR_TEMP
in kwargs:
450 color_temp = kwargs[ATTR_COLOR_TEMP]
451 percent_color_temp = self.
translatetranslate(
455 if ATTR_BRIGHTNESS
in kwargs:
456 brightness = kwargs[ATTR_BRIGHTNESS]
457 percent_brightness = ceil(100 * brightness / 255.0)
459 if ATTR_BRIGHTNESS
in kwargs
and ATTR_COLOR_TEMP
in kwargs:
461 "Setting brightness and color temperature: %s %s%%, %s mireds, %s%% cct",
469 "Setting brightness and color temperature failed: %s bri, %s cct",
470 self.
_device_device.set_brightness_and_color_temperature,
479 elif ATTR_COLOR_TEMP
in kwargs:
481 "Setting color temperature: %s mireds, %s%% cct",
487 "Setting color temperature failed: %s cct",
488 self.
_device_device.set_color_temperature,
495 elif ATTR_BRIGHTNESS
in kwargs:
496 brightness = kwargs[ATTR_BRIGHTNESS]
497 percent_brightness = ceil(100 * brightness / 255.0)
499 _LOGGER.debug(
"Setting brightness: %s %s%%", brightness, percent_brightness)
502 "Setting brightness failed: %s",
503 self.
_device_device.set_brightness,
511 await self.
_try_command_try_command(
"Turning the light on failed.", self.
_device_device.on)
514 """Fetch state from the device."""
516 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
517 except DeviceException
as ex:
520 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
524 _LOGGER.debug(
"Got new state: %s", state)
533 state.delay_off_countdown,
539 {ATTR_SCENE: state.scene, ATTR_DELAYED_TURN_OFF: delayed_turn_off}
543 def translate(value, left_min, left_max, right_min, right_max):
544 """Map a value from left span to right span."""
545 left_span = left_max - left_min
546 right_span = right_max - right_min
547 value_scaled =
float(value - left_min) /
float(left_span)
548 return int(right_min + (value_scaled * right_span))
552 """Representation of a Xiaomi Philips Ceiling Lamp."""
554 def __init__(self, name, device, entry, unique_id):
555 """Initialize the light device."""
556 super().
__init__(name, device, entry, unique_id)
559 {ATTR_NIGHT_LIGHT_MODE:
None, ATTR_AUTOMATIC_COLOR_TEMPERATURE:
None}
564 """Return the coldest color_temp that this light supports."""
569 """Return the warmest color_temp that this light supports."""
573 """Fetch state from the device."""
575 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
576 except DeviceException
as ex:
579 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
583 _LOGGER.debug(
"Got new state: %s", state)
592 state.delay_off_countdown,
599 ATTR_SCENE: state.scene,
600 ATTR_DELAYED_TURN_OFF: delayed_turn_off,
601 ATTR_NIGHT_LIGHT_MODE: state.smart_night_light,
602 ATTR_AUTOMATIC_COLOR_TEMPERATURE: state.automatic_color_temperature,
608 """Representation of a Xiaomi Philips Eyecare Lamp 2."""
610 def __init__(self, name, device, entry, unique_id):
611 """Initialize the light device."""
612 super().
__init__(name, device, entry, unique_id)
615 {ATTR_REMINDER:
None, ATTR_NIGHT_LIGHT_MODE:
None, ATTR_EYECARE_MODE:
None}
619 """Fetch state from the device."""
621 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
622 except DeviceException
as ex:
625 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
629 _LOGGER.debug(
"Got new state: %s", state)
635 state.delay_off_countdown,
642 ATTR_SCENE: state.scene,
643 ATTR_DELAYED_TURN_OFF: delayed_turn_off,
644 ATTR_REMINDER: state.reminder,
645 ATTR_NIGHT_LIGHT_MODE: state.smart_night_light,
646 ATTR_EYECARE_MODE: state.eyecare,
651 """Set delayed turn off."""
653 "Setting the turn off delay failed.",
655 round(time_period.total_seconds() / 60),
659 """Enable the eye fatigue notification."""
661 "Turning on the reminder failed.", self.
_device_device.reminder_on
665 """Disable the eye fatigue notification."""
667 "Turning off the reminder failed.", self.
_device_device.reminder_off
671 """Turn the smart night light mode on."""
673 "Turning on the smart night light mode failed.",
674 self.
_device_device.smart_night_light_on,
678 """Turn the smart night light mode off."""
680 "Turning off the smart night light mode failed.",
681 self.
_device_device.smart_night_light_off,
685 """Turn the eyecare mode on."""
687 "Turning on the eyecare mode failed.", self.
_device_device.eyecare_on
691 """Turn the eyecare mode off."""
693 "Turning off the eyecare mode failed.", self.
_device_device.eyecare_off
698 countdown: int, current: datetime.datetime, previous: datetime.datetime
700 """Update the turn off timestamp only if necessary."""
701 if countdown
is not None and countdown > 0:
702 new = current.replace(second=0, microsecond=0) +
timedelta(
709 lower =
timedelta(minutes=-DELAYED_TURN_OFF_MAX_DEVIATION_MINUTES)
710 upper =
timedelta(minutes=DELAYED_TURN_OFF_MAX_DEVIATION_MINUTES)
711 diff = previous - new
712 if lower < diff < upper:
721 """Representation of a Xiaomi Philips Eyecare Lamp Ambient Light."""
723 def __init__(self, name, device, entry, unique_id):
724 """Initialize the light device."""
725 name = f
"{name} Ambient Light"
726 if unique_id
is not None:
727 unique_id = f
"{unique_id}-ambient"
728 super().
__init__(name, device, entry, unique_id)
731 """Turn the light on."""
732 if ATTR_BRIGHTNESS
in kwargs:
733 brightness = kwargs[ATTR_BRIGHTNESS]
734 percent_brightness = ceil(100 * brightness / 255.0)
737 "Setting brightness of the ambient light: %s %s%%",
743 "Setting brightness of the ambient failed: %s",
744 self.
_device_device.set_ambient_brightness,
752 "Turning the ambient light on failed.", self.
_device_device.ambient_on
756 """Turn the light off."""
758 "Turning the ambient light off failed.", self.
_device_device.ambient_off
762 """Fetch state from the device."""
764 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
765 except DeviceException
as ex:
768 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
772 _LOGGER.debug(
"Got new state: %s", state)
779 """Representation of a Xiaomi Philips Zhirui Bedside Lamp."""
781 _attr_supported_color_modes = {ColorMode.COLOR_TEMP, ColorMode.HS}
783 def __init__(self, name, device, entry, unique_id):
784 """Initialize the light device."""
785 super().
__init__(name, device, entry, unique_id)
788 self.
_state_attrs_state_attrs.pop(ATTR_DELAYED_TURN_OFF)
791 ATTR_SLEEP_ASSISTANT:
None,
792 ATTR_SLEEP_OFF_TIME:
None,
793 ATTR_TOTAL_ASSISTANT_SLEEP_TIME:
None,
794 ATTR_BAND_SLEEP:
None,
801 """Return the coldest color_temp that this light supports."""
806 """Return the warmest color_temp that this light supports."""
811 """Return the hs color value."""
816 """Return the color mode of the light."""
819 return ColorMode.COLOR_TEMP
822 """Turn the light on."""
823 if ATTR_COLOR_TEMP
in kwargs:
824 color_temp = kwargs[ATTR_COLOR_TEMP]
825 percent_color_temp = self.
translatetranslate(
829 if ATTR_BRIGHTNESS
in kwargs:
830 brightness = kwargs[ATTR_BRIGHTNESS]
831 percent_brightness = ceil(100 * brightness / 255.0)
833 if ATTR_HS_COLOR
in kwargs:
834 hs_color = kwargs[ATTR_HS_COLOR]
835 rgb = color.color_hs_to_RGB(*hs_color)
837 if ATTR_BRIGHTNESS
in kwargs
and ATTR_HS_COLOR
in kwargs:
839 "Setting brightness and color: %s %s%%, %s",
846 "Setting brightness and color failed: %s bri, %s color",
847 self.
_device_device.set_brightness_and_rgb,
856 elif ATTR_BRIGHTNESS
in kwargs
and ATTR_COLOR_TEMP
in kwargs:
859 "Setting brightness and color temperature: "
860 "%s %s%%, %s mireds, %s%% cct"
869 "Setting brightness and color temperature failed: %s bri, %s cct",
870 self.
_device_device.set_brightness_and_color_temperature,
879 elif ATTR_HS_COLOR
in kwargs:
880 _LOGGER.debug(
"Setting color: %s", rgb)
883 "Setting color failed: %s", self.
_device_device.set_rgb, rgb
889 elif ATTR_COLOR_TEMP
in kwargs:
891 "Setting color temperature: %s mireds, %s%% cct",
897 "Setting color temperature failed: %s cct",
898 self.
_device_device.set_color_temperature,
905 elif ATTR_BRIGHTNESS
in kwargs:
906 brightness = kwargs[ATTR_BRIGHTNESS]
907 percent_brightness = ceil(100 * brightness / 255.0)
909 _LOGGER.debug(
"Setting brightness: %s %s%%", brightness, percent_brightness)
912 "Setting brightness failed: %s",
913 self.
_device_device.set_brightness,
921 await self.
_try_command_try_command(
"Turning the light on failed.", self.
_device_device.on)
924 """Fetch state from the device."""
926 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
927 except DeviceException
as ex:
930 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
934 _LOGGER.debug(
"Got new state: %s", state)
941 self.
_hs_color_hs_color = color.color_RGB_to_hs(*state.rgb)
945 ATTR_SCENE: state.scene,
946 ATTR_SLEEP_ASSISTANT: state.sleep_assistant,
947 ATTR_SLEEP_OFF_TIME: state.sleep_off_time,
948 ATTR_TOTAL_ASSISTANT_SLEEP_TIME: state.total_assistant_sleep_time,
949 ATTR_BAND_SLEEP: state.brand_sleep,
950 ATTR_BAND: state.brand,
955 """Set delayed turn off. Unsupported."""
960 """Representation of a gateway device's light."""
962 _attr_color_mode = ColorMode.HS
963 _attr_supported_color_modes = {ColorMode.HS}
965 def __init__(self, gateway_device, gateway_name, gateway_device_id):
966 """Initialize the XiaomiGatewayLight."""
968 self.
_name_name = f
"{gateway_name} Light"
974 self.
_rgb_rgb = (255, 255, 255)
979 """Return an unique ID."""
984 """Return the device info of the gateway."""
991 """Return the name of this entity, if any."""
992 return self.
_name_name
996 """Return true when state is known."""
1001 """Return true if it is on."""
1006 """Return the brightness of this light between 0..255."""
1011 """Return the hs color value."""
1015 """Turn the light on."""
1016 if ATTR_HS_COLOR
in kwargs:
1017 rgb = color.color_hs_to_RGB(*kwargs[ATTR_HS_COLOR])
1021 if ATTR_BRIGHTNESS
in kwargs:
1022 brightness_pct =
int(100 * kwargs[ATTR_BRIGHTNESS] / 255)
1026 self.
_gateway_gateway.light.set_rgb(brightness_pct, rgb)
1031 """Turn the light off."""
1036 """Fetch state from the device."""
1038 state_dict = await self.
hasshass.async_add_executor_job(
1039 self.
_gateway_gateway.light.rgb_status
1041 except GatewayException
as ex:
1045 "Got exception while fetching the gateway light state: %s", ex
1050 self.
_is_on_is_on = state_dict[
"is_on"]
1054 self.
_rgb_rgb = state_dict[
"rgb"]
1055 self.
_hs_hs = color.color_RGB_to_hs(*self.
_rgb_rgb)
1059 """Representation of Xiaomi Gateway Bulb."""
1061 _attr_color_mode = ColorMode.COLOR_TEMP
1062 _attr_supported_color_modes = {ColorMode.COLOR_TEMP}
1066 """Return the brightness of the light."""
1067 return round((self.
_sub_device_sub_device.status[
"brightness"] * 255) / 100)
1071 """Return current color temperature."""
1072 return self.
_sub_device_sub_device.status[
"color_temp"]
1076 """Return true if light is on."""
1077 return self.
_sub_device_sub_device.status[
"status"] ==
"on"
1081 """Return min cct."""
1082 return self.
_sub_device_sub_device.status[
"cct_min"]
1086 """Return max cct."""
1087 return self.
_sub_device_sub_device.status[
"cct_max"]
1090 """Instruct the light to turn on."""
1091 await self.
hasshass.async_add_executor_job(self.
_sub_device_sub_device.on)
1093 if ATTR_COLOR_TEMP
in kwargs:
1094 color_temp = kwargs[ATTR_COLOR_TEMP]
1095 await self.
hasshass.async_add_executor_job(
1096 self.
_sub_device_sub_device.set_color_temp, color_temp
1099 if ATTR_BRIGHTNESS
in kwargs:
1100 brightness = round((kwargs[ATTR_BRIGHTNESS] * 100) / 255)
1101 await self.
hasshass.async_add_executor_job(
1102 self.
_sub_device_sub_device.set_brightness, brightness
1106 """Instruct the light to turn off."""
1107 await self.
hasshass.async_add_executor_job(self.
_sub_device_sub_device.off)
tuple[float, float]|None hs_color(self)
None async_turn_on(self, **Any kwargs)
None async_turn_off(self, **Any kwargs)
None turn_off(self, **Any kwargs)
None turn_on(self, **Any kwargs)
def __init__(self, gateway_device, gateway_name, gateway_device_id)
DeviceInfo device_info(self)
def _try_command(self, mask_error, func, *args, **kwargs)
def __init__(self, name, device, entry, unique_id)
None async_turn_on(self, **Any kwargs)
def extra_state_attributes(self)
None async_turn_off(self, **Any kwargs)
None async_turn_on(self, **Any kwargs)
def translate(value, left_min, left_max, right_min, right_max)
def __init__(self, name, device, entry, unique_id)
def __init__(self, name, device, entry, unique_id)
None async_turn_on(self, **Any kwargs)
def __init__(self, name, device, entry, unique_id)
None async_turn_off(self, **Any kwargs)
def async_night_light_mode_on(self)
def async_reminder_on(self)
def async_reminder_off(self)
def async_set_delayed_turn_off(self, timedelta time_period)
def __init__(self, name, device, entry, unique_id)
def async_eyecare_mode_on(self)
def delayed_turn_off_timestamp(int countdown, datetime.datetime current, datetime.datetime previous)
def async_eyecare_mode_off(self)
def async_night_light_mode_off(self)
def __init__(self, name, device, entry, unique_id)
def async_set_scene(self, int scene=1)
def delayed_turn_off_timestamp(int countdown, datetime.datetime current, datetime.datetime previous)
def async_set_delayed_turn_off(self, timedelta time_period)
None async_turn_on(self, **Any kwargs)
tuple[float, float]|None hs_color(self)
def __init__(self, name, device, entry, unique_id)
def async_set_delayed_turn_off(self, timedelta time_period)
None schedule_update_ha_state(self, bool force_refresh=False)
IssData update(pyiss.ISS iss)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)