diff --git a/homeassistant/components/bond/light.py b/homeassistant/components/bond/light.py index 4ee6e77dd7b..949c5a54070 100644 --- a/homeassistant/components/bond/light.py +++ b/homeassistant/components/bond/light.py @@ -3,7 +3,11 @@ from typing import Any, Callable, List, Optional from bond import DeviceTypes -from homeassistant.components.light import LightEntity +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, + SUPPORT_BRIGHTNESS, + LightEntity, +) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import Entity @@ -29,9 +33,15 @@ async def async_setup_entry( for device in devices if device.type == DeviceTypes.CEILING_FAN and device.supports_light() ] - async_add_entities(lights, True) + fireplaces = [ + BondFireplace(hub, device) + for device in devices + if device.type == DeviceTypes.FIREPLACE + ] + async_add_entities(fireplaces, True) + class BondLight(BondEntity, LightEntity): """Representation of a Bond light.""" @@ -59,3 +69,54 @@ class BondLight(BondEntity, LightEntity): def turn_off(self, **kwargs: Any) -> None: """Turn off the light.""" self._hub.bond.turnLightOff(self._device.device_id) + + +class BondFireplace(BondEntity, LightEntity): + """Representation of a Bond-controlled fireplace.""" + + def __init__(self, hub: BondHub, device: BondDevice): + """Create HA entity representing Bond fan.""" + super().__init__(hub, device) + + self._power: Optional[bool] = None + # Bond flame level, 0-100 + self._flame: Optional[int] = None + + @property + def supported_features(self) -> Optional[int]: + """Flag brightness as supported feature to represent flame level.""" + return SUPPORT_BRIGHTNESS + + @property + def is_on(self) -> bool: + """Return True if power is on.""" + return self._power == 1 + + def turn_on(self, **kwargs: Any) -> None: + """Turn the fireplace on.""" + self._hub.bond.turnOn(self._device.device_id) + + brightness = kwargs.get(ATTR_BRIGHTNESS) + if brightness: + flame = round((brightness * 100) / 255) + self._hub.bond.setFlame(self._device.device_id, flame) + + def turn_off(self, **kwargs: Any) -> None: + """Turn the fireplace off.""" + self._hub.bond.turnOff(self._device.device_id) + + @property + def brightness(self): + """Return the flame of this fireplace converted to HA brightness between 0..255.""" + return round(self._flame * 255 / 100) if self._flame else None + + @property + def icon(self) -> Optional[str]: + """Show fireplace icon for the entity.""" + return "mdi:fireplace" if self._power == 1 else "mdi:fireplace-off" + + def update(self): + """Fetch assumed state of the device from the hub using API.""" + state: dict = self._hub.bond.getDeviceState(self._device.device_id) + self._power = state.get("power") + self._flame = state.get("flame") diff --git a/tests/components/bond/test_light.py b/tests/components/bond/test_light.py index 66393151b4f..fc9edf64727 100644 --- a/tests/components/bond/test_light.py +++ b/tests/components/bond/test_light.py @@ -5,7 +5,7 @@ import logging from bond import Actions, DeviceTypes from homeassistant import core -from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN +from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON from homeassistant.helpers.entity_registry import EntityRegistry from homeassistant.util import utcnow @@ -27,6 +27,11 @@ def ceiling_fan(name: str): } +def fireplace(name: str): + """Create a fireplace with given name.""" + return {"name": name, "type": DeviceTypes.FIREPLACE} + + async def test_entity_registry(hass: core.HomeAssistant): """Tests that the devices are registered in the entity registry.""" await setup_platform(hass, LIGHT_DOMAIN, ceiling_fan("name-1")) @@ -91,3 +96,54 @@ async def test_update_reports_light_is_off(hass: core.HomeAssistant): await hass.async_block_till_done() assert hass.states.get("light.name_1").state == "off" + + +async def test_turn_on_fireplace(hass: core.HomeAssistant): + """Tests that turn on command delegates to API.""" + await setup_platform( + hass, LIGHT_DOMAIN, fireplace("name-1"), bond_device_id="test-device-id" + ) + + with patch("homeassistant.components.bond.Bond.turnOn") as mock_turn_on, patch( + "homeassistant.components.bond.Bond.setFlame" + ) as mock_set_flame: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "light.name_1", ATTR_BRIGHTNESS: 128}, + blocking=True, + ) + await hass.async_block_till_done() + + mock_turn_on.assert_called_once() + mock_set_flame.assert_called_once_with("test-device-id", 50) + + +async def test_turn_off_fireplace(hass: core.HomeAssistant): + """Tests that turn off command delegates to API.""" + await setup_platform(hass, LIGHT_DOMAIN, fireplace("name-1")) + + with patch("homeassistant.components.bond.Bond.turnOff") as mock_turn_off: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "light.name_1"}, + blocking=True, + ) + await hass.async_block_till_done() + mock_turn_off.assert_called_once() + + +async def test_flame_converted_to_brightness(hass: core.HomeAssistant): + """Tests that reported flame level (0..100) converted to HA brightness (0...255).""" + await setup_platform(hass, LIGHT_DOMAIN, fireplace("name-1")) + + with patch( + "homeassistant.components.bond.Bond.getDeviceState", + return_value={"power": 1, "flame": 50}, + ): + async_fire_time_changed(hass, utcnow() + timedelta(seconds=30)) + await hass.async_block_till_done() + + _LOGGER.warning(hass.states.get("light.name_1").attributes) + assert hass.states.get("light.name_1").attributes[ATTR_BRIGHTNESS] == 128