diff --git a/homeassistant/components/wled/__init__.py b/homeassistant/components/wled/__init__.py index d54cfe3cd1cae6f7fbb2674259934e7823cde39c..ec2ad1bb6fe763f12a10b69558903e4b6ed33b68 100644 --- a/homeassistant/components/wled/__init__.py +++ b/homeassistant/components/wled/__init__.py @@ -1,6 +1,7 @@ """Support for WLED.""" from __future__ import annotations +from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN @@ -14,6 +15,7 @@ from .const import DOMAIN from .coordinator import WLEDDataUpdateCoordinator PLATFORMS = ( + BINARY_SENSOR_DOMAIN, BUTTON_DOMAIN, LIGHT_DOMAIN, SELECT_DOMAIN, diff --git a/homeassistant/components/wled/binary_sensor.py b/homeassistant/components/wled/binary_sensor.py new file mode 100644 index 0000000000000000000000000000000000000000..45df589de618a9ddf00d8e7c1ec9a4796366a62c --- /dev/null +++ b/homeassistant/components/wled/binary_sensor.py @@ -0,0 +1,58 @@ +"""Support for WLED binary sensor.""" +from __future__ import annotations + +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_UPDATE, + BinarySensorEntity, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ENTITY_CATEGORY_DIAGNOSTIC +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from .const import DOMAIN +from .coordinator import WLEDDataUpdateCoordinator +from .models import WLEDEntity + + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up a WLED binary sensor based on a config entry.""" + coordinator: WLEDDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + async_add_entities( + [ + WLEDUpdateBinarySensor(coordinator), + ] + ) + + +class WLEDUpdateBinarySensor(WLEDEntity, BinarySensorEntity): + """Defines a WLED firmware binary sensor.""" + + _attr_entity_category = ENTITY_CATEGORY_DIAGNOSTIC + _attr_device_class = DEVICE_CLASS_UPDATE + + def __init__(self, coordinator: WLEDDataUpdateCoordinator) -> None: + """Initialize the button entity.""" + super().__init__(coordinator=coordinator) + self._attr_name = f"{coordinator.data.info.name} Firmware" + self._attr_unique_id = f"{coordinator.data.info.mac_address}_update" + + @property + def is_on(self) -> bool: + """Return the state of the sensor.""" + current = self.coordinator.data.info.version + beta = self.coordinator.data.info.version_latest_beta + stable = self.coordinator.data.info.version_latest_stable + + return current is not None and ( + (stable is not None and stable > current) + or ( + beta is not None + and (current.alpha or current.beta or current.release_candidate) + and beta > current + ) + ) diff --git a/tests/components/wled/test_binary_sensor.py b/tests/components/wled/test_binary_sensor.py new file mode 100644 index 0000000000000000000000000000000000000000..61a883b780cb8c59ec1493da1fa8dfae65b2bdec --- /dev/null +++ b/tests/components/wled/test_binary_sensor.py @@ -0,0 +1,54 @@ +"""Tests for the WLED binary sensor platform.""" +from unittest.mock import MagicMock + +import pytest + +from homeassistant.components.binary_sensor import DEVICE_CLASS_UPDATE +from homeassistant.const import ( + ATTR_DEVICE_CLASS, + ATTR_ICON, + ENTITY_CATEGORY_DIAGNOSTIC, + STATE_OFF, + STATE_ON, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from tests.common import MockConfigEntry + + +async def test_update_available( + hass: HomeAssistant, init_integration: MockConfigEntry, mock_wled: MagicMock +) -> None: + """Test the firmware update binary sensor.""" + entity_registry = er.async_get(hass) + + state = hass.states.get("binary_sensor.wled_rgb_light_firmware") + assert state + assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_UPDATE + assert state.state == STATE_ON + assert ATTR_ICON not in state.attributes + + entry = entity_registry.async_get("binary_sensor.wled_rgb_light_firmware") + assert entry + assert entry.unique_id == "aabbccddeeff_update" + assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC + + +@pytest.mark.parametrize("mock_wled", ["wled/rgb_websocket.json"], indirect=True) +async def test_no_update_available( + hass: HomeAssistant, init_integration: MockConfigEntry, mock_wled: MagicMock +) -> None: + """Test the update binary sensor. There is no update available.""" + entity_registry = er.async_get(hass) + + state = hass.states.get("binary_sensor.wled_websocket_firmware") + assert state + assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_UPDATE + assert state.state == STATE_OFF + assert ATTR_ICON not in state.attributes + + entry = entity_registry.async_get("binary_sensor.wled_websocket_firmware") + assert entry + assert entry.unique_id == "aabbccddeeff_update" + assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC