mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add light platform to SmartTub (#46886)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
1a27af43cc
commit
5cd022a683
@ -7,7 +7,7 @@ from .controller import SmartTubController
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = ["climate", "sensor", "switch"]
|
||||
PLATFORMS = ["climate", "light", "sensor", "switch"]
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
|
@ -13,3 +13,10 @@ API_TIMEOUT = 5
|
||||
|
||||
DEFAULT_MIN_TEMP = 18.5
|
||||
DEFAULT_MAX_TEMP = 40
|
||||
|
||||
# the device doesn't remember any state for the light, so we have to choose a
|
||||
# mode (smarttub.SpaLight.LightMode) when turning it on. There is no white
|
||||
# mode.
|
||||
DEFAULT_LIGHT_EFFECT = "purple"
|
||||
# default to 50% brightness
|
||||
DEFAULT_LIGHT_BRIGHTNESS = 128
|
||||
|
@ -86,13 +86,15 @@ class SmartTubController:
|
||||
return data
|
||||
|
||||
async def _get_spa_data(self, spa):
|
||||
status, pumps = await asyncio.gather(
|
||||
status, pumps, lights = await asyncio.gather(
|
||||
spa.get_status(),
|
||||
spa.get_pumps(),
|
||||
spa.get_lights(),
|
||||
)
|
||||
return {
|
||||
"status": status,
|
||||
"pumps": {pump.id: pump for pump in pumps},
|
||||
"lights": {light.zone: light for light in lights},
|
||||
}
|
||||
|
||||
async def async_register_devices(self, entry):
|
||||
|
141
homeassistant/components/smarttub/light.py
Normal file
141
homeassistant/components/smarttub/light.py
Normal file
@ -0,0 +1,141 @@
|
||||
"""Platform for light integration."""
|
||||
import logging
|
||||
|
||||
from smarttub import SpaLight
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_EFFECT,
|
||||
EFFECT_COLORLOOP,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_EFFECT,
|
||||
LightEntity,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
DEFAULT_LIGHT_BRIGHTNESS,
|
||||
DEFAULT_LIGHT_EFFECT,
|
||||
DOMAIN,
|
||||
SMARTTUB_CONTROLLER,
|
||||
)
|
||||
from .entity import SmartTubEntity
|
||||
from .helpers import get_spa_name
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Set up entities for any lights in the tub."""
|
||||
|
||||
controller = hass.data[DOMAIN][entry.entry_id][SMARTTUB_CONTROLLER]
|
||||
|
||||
entities = [
|
||||
SmartTubLight(controller.coordinator, light)
|
||||
for spa in controller.spas
|
||||
for light in await spa.get_lights()
|
||||
]
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class SmartTubLight(SmartTubEntity, LightEntity):
|
||||
"""A light on a spa."""
|
||||
|
||||
def __init__(self, coordinator, light):
|
||||
"""Initialize the entity."""
|
||||
super().__init__(coordinator, light.spa, "light")
|
||||
self.light_zone = light.zone
|
||||
|
||||
@property
|
||||
def light(self) -> SpaLight:
|
||||
"""Return the underlying SpaLight object for this entity."""
|
||||
return self.coordinator.data[self.spa.id]["lights"][self.light_zone]
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return a unique ID for this light entity."""
|
||||
return f"{super().unique_id}-{self.light_zone}"
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return a name for this light entity."""
|
||||
spa_name = get_spa_name(self.spa)
|
||||
return f"{spa_name} Light {self.light_zone}"
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
|
||||
# SmartTub intensity is 0..100
|
||||
return self._smarttub_to_hass_brightness(self.light.intensity)
|
||||
|
||||
@staticmethod
|
||||
def _smarttub_to_hass_brightness(intensity):
|
||||
if intensity in (0, 1):
|
||||
return 0
|
||||
return round(intensity * 255 / 100)
|
||||
|
||||
@staticmethod
|
||||
def _hass_to_smarttub_brightness(brightness):
|
||||
return round(brightness * 100 / 255)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the light is on."""
|
||||
return self.light.mode != SpaLight.LightMode.OFF
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
return SUPPORT_BRIGHTNESS | SUPPORT_EFFECT
|
||||
|
||||
@property
|
||||
def effect(self):
|
||||
"""Return the current effect."""
|
||||
mode = self.light.mode.name.lower()
|
||||
if mode in self.effect_list:
|
||||
return mode
|
||||
return None
|
||||
|
||||
@property
|
||||
def effect_list(self):
|
||||
"""Return the list of supported effects."""
|
||||
effects = [
|
||||
effect
|
||||
for effect in map(self._light_mode_to_effect, SpaLight.LightMode)
|
||||
if effect is not None
|
||||
]
|
||||
|
||||
return effects
|
||||
|
||||
@staticmethod
|
||||
def _light_mode_to_effect(light_mode: SpaLight.LightMode):
|
||||
if light_mode == SpaLight.LightMode.OFF:
|
||||
return None
|
||||
if light_mode == SpaLight.LightMode.HIGH_SPEED_COLOR_WHEEL:
|
||||
return EFFECT_COLORLOOP
|
||||
|
||||
return light_mode.name.lower()
|
||||
|
||||
@staticmethod
|
||||
def _effect_to_light_mode(effect):
|
||||
if effect == EFFECT_COLORLOOP:
|
||||
return SpaLight.LightMode.HIGH_SPEED_COLOR_WHEEL
|
||||
|
||||
return SpaLight.LightMode[effect.upper()]
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the light on."""
|
||||
|
||||
mode = self._effect_to_light_mode(kwargs.get(ATTR_EFFECT, DEFAULT_LIGHT_EFFECT))
|
||||
intensity = self._hass_to_smarttub_brightness(
|
||||
kwargs.get(ATTR_BRIGHTNESS, DEFAULT_LIGHT_BRIGHTNESS)
|
||||
)
|
||||
|
||||
await self.light.set_mode(mode, intensity)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the light off."""
|
||||
await self.light.set_mode(self.light.LightMode.OFF, 0)
|
||||
await self.coordinator.async_request_refresh()
|
@ -90,6 +90,20 @@ def mock_spa():
|
||||
|
||||
mock_spa.get_pumps.return_value = [mock_circulation_pump, mock_jet_off, mock_jet_on]
|
||||
|
||||
mock_light_off = create_autospec(smarttub.SpaLight, instance=True)
|
||||
mock_light_off.spa = mock_spa
|
||||
mock_light_off.zone = 1
|
||||
mock_light_off.intensity = 0
|
||||
mock_light_off.mode = smarttub.SpaLight.LightMode.OFF
|
||||
|
||||
mock_light_on = create_autospec(smarttub.SpaLight, instance=True)
|
||||
mock_light_on.spa = mock_spa
|
||||
mock_light_on.zone = 2
|
||||
mock_light_on.intensity = 50
|
||||
mock_light_on.mode = smarttub.SpaLight.LightMode.PURPLE
|
||||
|
||||
mock_spa.get_lights.return_value = [mock_light_off, mock_light_on]
|
||||
|
||||
return mock_spa
|
||||
|
||||
|
||||
|
38
tests/components/smarttub/test_light.py
Normal file
38
tests/components/smarttub/test_light.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""Test the SmartTub light platform."""
|
||||
|
||||
from smarttub import SpaLight
|
||||
|
||||
|
||||
async def test_light(spa, setup_entry, hass):
|
||||
"""Test light entity."""
|
||||
|
||||
for light in spa.get_lights.return_value:
|
||||
entity_id = f"light.{spa.brand}_{spa.model}_light_{light.zone}"
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None
|
||||
if light.mode == SpaLight.LightMode.OFF:
|
||||
assert state.state == "off"
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"entity_id": entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
light.set_mode.assert_called()
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"entity_id": entity_id, "brightness": 255},
|
||||
blocking=True,
|
||||
)
|
||||
light.set_mode.assert_called_with(SpaLight.LightMode.PURPLE, 100)
|
||||
|
||||
else:
|
||||
assert state.state == "on"
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_off",
|
||||
{"entity_id": entity_id},
|
||||
blocking=True,
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user