diff --git a/homeassistant/components/wled/__init__.py b/homeassistant/components/wled/__init__.py index ba87fb58122..b4834347694 100644 --- a/homeassistant/components/wled/__init__.py +++ b/homeassistant/components/wled/__init__.py @@ -5,9 +5,12 @@ from __future__ import annotations from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.typing import ConfigType +from homeassistant.util.hass_dict import HassKey -from .const import LOGGER -from .coordinator import WLEDDataUpdateCoordinator +from .const import DOMAIN +from .coordinator import WLEDDataUpdateCoordinator, WLEDReleasesDataUpdateCoordinator PLATFORMS = ( Platform.BUTTON, @@ -21,23 +24,26 @@ PLATFORMS = ( type WLEDConfigEntry = ConfigEntry[WLEDDataUpdateCoordinator] +WLED_KEY: HassKey[WLEDReleasesDataUpdateCoordinator] = HassKey(DOMAIN) +CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN) + + +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: + """Set up the WLED integration. + + We set up a single coordinator for fetching WLED releases, which + is used across all WLED devices (and config entries) to avoid + fetching the same data multiple times for each. + """ + hass.data[WLED_KEY] = WLEDReleasesDataUpdateCoordinator(hass) + await hass.data[WLED_KEY].async_request_refresh() + return True + async def async_setup_entry(hass: HomeAssistant, entry: WLEDConfigEntry) -> bool: """Set up WLED from a config entry.""" - coordinator = WLEDDataUpdateCoordinator(hass, entry=entry) - await coordinator.async_config_entry_first_refresh() - - if coordinator.data.info.leds.cct: - LOGGER.error( - ( - "WLED device '%s' has a CCT channel, which is not supported by " - "this integration" - ), - entry.title, - ) - return False - - entry.runtime_data = coordinator + entry.runtime_data = WLEDDataUpdateCoordinator(hass, entry=entry) + await entry.runtime_data.async_config_entry_first_refresh() # Set up all platforms for this device/entry. await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) diff --git a/homeassistant/components/wled/config_flow.py b/homeassistant/components/wled/config_flow.py index c40753b686a..7853ad2101e 100644 --- a/homeassistant/components/wled/config_flow.py +++ b/homeassistant/components/wled/config_flow.py @@ -46,8 +46,6 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN): except WLEDConnectionError: errors["base"] = "cannot_connect" else: - if device.info.leds.cct: - return self.async_abort(reason="cct_unsupported") await self.async_set_unique_id(device.info.mac_address) self._abort_if_unique_id_configured( updates={CONF_HOST: user_input[CONF_HOST]} @@ -84,9 +82,6 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN): except WLEDConnectionError: return self.async_abort(reason="cannot_connect") - if self.discovered_device.info.leds.cct: - return self.async_abort(reason="cct_unsupported") - await self.async_set_unique_id(self.discovered_device.info.mac_address) self._abort_if_unique_id_configured(updates={CONF_HOST: discovery_info.host}) diff --git a/homeassistant/components/wled/const.py b/homeassistant/components/wled/const.py index f698347537c..635b78dcf13 100644 --- a/homeassistant/components/wled/const.py +++ b/homeassistant/components/wled/const.py @@ -3,11 +3,16 @@ from datetime import timedelta import logging +from wled import LightCapability + +from homeassistant.components.light import ColorMode + # Integration domain DOMAIN = "wled" LOGGER = logging.getLogger(__package__) SCAN_INTERVAL = timedelta(seconds=10) +RELEASES_SCAN_INTERVAL = timedelta(hours=3) # Options CONF_KEEP_MAIN_LIGHT = "keep_master_light" @@ -24,3 +29,72 @@ ATTR_SOFTWARE_VERSION = "sw_version" ATTR_SPEED = "speed" ATTR_TARGET_BRIGHTNESS = "target_brightness" ATTR_UDP_PORT = "udp_port" + + +LIGHT_CAPABILITIES_COLOR_MODE_MAPPING: dict[LightCapability, list[ColorMode]] = { + LightCapability.NONE: [ + ColorMode.ONOFF, + ], + LightCapability.RGB_COLOR: [ + ColorMode.RGB, + ], + LightCapability.WHITE_CHANNEL: [ + ColorMode.BRIGHTNESS, + ], + LightCapability.RGB_COLOR | LightCapability.WHITE_CHANNEL: [ + ColorMode.RGBW, + ], + LightCapability.COLOR_TEMPERATURE: [ + ColorMode.COLOR_TEMP, + ], + LightCapability.RGB_COLOR | LightCapability.COLOR_TEMPERATURE: [ + ColorMode.RGBWW, + ], + LightCapability.WHITE_CHANNEL | LightCapability.COLOR_TEMPERATURE: [ + ColorMode.COLOR_TEMP, + ], + LightCapability.RGB_COLOR + | LightCapability.WHITE_CHANNEL + | LightCapability.COLOR_TEMPERATURE: [ + ColorMode.RGB, + ColorMode.COLOR_TEMP, + ], + LightCapability.MANUAL_WHITE: [ + ColorMode.BRIGHTNESS, + ], + LightCapability.RGB_COLOR | LightCapability.MANUAL_WHITE: [ + ColorMode.RGBW, + ], + LightCapability.WHITE_CHANNEL | LightCapability.MANUAL_WHITE: [ + ColorMode.BRIGHTNESS, + ], + LightCapability.RGB_COLOR + | LightCapability.WHITE_CHANNEL + | LightCapability.MANUAL_WHITE: [ + ColorMode.RGBW, + ColorMode.WHITE, + ], + LightCapability.COLOR_TEMPERATURE | LightCapability.MANUAL_WHITE: [ + ColorMode.COLOR_TEMP, + ColorMode.WHITE, + ], + LightCapability.RGB_COLOR + | LightCapability.COLOR_TEMPERATURE + | LightCapability.MANUAL_WHITE: [ + ColorMode.RGBW, + ColorMode.COLOR_TEMP, + ], + LightCapability.WHITE_CHANNEL + | LightCapability.COLOR_TEMPERATURE + | LightCapability.MANUAL_WHITE: [ + ColorMode.COLOR_TEMP, + ColorMode.WHITE, + ], + LightCapability.RGB_COLOR + | LightCapability.WHITE_CHANNEL + | LightCapability.COLOR_TEMPERATURE + | LightCapability.MANUAL_WHITE: [ + ColorMode.RGBW, + ColorMode.COLOR_TEMP, + ], +} diff --git a/homeassistant/components/wled/coordinator.py b/homeassistant/components/wled/coordinator.py index f6219c63cb8..cb39fde5e5a 100644 --- a/homeassistant/components/wled/coordinator.py +++ b/homeassistant/components/wled/coordinator.py @@ -2,7 +2,14 @@ from __future__ import annotations -from wled import WLED, Device as WLEDDevice, WLEDConnectionClosedError, WLEDError +from wled import ( + WLED, + Device as WLEDDevice, + Releases, + WLEDConnectionClosedError, + WLEDError, + WLEDReleases, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP @@ -15,6 +22,7 @@ from .const import ( DEFAULT_KEEP_MAIN_LIGHT, DOMAIN, LOGGER, + RELEASES_SCAN_INTERVAL, SCAN_INTERVAL, ) @@ -101,17 +109,37 @@ class WLEDDataUpdateCoordinator(DataUpdateCoordinator[WLEDDevice]): async def _async_update_data(self) -> WLEDDevice: """Fetch data from WLED.""" try: - device = await self.wled.update(full_update=not self.last_update_success) + device = await self.wled.update() except WLEDError as error: raise UpdateFailed(f"Invalid response from API: {error}") from error # If the device supports a WebSocket, try activating it. if ( device.info.websocket is not None - and device.info.leds.cct is not True and not self.wled.connected and not self.unsub ): self._use_websocket() return device + + +class WLEDReleasesDataUpdateCoordinator(DataUpdateCoordinator[Releases]): + """Class to manage fetching WLED releases.""" + + def __init__(self, hass: HomeAssistant) -> None: + """Initialize global WLED releases updater.""" + self.wled = WLEDReleases(session=async_get_clientsession(hass)) + super().__init__( + hass, + LOGGER, + name=DOMAIN, + update_interval=RELEASES_SCAN_INTERVAL, + ) + + async def _async_update_data(self) -> Releases: + """Fetch release data from WLED.""" + try: + return await self.wled.releases() + except WLEDError as error: + raise UpdateFailed(f"Invalid response from GitHub API: {error}") from error diff --git a/homeassistant/components/wled/diagnostics.py b/homeassistant/components/wled/diagnostics.py index e81760e0f72..732cd3602a0 100644 --- a/homeassistant/components/wled/diagnostics.py +++ b/homeassistant/components/wled/diagnostics.py @@ -17,31 +17,23 @@ async def async_get_config_entry_diagnostics( coordinator = entry.runtime_data data: dict[str, Any] = { - "info": async_redact_data(coordinator.data.info.__dict__, "wifi"), - "state": coordinator.data.state.__dict__, + "info": async_redact_data(coordinator.data.info.to_dict(), "wifi"), + "state": coordinator.data.state.to_dict(), "effects": { - effect.effect_id: effect.name for effect in coordinator.data.effects + effect.effect_id: effect.name + for effect in coordinator.data.effects.values() }, "palettes": { - palette.palette_id: palette.name for palette in coordinator.data.palettes + palette.palette_id: palette.name + for palette in coordinator.data.palettes.values() }, "playlists": { - playlist.playlist_id: { - "name": playlist.name, - "repeat": playlist.repeat, - "shuffle": playlist.shuffle, - "end": playlist.end.preset_id if playlist.end else None, - } - for playlist in coordinator.data.playlists + playlist.playlist_id: playlist.name + for playlist in coordinator.data.playlists.values() }, "presets": { - preset.preset_id: { - "name": preset.name, - "quick_label": preset.quick_label, - "on": preset.on, - "transition": preset.transition, - } - for preset in coordinator.data.presets + preset.preset_id: preset.name + for preset in coordinator.data.presets.values() }, } return data diff --git a/homeassistant/components/wled/light.py b/homeassistant/components/wled/light.py index 36ebd024de3..5423df84686 100644 --- a/homeassistant/components/wled/light.py +++ b/homeassistant/components/wled/light.py @@ -19,7 +19,12 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import WLEDConfigEntry -from .const import ATTR_COLOR_PRIMARY, ATTR_ON, ATTR_SEGMENT_ID +from .const import ( + ATTR_COLOR_PRIMARY, + ATTR_ON, + ATTR_SEGMENT_ID, + LIGHT_CAPABILITIES_COLOR_MODE_MAPPING, +) from .coordinator import WLEDDataUpdateCoordinator from .entity import WLEDEntity from .helpers import wled_exception_handler @@ -112,8 +117,6 @@ class WLEDSegmentLight(WLEDEntity, LightEntity): ) -> None: """Initialize WLED segment light.""" super().__init__(coordinator=coordinator) - self._rgbw = coordinator.data.info.leds.rgbw - self._wv = coordinator.data.info.leds.wv self._segment = segment # Segment 0 uses a simpler name, which is more natural for when using @@ -127,18 +130,24 @@ class WLEDSegmentLight(WLEDEntity, LightEntity): f"{self.coordinator.data.info.mac_address}_{self._segment}" ) - self._attr_color_mode = ColorMode.RGB - self._attr_supported_color_modes = {ColorMode.RGB} - if self._rgbw and self._wv: - self._attr_color_mode = ColorMode.RGBW - self._attr_supported_color_modes = {ColorMode.RGBW} + if ( + coordinator.data.info.leds.segment_light_capabilities is not None + and ( + color_modes := LIGHT_CAPABILITIES_COLOR_MODE_MAPPING.get( + coordinator.data.info.leds.segment_light_capabilities[segment] + ) + ) + is not None + ): + self._attr_color_mode = color_modes[0] + self._attr_supported_color_modes = set(color_modes) @property def available(self) -> bool: """Return True if entity is available.""" try: self.coordinator.data.state.segments[self._segment] - except IndexError: + except KeyError: return False return super().available @@ -146,20 +155,23 @@ class WLEDSegmentLight(WLEDEntity, LightEntity): @property def rgb_color(self) -> tuple[int, int, int] | None: """Return the color value.""" - return self.coordinator.data.state.segments[self._segment].color_primary[:3] + if not (color := self.coordinator.data.state.segments[self._segment].color): + return None + return color.primary[:3] @property def rgbw_color(self) -> tuple[int, int, int, int] | None: """Return the color value.""" - return cast( - tuple[int, int, int, int], - self.coordinator.data.state.segments[self._segment].color_primary, - ) + if not (color := self.coordinator.data.state.segments[self._segment].color): + return None + return cast(tuple[int, int, int, int], color.primary) @property def effect(self) -> str | None: """Return the current effect of the light.""" - return self.coordinator.data.state.segments[self._segment].effect.name + return self.coordinator.data.effects[ + int(self.coordinator.data.state.segments[self._segment].effect_id) + ].name @property def brightness(self) -> int | None: @@ -178,7 +190,7 @@ class WLEDSegmentLight(WLEDEntity, LightEntity): @property def effect_list(self) -> list[str]: """Return the list of supported effects.""" - return [effect.name for effect in self.coordinator.data.effects] + return [effect.name for effect in self.coordinator.data.effects.values()] @property def is_on(self) -> bool: @@ -258,7 +270,11 @@ def async_update_segments( async_add_entities: AddEntitiesCallback, ) -> None: """Update segments.""" - segment_ids = {light.segment_id for light in coordinator.data.state.segments} + segment_ids = { + light.segment_id + for light in coordinator.data.state.segments.values() + if light.segment_id is not None + } new_entities: list[WLEDMainLight | WLEDSegmentLight] = [] # More than 1 segment now? No main? Add main controls diff --git a/homeassistant/components/wled/manifest.json b/homeassistant/components/wled/manifest.json index a01bbcabdd6..85d8e957120 100644 --- a/homeassistant/components/wled/manifest.json +++ b/homeassistant/components/wled/manifest.json @@ -7,6 +7,6 @@ "integration_type": "device", "iot_class": "local_push", "quality_scale": "platinum", - "requirements": ["wled==0.18.0"], + "requirements": ["wled==0.19.2"], "zeroconf": ["_wled._tcp.local."] } diff --git a/homeassistant/components/wled/number.py b/homeassistant/components/wled/number.py index 5af466360bb..225d783bfdb 100644 --- a/homeassistant/components/wled/number.py +++ b/homeassistant/components/wled/number.py @@ -44,7 +44,7 @@ async def async_setup_entry( class WLEDNumberEntityDescription(NumberEntityDescription): """Class describing WLED number entities.""" - value_fn: Callable[[Segment], float | None] + value_fn: Callable[[Segment], int | None] NUMBERS = [ @@ -64,7 +64,7 @@ NUMBERS = [ native_step=1, native_min_value=0, native_max_value=255, - value_fn=lambda segment: segment.intensity, + value_fn=lambda segment: int(segment.intensity), ), ] @@ -100,7 +100,7 @@ class WLEDNumber(WLEDEntity, NumberEntity): """Return True if entity is available.""" try: self.coordinator.data.state.segments[self._segment] - except IndexError: + except KeyError: return False return super().available @@ -133,7 +133,11 @@ def async_update_segments( async_add_entities: AddEntitiesCallback, ) -> None: """Update segments.""" - segment_ids = {segment.segment_id for segment in coordinator.data.state.segments} + segment_ids = { + segment.segment_id + for segment in coordinator.data.state.segments.values() + if segment.segment_id is not None + } new_entities: list[WLEDNumber] = [] diff --git a/homeassistant/components/wled/select.py b/homeassistant/components/wled/select.py index 20b14531ac7..a645b04573c 100644 --- a/homeassistant/components/wled/select.py +++ b/homeassistant/components/wled/select.py @@ -4,7 +4,7 @@ from __future__ import annotations from functools import partial -from wled import Live, Playlist, Preset +from wled import LiveDataOverride from homeassistant.components.select import SelectEntity from homeassistant.const import EntityCategory @@ -56,17 +56,17 @@ class WLEDLiveOverrideSelect(WLEDEntity, SelectEntity): super().__init__(coordinator=coordinator) self._attr_unique_id = f"{coordinator.data.info.mac_address}_live_override" - self._attr_options = [str(live.value) for live in Live] + self._attr_options = [str(live.value) for live in LiveDataOverride] @property def current_option(self) -> str: """Return the current selected live override.""" - return str(self.coordinator.data.state.lor.value) + return str(self.coordinator.data.state.live_data_override.value) @wled_exception_handler async def async_select_option(self, option: str) -> None: """Set WLED state to the selected live override state.""" - await self.coordinator.wled.live(live=Live(int(option))) + await self.coordinator.wled.live(live=LiveDataOverride(int(option))) class WLEDPresetSelect(WLEDEntity, SelectEntity): @@ -79,7 +79,9 @@ class WLEDPresetSelect(WLEDEntity, SelectEntity): super().__init__(coordinator=coordinator) self._attr_unique_id = f"{coordinator.data.info.mac_address}_preset" - self._attr_options = [preset.name for preset in self.coordinator.data.presets] + self._attr_options = [ + preset.name for preset in self.coordinator.data.presets.values() + ] @property def available(self) -> bool: @@ -89,9 +91,13 @@ class WLEDPresetSelect(WLEDEntity, SelectEntity): @property def current_option(self) -> str | None: """Return the current selected preset.""" - if not isinstance(self.coordinator.data.state.preset, Preset): + if not self.coordinator.data.state.preset_id: return None - return self.coordinator.data.state.preset.name + if preset := self.coordinator.data.presets.get( + self.coordinator.data.state.preset_id + ): + return preset.name + return None @wled_exception_handler async def async_select_option(self, option: str) -> None: @@ -110,7 +116,7 @@ class WLEDPlaylistSelect(WLEDEntity, SelectEntity): self._attr_unique_id = f"{coordinator.data.info.mac_address}_playlist" self._attr_options = [ - playlist.name for playlist in self.coordinator.data.playlists + playlist.name for playlist in self.coordinator.data.playlists.values() ] @property @@ -121,9 +127,13 @@ class WLEDPlaylistSelect(WLEDEntity, SelectEntity): @property def current_option(self) -> str | None: """Return the currently selected playlist.""" - if not isinstance(self.coordinator.data.state.playlist, Playlist): + if not self.coordinator.data.state.playlist_id: return None - return self.coordinator.data.state.playlist.name + if playlist := self.coordinator.data.playlists.get( + self.coordinator.data.state.playlist_id + ): + return playlist.name + return None @wled_exception_handler async def async_select_option(self, option: str) -> None: @@ -150,7 +160,7 @@ class WLEDPaletteSelect(WLEDEntity, SelectEntity): self._attr_unique_id = f"{coordinator.data.info.mac_address}_palette_{segment}" self._attr_options = [ - palette.name for palette in self.coordinator.data.palettes + palette.name for palette in self.coordinator.data.palettes.values() ] self._segment = segment @@ -159,7 +169,7 @@ class WLEDPaletteSelect(WLEDEntity, SelectEntity): """Return True if entity is available.""" try: self.coordinator.data.state.segments[self._segment] - except IndexError: + except KeyError: return False return super().available @@ -167,7 +177,9 @@ class WLEDPaletteSelect(WLEDEntity, SelectEntity): @property def current_option(self) -> str | None: """Return the current selected color palette.""" - return self.coordinator.data.state.segments[self._segment].palette.name + return self.coordinator.data.palettes[ + int(self.coordinator.data.state.segments[self._segment].palette_id) + ].name @wled_exception_handler async def async_select_option(self, option: str) -> None: @@ -182,7 +194,11 @@ def async_update_segments( async_add_entities: AddEntitiesCallback, ) -> None: """Update segments.""" - segment_ids = {segment.segment_id for segment in coordinator.data.state.segments} + segment_ids = { + segment.segment_id + for segment in coordinator.data.state.segments.values() + if segment.segment_id is not None + } new_entities: list[WLEDPaletteSelect] = [] diff --git a/homeassistant/components/wled/sensor.py b/homeassistant/components/wled/sensor.py index 7d18665a085..4f97c367612 100644 --- a/homeassistant/components/wled/sensor.py +++ b/homeassistant/components/wled/sensor.py @@ -4,7 +4,7 @@ from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass -from datetime import datetime, timedelta +from datetime import datetime from wled import Device as WLEDDevice @@ -71,7 +71,7 @@ SENSORS: tuple[WLEDSensorEntityDescription, ...] = ( device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, - value_fn=lambda device: (utcnow() - timedelta(seconds=device.info.uptime)), + value_fn=lambda device: (utcnow() - device.info.uptime), ), WLEDSensorEntityDescription( key="free_heap", diff --git a/homeassistant/components/wled/strings.json b/homeassistant/components/wled/strings.json index 9581641f545..50dc0129369 100644 --- a/homeassistant/components/wled/strings.json +++ b/homeassistant/components/wled/strings.json @@ -21,8 +21,7 @@ }, "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", - "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", - "cct_unsupported": "This WLED device uses CCT channels, which is not supported by this integration" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" } }, "options": { diff --git a/homeassistant/components/wled/switch.py b/homeassistant/components/wled/switch.py index 7ec75b956c0..643834dcdec 100644 --- a/homeassistant/components/wled/switch.py +++ b/homeassistant/components/wled/switch.py @@ -11,7 +11,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import WLEDConfigEntry -from .const import ATTR_DURATION, ATTR_FADE, ATTR_TARGET_BRIGHTNESS, ATTR_UDP_PORT +from .const import ATTR_DURATION, ATTR_TARGET_BRIGHTNESS, ATTR_UDP_PORT from .coordinator import WLEDDataUpdateCoordinator from .entity import WLEDEntity from .helpers import wled_exception_handler @@ -62,7 +62,6 @@ class WLEDNightlightSwitch(WLEDEntity, SwitchEntity): state = self.coordinator.data.state return { ATTR_DURATION: state.nightlight.duration, - ATTR_FADE: state.nightlight.fade, ATTR_TARGET_BRIGHTNESS: state.nightlight.target_brightness, } @@ -171,7 +170,7 @@ class WLEDReverseSwitch(WLEDEntity, SwitchEntity): """Return True if entity is available.""" try: self.coordinator.data.state.segments[self._segment] - except IndexError: + except KeyError: return False return super().available @@ -199,7 +198,11 @@ def async_update_segments( async_add_entities: AddEntitiesCallback, ) -> None: """Update segments.""" - segment_ids = {segment.segment_id for segment in coordinator.data.state.segments} + segment_ids = { + segment.segment_id + for segment in coordinator.data.state.segments.values() + if segment.segment_id is not None + } new_entities: list[WLEDReverseSwitch] = [] diff --git a/homeassistant/components/wled/update.py b/homeassistant/components/wled/update.py index 05df5fcf54f..384b394ac50 100644 --- a/homeassistant/components/wled/update.py +++ b/homeassistant/components/wled/update.py @@ -12,8 +12,8 @@ from homeassistant.components.update import ( from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import WLEDConfigEntry -from .coordinator import WLEDDataUpdateCoordinator +from . import WLED_KEY, WLEDConfigEntry +from .coordinator import WLEDDataUpdateCoordinator, WLEDReleasesDataUpdateCoordinator from .entity import WLEDEntity from .helpers import wled_exception_handler @@ -24,7 +24,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up WLED update based on a config entry.""" - async_add_entities([WLEDUpdateEntity(entry.runtime_data)]) + async_add_entities([WLEDUpdateEntity(entry.runtime_data, hass.data[WLED_KEY])]) class WLEDUpdateEntity(WLEDEntity, UpdateEntity): @@ -36,11 +36,33 @@ class WLEDUpdateEntity(WLEDEntity, UpdateEntity): ) _attr_title = "WLED" - def __init__(self, coordinator: WLEDDataUpdateCoordinator) -> None: + def __init__( + self, + coordinator: WLEDDataUpdateCoordinator, + releases_coordinator: WLEDReleasesDataUpdateCoordinator, + ) -> None: """Initialize the update entity.""" super().__init__(coordinator=coordinator) + self.releases_coordinator = releases_coordinator self._attr_unique_id = coordinator.data.info.mac_address + async def async_added_to_hass(self) -> None: + """When entity is added to hass. + + Register extra update listener for the releases coordinator. + """ + await super().async_added_to_hass() + self.async_on_remove( + self.releases_coordinator.async_add_listener( + self._handle_coordinator_update + ) + ) + + @property + def available(self) -> bool: + """Return if entity is available.""" + return super().available and self.releases_coordinator.last_update_success + @property def installed_version(self) -> str | None: """Version currently installed and in use.""" @@ -54,17 +76,17 @@ class WLEDUpdateEntity(WLEDEntity, UpdateEntity): # If we already run a pre-release, we consider being on the beta channel. # Offer beta version upgrade, unless stable is newer if ( - (beta := self.coordinator.data.info.version_latest_beta) is not None + (beta := self.releases_coordinator.data.beta) is not None and (current := self.coordinator.data.info.version) is not None and (current.alpha or current.beta or current.release_candidate) and ( - (stable := self.coordinator.data.info.version_latest_stable) is None - or (stable is not None and stable < beta) + (stable := self.releases_coordinator.data.stable) is None + or (stable is not None and stable < beta and current > stable) ) ): return str(beta) - if (stable := self.coordinator.data.info.version_latest_stable) is not None: + if (stable := self.releases_coordinator.data.stable) is not None: return str(stable) return None diff --git a/requirements_all.txt b/requirements_all.txt index 00b421526c0..bfc9e8d92cb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2896,7 +2896,7 @@ wiffi==1.1.2 wirelesstagpy==0.8.1 # homeassistant.components.wled -wled==0.18.0 +wled==0.19.2 # homeassistant.components.wolflink wolf-comm==0.0.9 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9595d2c0c08..ab9463a787a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2270,7 +2270,7 @@ whois==0.9.27 wiffi==1.1.2 # homeassistant.components.wled -wled==0.18.0 +wled==0.19.2 # homeassistant.components.wolflink wolf-comm==0.0.9 diff --git a/tests/components/wled/conftest.py b/tests/components/wled/conftest.py index 2cf909ca664..301729843a2 100644 --- a/tests/components/wled/conftest.py +++ b/tests/components/wled/conftest.py @@ -5,7 +5,7 @@ from unittest.mock import AsyncMock, MagicMock, patch from freezegun.api import FrozenDateTimeFactory import pytest -from wled import Device as WLEDDevice +from wled import Device as WLEDDevice, Releases from homeassistant.components.wled.const import DOMAIN from homeassistant.const import CONF_HOST @@ -51,7 +51,24 @@ def device_fixture() -> str: @pytest.fixture -def mock_wled(device_fixture: str) -> Generator[MagicMock]: +def mock_wled_releases() -> Generator[MagicMock]: + """Return a mocked WLEDReleases client.""" + with patch( + "homeassistant.components.wled.coordinator.WLEDReleases", autospec=True + ) as wled_releases_mock: + wled_releases = wled_releases_mock.return_value + wled_releases.releases.return_value = Releases( + beta="1.0.0b5", + stable="0.99.0", + ) + + yield wled_releases + + +@pytest.fixture +def mock_wled( + device_fixture: str, mock_wled_releases: MagicMock +) -> Generator[MagicMock]: """Return a mocked WLED client.""" with ( patch( @@ -60,11 +77,12 @@ def mock_wled(device_fixture: str) -> Generator[MagicMock]: patch("homeassistant.components.wled.config_flow.WLED", new=wled_mock), ): wled = wled_mock.return_value - wled.update.return_value = WLEDDevice( + wled.update.return_value = WLEDDevice.from_dict( load_json_object_fixture(f"{device_fixture}.json", DOMAIN) ) wled.connected = False wled.host = "127.0.0.1" + yield wled diff --git a/tests/components/wled/fixtures/rgb.json b/tests/components/wled/fixtures/rgb.json index 21f9b005b72..50a82eb792e 100644 --- a/tests/components/wled/fixtures/rgb.json +++ b/tests/components/wled/fixtures/rgb.json @@ -1,28 +1,41 @@ { "state": { "on": true, - "bri": 127, + "bri": 128, "transition": 7, "ps": -1, "pl": -1, "nl": { "on": false, "dur": 60, - "fade": true, - "tbri": 0 + "mode": 1, + "tbri": 0, + "rem": -1 }, "udpn": { "send": false, - "recv": true + "recv": true, + "sgrp": 1, + "rgrp": 1 }, + "lor": 0, + "mainseg": 1, "seg": [ { "id": 0, "start": 0, - "stop": 19, - "len": 20, + "stop": 15, + "len": 15, + "grp": 1, + "spc": 0, + "of": 0, + "on": true, + "frz": false, + "bri": 255, + "cct": 127, + "set": 0, "col": [ - [255, 159, 0], + [127, 172, 255], [0, 0, 0], [0, 0, 0] ], @@ -30,62 +43,106 @@ "sx": 32, "ix": 128, "pal": 0, - "sel": true, + "c1": 128, + "c2": 128, + "c3": 16, + "sel": false, "rev": false, - "cln": -1 + "mi": false, + "o1": false, + "o2": false, + "o3": false, + "si": 0, + "m12": 0 }, { "id": 1, - "start": 20, + "start": 15, "stop": 30, - "len": 10, + "len": 15, + "grp": 1, + "spc": 0, + "of": 0, + "on": true, + "frz": false, + "bri": 255, + "cct": 127, + "set": 0, "col": [ - [0, 255, 123], + [255, 170, 0], [0, 0, 0], [0, 0, 0] ], - "fx": 1, + "fx": 3, "sx": 16, "ix": 64, "pal": 1, + "c1": 128, + "c2": 128, + "c3": 16, "sel": true, "rev": true, - "cln": -1 + "mi": false, + "o1": false, + "o2": false, + "o3": false, + "si": 0, + "m12": 0 } ] }, "info": { - "ver": "0.8.5", - "version_latest_stable": "0.12.0", - "version_latest_beta": "0.13.0b1", - "vid": 1909122, + "ver": "0.14.4", + "vid": 2405180, "leds": { "count": 30, - "rgbw": false, - "pin": [2], - "pwr": 470, + "pwr": 515, + "fps": 5, "maxpwr": 850, - "maxseg": 10 + "maxseg": 32, + "seglc": [1, 1], + "lc": 1, + "rgbw": false, + "wv": 0, + "cct": 0 }, + "str": false, "name": "WLED RGB Light", "udpport": 21324, "live": false, - "fxcount": 81, - "palcount": 50, + "liveseg": -1, + "lm": "", + "lip": "", + "ws": -1, + "fxcount": 187, + "palcount": 71, + "cpalcount": 0, + "maps": [ + { + "id": 0 + } + ], "wifi": { "bssid": "AA:AA:AA:AA:AA:BB", - "rssi": -62, - "signal": 76, + "rssi": -43, + "signal": 100, "channel": 11 }, - "arch": "esp8266", - "core": "2_4_2", - "freeheap": 14600, - "uptime": 32, - "opt": 119, + "fs": { + "u": 12, + "t": 983, + "pmt": 1718827787 + }, + "ndc": 1, + "arch": "esp32", + "core": "v3.3.6-16-gcc5440f6a2", + "lwip": 0, + "freeheap": 198384, + "uptime": 966, + "time": "2024-6-19, 20:10:38", + "opt": 79, "brand": "WLED", - "product": "DIY light", - "btype": "bin", + "product": "FOSS", "mac": "aabbccddeeff", "ip": "127.0.0.1" }, @@ -101,21 +158,21 @@ "Colorloop", "Rainbow", "Scan", - "Dual Scan", + "Scan Dual", "Fade", - "Chase", - "Chase Rainbow", + "Theater", + "Theater Rainbow", "Running", "Saw", "Twinkle", "Dissolve", "Dissolve Rnd", "Sparkle", - "Dark Sparkle", + "Sparkle Dark", "Sparkle+", "Strobe", "Strobe Rainbow", - "Mega Strobe", + "Strobe Mega", "Blink Rainbow", "Android", "Chase", @@ -127,30 +184,30 @@ "Colorful", "Traffic Light", "Sweep Random", - "Running 2", - "Red & Blue", + "Chase 2", + "Aurora", "Stream", "Scanner", "Lighthouse", "Fireworks", "Rain", - "Merry Christmas", + "Tetrix", "Fire Flicker", "Gradient", "Loading", - "In Out", - "In In", - "Out Out", - "Out In", - "Circus", - "Halloween", - "Tri Chase", + "Rolling Balls", + "Fairy", + "Two Dots", + "Fairytwinkle", + "Running Dual", + "RSVD", + "Chase 3", "Tri Wipe", "Tri Fade", "Lightning", "ICU", "Multi Comet", - "Dual Scanner", + "Scanner Dual", "Stream 2", "Oscillate", "Pride 2015", @@ -158,27 +215,133 @@ "Palette", "Fire 2012", "Colorwaves", - "BPM", + "Bpm", "Fill Noise", "Noise 1", "Noise 2", "Noise 3", "Noise 4", - "Colortwinkle", + "Colortwinkles", "Lake", "Meteor", - "Smooth Meteor", + "Meteor Smooth", "Railway", "Ripple", - "Twinklefox" + "Twinklefox", + "Twinklecat", + "Halloween Eyes", + "Solid Pattern", + "Solid Pattern Tri", + "Spots", + "Spots Fade", + "Glitter", + "Candle", + "Fireworks Starburst", + "Fireworks 1D", + "Bouncing Balls", + "Sinelon", + "Sinelon Dual", + "Sinelon Rainbow", + "Popcorn", + "Drip", + "Plasma", + "Percent", + "Ripple Rainbow", + "Heartbeat", + "Pacifica", + "Candle Multi", + "Solid Glitter", + "Sunrise", + "Phased", + "Twinkleup", + "Noise Pal", + "Sine", + "Phased Noise", + "Flow", + "Chunchun", + "Dancing Shadows", + "Washing Machine", + "RSVD", + "Blends", + "TV Simulator", + "Dynamic Smooth", + "Spaceships", + "Crazy Bees", + "Ghost Rider", + "Blobs", + "Scrolling Text", + "Drift Rose", + "Distortion Waves", + "Soap", + "Octopus", + "Waving Cell", + "Pixels", + "Pixelwave", + "Juggles", + "Matripix", + "Gravimeter", + "Plasmoid", + "Puddles", + "Midnoise", + "Noisemeter", + "Freqwave", + "Freqmatrix", + "GEQ", + "Waterfall", + "Freqpixels", + "RSVD", + "Noisefire", + "Puddlepeak", + "Noisemove", + "Noise2D", + "Perlin Move", + "Ripple Peak", + "Firenoise", + "Squared Swirl", + "RSVD", + "DNA", + "Matrix", + "Metaballs", + "Freqmap", + "Gravcenter", + "Gravcentric", + "Gravfreq", + "DJ Light", + "Funky Plank", + "RSVD", + "Pulser", + "Blurz", + "Drift", + "Waverly", + "Sun Radiation", + "Colored Bursts", + "Julia", + "RSVD", + "RSVD", + "RSVD", + "Game Of Life", + "Tartan", + "Polar Lights", + "Swirl", + "Lissajous", + "Frizzles", + "Plasma Ball", + "Flow Stripe", + "Hiphotic", + "Sindots", + "DNA Spiral", + "Black Hole", + "Wavesins", + "Rocktaves", + "Akemi" ], "palettes": [ "Default", - "Random Cycle", - "Primary Color", - "Based on Primary", - "Set Colors", - "Based on Set", + "* Random Cycle", + "* Color 1", + "* Colors 1&2", + "* Color Gradient", + "* Colors Only", "Party", "Cloud", "Lava", @@ -195,11 +358,11 @@ "Splash", "Pastel", "Sunset 2", - "Beech", + "Beach", "Vintage", "Departure", "Landscape", - "Beach", + "Beech", "Sherbet", "Hult", "Hult 64", @@ -222,6 +385,27 @@ "April Night", "Orangery", "C9", - "Sakura" + "Sakura", + "Aurora", + "Atlantica", + "C9 2", + "C9 New", + "Temperature", + "Aurora 2", + "Retro Clown", + "Candy", + "Toxy Reaf", + "Fairy Reaf", + "Semi Blue", + "Pink Candy", + "Red Reaf", + "Aqua Flash", + "Yelblu Hot", + "Lite Light", + "Red Flash", + "Blink Red", + "Red Shift", + "Red Tide", + "Candy2" ] } diff --git a/tests/components/wled/fixtures/rgb_no_update.json b/tests/components/wled/fixtures/rgb_no_update.json deleted file mode 100644 index c8aa902cc95..00000000000 --- a/tests/components/wled/fixtures/rgb_no_update.json +++ /dev/null @@ -1,227 +0,0 @@ -{ - "state": { - "on": true, - "bri": 127, - "transition": 7, - "ps": -1, - "pl": -1, - "nl": { - "on": false, - "dur": 60, - "fade": true, - "tbri": 0 - }, - "udpn": { - "send": false, - "recv": true - }, - "seg": [ - { - "id": 0, - "start": 0, - "stop": 19, - "len": 20, - "col": [ - [255, 159, 0], - [0, 0, 0], - [0, 0, 0] - ], - "fx": 0, - "sx": 32, - "ix": 128, - "pal": 0, - "sel": true, - "rev": false, - "cln": -1 - }, - { - "id": 1, - "start": 20, - "stop": 30, - "len": 10, - "col": [ - [0, 255, 123], - [0, 0, 0], - [0, 0, 0] - ], - "fx": 1, - "sx": 16, - "ix": 64, - "pal": 1, - "sel": true, - "rev": true, - "cln": -1 - } - ] - }, - "info": { - "ver": null, - "version_latest_stable": null, - "version_latest_beta": null, - "vid": 1909122, - "leds": { - "count": 30, - "rgbw": false, - "pin": [2], - "pwr": 470, - "maxpwr": 850, - "maxseg": 10 - }, - "name": "WLED RGB Light", - "udpport": 21324, - "live": false, - "fxcount": 81, - "palcount": 50, - "wifi": { - "bssid": "AA:AA:AA:AA:AA:BB", - "rssi": -62, - "signal": 76, - "channel": 11 - }, - "arch": "esp8266", - "core": "2_4_2", - "freeheap": 14600, - "uptime": 32, - "opt": 119, - "brand": "WLED", - "product": "DIY light", - "btype": "bin", - "mac": "aabbccddeeff", - "ip": "127.0.0.1" - }, - "effects": [ - "Solid", - "Blink", - "Breathe", - "Wipe", - "Wipe Random", - "Random Colors", - "Sweep", - "Dynamic", - "Colorloop", - "Rainbow", - "Scan", - "Dual Scan", - "Fade", - "Chase", - "Chase Rainbow", - "Running", - "Saw", - "Twinkle", - "Dissolve", - "Dissolve Rnd", - "Sparkle", - "Dark Sparkle", - "Sparkle+", - "Strobe", - "Strobe Rainbow", - "Mega Strobe", - "Blink Rainbow", - "Android", - "Chase", - "Chase Random", - "Chase Rainbow", - "Chase Flash", - "Chase Flash Rnd", - "Rainbow Runner", - "Colorful", - "Traffic Light", - "Sweep Random", - "Running 2", - "Red & Blue", - "Stream", - "Scanner", - "Lighthouse", - "Fireworks", - "Rain", - "Merry Christmas", - "Fire Flicker", - "Gradient", - "Loading", - "In Out", - "In In", - "Out Out", - "Out In", - "Circus", - "Halloween", - "Tri Chase", - "Tri Wipe", - "Tri Fade", - "Lightning", - "ICU", - "Multi Comet", - "Dual Scanner", - "Stream 2", - "Oscillate", - "Pride 2015", - "Juggle", - "Palette", - "Fire 2012", - "Colorwaves", - "BPM", - "Fill Noise", - "Noise 1", - "Noise 2", - "Noise 3", - "Noise 4", - "Colortwinkle", - "Lake", - "Meteor", - "Smooth Meteor", - "Railway", - "Ripple", - "Twinklefox" - ], - "palettes": [ - "Default", - "Random Cycle", - "Primary Color", - "Based on Primary", - "Set Colors", - "Based on Set", - "Party", - "Cloud", - "Lava", - "Ocean", - "Forest", - "Rainbow", - "Rainbow Bands", - "Sunset", - "Rivendell", - "Breeze", - "Red & Blue", - "Yellowout", - "Analogous", - "Splash", - "Pastel", - "Sunset 2", - "Beech", - "Vintage", - "Departure", - "Landscape", - "Beach", - "Sherbet", - "Hult", - "Hult 64", - "Drywet", - "Jul", - "Grintage", - "Rewhi", - "Tertiary", - "Fire", - "Icefire", - "Cyane", - "Light Pink", - "Autumn", - "Magenta", - "Magred", - "Yelmag", - "Yelblu", - "Orange & Teal", - "Tiamat", - "April Night", - "Orangery", - "C9", - "Sakura" - ] -} diff --git a/tests/components/wled/fixtures/rgb_single_segment.json b/tests/components/wled/fixtures/rgb_single_segment.json index aa0b79e98f5..512ac2a00df 100644 --- a/tests/components/wled/fixtures/rgb_single_segment.json +++ b/tests/components/wled/fixtures/rgb_single_segment.json @@ -1,28 +1,41 @@ { "state": { "on": true, - "bri": 127, + "bri": 128, "transition": 7, "ps": -1, "pl": -1, "nl": { "on": false, "dur": 60, - "fade": true, - "tbri": 0 + "mode": 1, + "tbri": 0, + "rem": -1 }, "udpn": { "send": false, - "recv": true + "recv": true, + "sgrp": 1, + "rgrp": 1 }, + "lor": 0, + "mainseg": 0, "seg": [ { "id": 0, "start": 0, "stop": 30, - "len": 20, + "len": 30, + "grp": 1, + "spc": 0, + "of": 0, + "on": true, + "frz": false, + "bri": 255, + "cct": 127, + "set": 0, "col": [ - [255, 159, 0], + [127, 172, 255], [0, 0, 0], [0, 0, 0] ], @@ -30,44 +43,72 @@ "sx": 32, "ix": 128, "pal": 0, + "c1": 128, + "c2": 128, + "c3": 16, "sel": true, "rev": false, - "cln": -1 + "mi": false, + "o1": false, + "o2": false, + "o3": false, + "si": 0, + "m12": 0 } ] }, "info": { - "ver": "0.8.6b1", - "version_latest_stable": "0.8.5", - "version_latest_beta": "0.8.6b2", - "vid": 1909122, + "ver": "1.0.0b4", + "vid": 2405180, "leds": { "count": 30, - "rgbw": false, - "pin": [2], - "pwr": 470, + "pwr": 536, + "fps": 5, "maxpwr": 850, - "maxseg": 10 + "maxseg": 32, + "seglc": [1], + "lc": 1, + "rgbw": false, + "wv": 0, + "cct": 0 }, + "str": false, "name": "WLED RGB Light", "udpport": 21324, "live": false, - "fxcount": 81, - "palcount": 50, + "liveseg": -1, + "lm": "", + "lip": "", + "ws": -1, + "fxcount": 187, + "palcount": 71, + "cpalcount": 0, + "maps": [ + { + "id": 0 + } + ], "wifi": { "bssid": "AA:AA:AA:AA:AA:BB", - "rssi": -62, - "signal": 76, + "rssi": -44, + "signal": 100, "channel": 11 }, - "arch": "esp8266", - "core": "2_4_2", - "freeheap": 14600, - "uptime": 32, - "opt": 119, + "fs": { + "u": 12, + "t": 983, + "pmt": 0 + }, + "ndc": 1, + "arch": "esp32", + "core": "v3.3.6-16-gcc5440f6a2", + "lwip": 0, + "freeheap": 196960, + "uptime": 461, + "time": "1970-1-1, 00:07:41", + "opt": 79, "brand": "WLED", - "product": "DIY light", - "btype": "bin", + "product": "FOSS", "mac": "aabbccddeeff", "ip": "127.0.0.1" }, @@ -83,21 +124,21 @@ "Colorloop", "Rainbow", "Scan", - "Dual Scan", + "Scan Dual", "Fade", - "Chase", - "Chase Rainbow", + "Theater", + "Theater Rainbow", "Running", "Saw", "Twinkle", "Dissolve", "Dissolve Rnd", "Sparkle", - "Dark Sparkle", + "Sparkle Dark", "Sparkle+", "Strobe", "Strobe Rainbow", - "Mega Strobe", + "Strobe Mega", "Blink Rainbow", "Android", "Chase", @@ -109,30 +150,30 @@ "Colorful", "Traffic Light", "Sweep Random", - "Running 2", - "Red & Blue", + "Chase 2", + "Aurora", "Stream", "Scanner", "Lighthouse", "Fireworks", "Rain", - "Merry Christmas", + "Tetrix", "Fire Flicker", "Gradient", "Loading", - "In Out", - "In In", - "Out Out", - "Out In", - "Circus", - "Halloween", - "Tri Chase", + "Rolling Balls", + "Fairy", + "Two Dots", + "Fairytwinkle", + "Running Dual", + "RSVD", + "Chase 3", "Tri Wipe", "Tri Fade", "Lightning", "ICU", "Multi Comet", - "Dual Scanner", + "Scanner Dual", "Stream 2", "Oscillate", "Pride 2015", @@ -140,27 +181,133 @@ "Palette", "Fire 2012", "Colorwaves", - "BPM", + "Bpm", "Fill Noise", "Noise 1", "Noise 2", "Noise 3", "Noise 4", - "Colortwinkle", + "Colortwinkles", "Lake", "Meteor", - "Smooth Meteor", + "Meteor Smooth", "Railway", "Ripple", - "Twinklefox" + "Twinklefox", + "Twinklecat", + "Halloween Eyes", + "Solid Pattern", + "Solid Pattern Tri", + "Spots", + "Spots Fade", + "Glitter", + "Candle", + "Fireworks Starburst", + "Fireworks 1D", + "Bouncing Balls", + "Sinelon", + "Sinelon Dual", + "Sinelon Rainbow", + "Popcorn", + "Drip", + "Plasma", + "Percent", + "Ripple Rainbow", + "Heartbeat", + "Pacifica", + "Candle Multi", + "Solid Glitter", + "Sunrise", + "Phased", + "Twinkleup", + "Noise Pal", + "Sine", + "Phased Noise", + "Flow", + "Chunchun", + "Dancing Shadows", + "Washing Machine", + "RSVD", + "Blends", + "TV Simulator", + "Dynamic Smooth", + "Spaceships", + "Crazy Bees", + "Ghost Rider", + "Blobs", + "Scrolling Text", + "Drift Rose", + "Distortion Waves", + "Soap", + "Octopus", + "Waving Cell", + "Pixels", + "Pixelwave", + "Juggles", + "Matripix", + "Gravimeter", + "Plasmoid", + "Puddles", + "Midnoise", + "Noisemeter", + "Freqwave", + "Freqmatrix", + "GEQ", + "Waterfall", + "Freqpixels", + "RSVD", + "Noisefire", + "Puddlepeak", + "Noisemove", + "Noise2D", + "Perlin Move", + "Ripple Peak", + "Firenoise", + "Squared Swirl", + "RSVD", + "DNA", + "Matrix", + "Metaballs", + "Freqmap", + "Gravcenter", + "Gravcentric", + "Gravfreq", + "DJ Light", + "Funky Plank", + "RSVD", + "Pulser", + "Blurz", + "Drift", + "Waverly", + "Sun Radiation", + "Colored Bursts", + "Julia", + "RSVD", + "RSVD", + "RSVD", + "Game Of Life", + "Tartan", + "Polar Lights", + "Swirl", + "Lissajous", + "Frizzles", + "Plasma Ball", + "Flow Stripe", + "Hiphotic", + "Sindots", + "DNA Spiral", + "Black Hole", + "Wavesins", + "Rocktaves", + "Akemi" ], "palettes": [ "Default", - "Random Cycle", - "Primary Color", - "Based on Primary", - "Set Colors", - "Based on Set", + "* Random Cycle", + "* Color 1", + "* Colors 1&2", + "* Color Gradient", + "* Colors Only", "Party", "Cloud", "Lava", @@ -177,11 +324,11 @@ "Splash", "Pastel", "Sunset 2", - "Beech", + "Beach", "Vintage", "Departure", "Landscape", - "Beach", + "Beech", "Sherbet", "Hult", "Hult 64", @@ -204,6 +351,27 @@ "April Night", "Orangery", "C9", - "Sakura" + "Sakura", + "Aurora", + "Atlantica", + "C9 2", + "C9 New", + "Temperature", + "Aurora 2", + "Retro Clown", + "Candy", + "Toxy Reaf", + "Fairy Reaf", + "Semi Blue", + "Pink Candy", + "Red Reaf", + "Aqua Flash", + "Yelblu Hot", + "Lite Light", + "Red Flash", + "Blink Red", + "Red Shift", + "Red Tide", + "Candy2" ] } diff --git a/tests/components/wled/fixtures/rgb_websocket.json b/tests/components/wled/fixtures/rgb_websocket.json index 4a0ed7b1ee5..f5a3e715654 100644 --- a/tests/components/wled/fixtures/rgb_websocket.json +++ b/tests/components/wled/fixtures/rgb_websocket.json @@ -1,26 +1,22 @@ { "state": { "on": true, - "bri": 255, + "bri": 128, "transition": 7, "ps": -1, "pl": -1, - "ccnf": { - "min": 1, - "max": 5, - "time": 12 - }, "nl": { "on": false, "dur": 60, - "fade": true, "mode": 1, "tbri": 0, "rem": -1 }, "udpn": { "send": false, - "recv": true + "recv": true, + "sgrp": 1, + "rgrp": 1 }, "lor": 0, "mainseg": 0, @@ -28,70 +24,89 @@ { "id": 0, "start": 0, - "stop": 13, - "len": 13, + "stop": 30, + "len": 30, "grp": 1, "spc": 0, + "of": 0, "on": true, + "frz": false, "bri": 255, + "cct": 127, + "set": 0, "col": [ - [255, 181, 218], + [127, 172, 255], [0, 0, 0], [0, 0, 0] ], "fx": 0, - "sx": 43, + "sx": 128, "ix": 128, - "pal": 2, + "pal": 0, + "c1": 128, + "c2": 128, + "c3": 16, "sel": true, "rev": false, - "mi": false + "mi": false, + "o1": false, + "o2": false, + "o3": false, + "si": 0, + "m12": 0 } ] }, "info": { - "ver": "0.12.0-b2", - "version_latest_stable": "0.11.0", - "version_latest_beta": "0.12.0-b2", - "vid": 2103220, + "ver": "0.99.0", + "vid": 2405180, "leds": { - "count": 13, + "count": 30, + "pwr": 536, + "fps": 5, + "maxpwr": 850, + "maxseg": 32, + "seglc": [1], + "lc": 1, "rgbw": false, - "wv": false, - "pin": [2], - "pwr": 266, - "fps": 2, - "maxpwr": 1000, - "maxseg": 12, - "seglock": false + "wv": 0, + "cct": 0 }, "str": false, "name": "WLED WebSocket", "udpport": 21324, "live": false, + "liveseg": -1, "lm": "", "lip": "", "ws": 0, - "fxcount": 118, - "palcount": 56, + "fxcount": 187, + "palcount": 71, + "cpalcount": 0, + "maps": [ + { + "id": 0 + } + ], "wifi": { "bssid": "AA:AA:AA:AA:AA:BB", - "rssi": -68, - "signal": 64, - "channel": 6 + "rssi": -44, + "signal": 100, + "channel": 11 }, "fs": { - "u": 40, - "t": 1024, - "pmt": 1623156685 + "u": 12, + "t": 983, + "pmt": 0 }, "ndc": 1, - "arch": "esp8266", - "core": "2_7_4_7", - "lwip": 1, - "freeheap": 22752, - "uptime": 258411, - "opt": 127, + "arch": "esp32", + "core": "v3.3.6-16-gcc5440f6a2", + "lwip": 0, + "freeheap": 196960, + "uptime": 461, + "time": "1970-1-1, 00:07:41", + "opt": 79, "brand": "WLED", "product": "FOSS", "mac": "aabbccddeeff", @@ -135,7 +150,7 @@ "Colorful", "Traffic Light", "Sweep Random", - "Running 2", + "Chase 2", "Aurora", "Stream", "Scanner", @@ -146,13 +161,13 @@ "Fire Flicker", "Gradient", "Loading", - "Police", - "Police All", + "Rolling Balls", + "Fairy", "Two Dots", - "Two Areas", - "Circus", - "Halloween", - "Tri Chase", + "Fairytwinkle", + "Running Dual", + "RSVD", + "Chase 3", "Tri Wipe", "Tri Fade", "Lightning", @@ -212,10 +227,79 @@ "Chunchun", "Dancing Shadows", "Washing Machine", - "Candy Cane", + "RSVD", "Blends", "TV Simulator", - "Dynamic Smooth" + "Dynamic Smooth", + "Spaceships", + "Crazy Bees", + "Ghost Rider", + "Blobs", + "Scrolling Text", + "Drift Rose", + "Distortion Waves", + "Soap", + "Octopus", + "Waving Cell", + "Pixels", + "Pixelwave", + "Juggles", + "Matripix", + "Gravimeter", + "Plasmoid", + "Puddles", + "Midnoise", + "Noisemeter", + "Freqwave", + "Freqmatrix", + "GEQ", + "Waterfall", + "Freqpixels", + "RSVD", + "Noisefire", + "Puddlepeak", + "Noisemove", + "Noise2D", + "Perlin Move", + "Ripple Peak", + "Firenoise", + "Squared Swirl", + "RSVD", + "DNA", + "Matrix", + "Metaballs", + "Freqmap", + "Gravcenter", + "Gravcentric", + "Gravfreq", + "DJ Light", + "Funky Plank", + "RSVD", + "Pulser", + "Blurz", + "Drift", + "Waverly", + "Sun Radiation", + "Colored Bursts", + "Julia", + "RSVD", + "RSVD", + "RSVD", + "Game Of Life", + "Tartan", + "Polar Lights", + "Swirl", + "Lissajous", + "Frizzles", + "Plasma Ball", + "Flow Stripe", + "Hiphotic", + "Sindots", + "DNA Spiral", + "Black Hole", + "Wavesins", + "Rocktaves", + "Akemi" ], "palettes": [ "Default", @@ -240,11 +324,11 @@ "Splash", "Pastel", "Sunset 2", - "Beech", + "Beach", "Vintage", "Departure", "Landscape", - "Beach", + "Beech", "Sherbet", "Hult", "Hult 64", @@ -273,6 +357,21 @@ "C9 2", "C9 New", "Temperature", - "Aurora 2" + "Aurora 2", + "Retro Clown", + "Candy", + "Toxy Reaf", + "Fairy Reaf", + "Semi Blue", + "Pink Candy", + "Red Reaf", + "Aqua Flash", + "Yelblu Hot", + "Lite Light", + "Red Flash", + "Blink Red", + "Red Shift", + "Red Tide", + "Candy2" ] } diff --git a/tests/components/wled/fixtures/rgbw.json b/tests/components/wled/fixtures/rgbw.json index 100b3936900..285842605ae 100644 --- a/tests/components/wled/fixtures/rgbw.json +++ b/tests/components/wled/fixtures/rgbw.json @@ -1,74 +1,115 @@ { "state": { "on": true, - "bri": 140, + "bri": 128, "transition": 7, - "ps": 1, - "pl": 3, + "ps": -1, + "pl": -1, "nl": { "on": false, "dur": 60, - "fade": true, - "tbri": 0 + "mode": 1, + "tbri": 0, + "rem": -1 }, "udpn": { "send": false, - "recv": true + "recv": true, + "sgrp": 1, + "rgrp": 1 }, + "lor": 0, + "mainseg": 0, "seg": [ { "id": 0, "start": 0, - "stop": 13, - "len": 13, + "stop": 30, + "len": 30, + "grp": 1, + "spc": 0, + "of": 0, + "on": true, + "frz": false, + "bri": 255, + "cct": 127, + "set": 0, "col": [ [255, 0, 0, 139], [0, 0, 0, 0], [0, 0, 0, 0] ], - "fx": 9, - "sx": 165, + "fx": 0, + "sx": 128, "ix": 128, "pal": 0, + "c1": 128, + "c2": 128, + "c3": 16, "sel": true, "rev": false, - "cln": -1 + "mi": false, + "o1": false, + "o2": false, + "o3": false, + "si": 0, + "m12": 0 } ] }, "info": { - "ver": "0.8.6b4", - "version_latest_stable": "0.8.6", - "version_latest_beta": "0.8.6b5", - "vid": 1910255, + "ver": "0.99.0b1", + "vid": 2405180, "leds": { - "count": 13, - "rgbw": true, - "pin": [2], - "pwr": 208, + "count": 30, + "pwr": 536, + "fps": 5, "maxpwr": 850, - "maxseg": 10 + "maxseg": 32, + "seglc": [3], + "lc": 3, + "rgbw": true, + "wv": 0, + "cct": 0 }, + "str": false, "name": "WLED RGBW Light", "udpport": 21324, "live": false, - "fxcount": 83, - "palcount": 50, + "liveseg": -1, + "lm": "", + "lip": "", + "ws": -1, + "fxcount": 187, + "palcount": 71, + "cpalcount": 0, + "maps": [ + { + "id": 0 + } + ], "wifi": { "bssid": "AA:AA:AA:AA:AA:BB", - "rssi": -62, - "signal": 76, + "rssi": -44, + "signal": 100, "channel": 11 }, - "arch": "esp8266", - "core": "2_5_2", - "freeheap": 20136, - "uptime": 5591, - "opt": 119, + "fs": { + "u": 12, + "t": 983, + "pmt": 0 + }, + "ndc": 1, + "arch": "esp32", + "core": "v3.3.6-16-gcc5440f6a2", + "lwip": 0, + "freeheap": 196960, + "uptime": 461, + "time": "1970-1-1, 00:07:41", + "opt": 79, "brand": "WLED", - "product": "DIY light", - "btype": "bin", - "mac": "aabbccddee11", + "product": "FOSS", + "mac": "aabbccddeeff", "ip": "127.0.0.1" }, "effects": [ @@ -83,21 +124,21 @@ "Colorloop", "Rainbow", "Scan", - "Dual Scan", + "Scan Dual", "Fade", - "Chase", - "Chase Rainbow", + "Theater", + "Theater Rainbow", "Running", "Saw", "Twinkle", "Dissolve", "Dissolve Rnd", "Sparkle", - "Dark Sparkle", + "Sparkle Dark", "Sparkle+", "Strobe", "Strobe Rainbow", - "Mega Strobe", + "Strobe Mega", "Blink Rainbow", "Android", "Chase", @@ -109,30 +150,30 @@ "Colorful", "Traffic Light", "Sweep Random", - "Running 2", - "Red & Blue", + "Chase 2", + "Aurora", "Stream", "Scanner", "Lighthouse", "Fireworks", "Rain", - "Merry Christmas", + "Tetrix", "Fire Flicker", "Gradient", "Loading", - "In Out", - "In In", - "Out Out", - "Out In", - "Circus", - "Halloween", - "Tri Chase", + "Rolling Balls", + "Fairy", + "Two Dots", + "Fairytwinkle", + "Running Dual", + "RSVD", + "Chase 3", "Tri Wipe", "Tri Fade", "Lightning", "ICU", "Multi Comet", - "Dual Scanner", + "Scanner Dual", "Stream 2", "Oscillate", "Pride 2015", @@ -140,7 +181,7 @@ "Palette", "Fire 2012", "Colorwaves", - "BPM", + "Bpm", "Fill Noise", "Noise 1", "Noise 2", @@ -149,20 +190,124 @@ "Colortwinkles", "Lake", "Meteor", - "Smooth Meteor", + "Meteor Smooth", "Railway", "Ripple", "Twinklefox", "Twinklecat", - "Halloween Eyes" + "Halloween Eyes", + "Solid Pattern", + "Solid Pattern Tri", + "Spots", + "Spots Fade", + "Glitter", + "Candle", + "Fireworks Starburst", + "Fireworks 1D", + "Bouncing Balls", + "Sinelon", + "Sinelon Dual", + "Sinelon Rainbow", + "Popcorn", + "Drip", + "Plasma", + "Percent", + "Ripple Rainbow", + "Heartbeat", + "Pacifica", + "Candle Multi", + "Solid Glitter", + "Sunrise", + "Phased", + "Twinkleup", + "Noise Pal", + "Sine", + "Phased Noise", + "Flow", + "Chunchun", + "Dancing Shadows", + "Washing Machine", + "RSVD", + "Blends", + "TV Simulator", + "Dynamic Smooth", + "Spaceships", + "Crazy Bees", + "Ghost Rider", + "Blobs", + "Scrolling Text", + "Drift Rose", + "Distortion Waves", + "Soap", + "Octopus", + "Waving Cell", + "Pixels", + "Pixelwave", + "Juggles", + "Matripix", + "Gravimeter", + "Plasmoid", + "Puddles", + "Midnoise", + "Noisemeter", + "Freqwave", + "Freqmatrix", + "GEQ", + "Waterfall", + "Freqpixels", + "RSVD", + "Noisefire", + "Puddlepeak", + "Noisemove", + "Noise2D", + "Perlin Move", + "Ripple Peak", + "Firenoise", + "Squared Swirl", + "RSVD", + "DNA", + "Matrix", + "Metaballs", + "Freqmap", + "Gravcenter", + "Gravcentric", + "Gravfreq", + "DJ Light", + "Funky Plank", + "RSVD", + "Pulser", + "Blurz", + "Drift", + "Waverly", + "Sun Radiation", + "Colored Bursts", + "Julia", + "RSVD", + "RSVD", + "RSVD", + "Game Of Life", + "Tartan", + "Polar Lights", + "Swirl", + "Lissajous", + "Frizzles", + "Plasma Ball", + "Flow Stripe", + "Hiphotic", + "Sindots", + "DNA Spiral", + "Black Hole", + "Wavesins", + "Rocktaves", + "Akemi" ], "palettes": [ "Default", - "Random Cycle", - "Primary Color", - "Based on Primary", - "Set Colors", - "Based on Set", + "* Random Cycle", + "* Color 1", + "* Colors 1&2", + "* Color Gradient", + "* Colors Only", "Party", "Cloud", "Lava", @@ -179,11 +324,11 @@ "Splash", "Pastel", "Sunset 2", - "Beech", + "Beach", "Vintage", "Departure", "Landscape", - "Beach", + "Beech", "Sherbet", "Hult", "Hult 64", @@ -206,36 +351,82 @@ "April Night", "Orangery", "C9", - "Sakura" + "Sakura", + "Aurora", + "Atlantica", + "C9 2", + "C9 New", + "Temperature", + "Aurora 2", + "Retro Clown", + "Candy", + "Toxy Reaf", + "Fairy Reaf", + "Semi Blue", + "Pink Candy", + "Red Reaf", + "Aqua Flash", + "Yelblu Hot", + "Lite Light", + "Red Flash", + "Blink Red", + "Red Shift", + "Red Tide", + "Candy2" ], "presets": { "0": {}, "1": { - "on": false, - "bri": 255, + "on": true, + "bri": 128, "transition": 7, "mainseg": 0, "seg": [ { "id": 0, "start": 0, - "stop": 13, + "stop": 131, "grp": 1, "spc": 0, + "of": 0, "on": true, + "frz": false, "bri": 255, + "cct": 127, + "set": 0, + "n": "", "col": [ - [97, 144, 255], + [40, 255, 3], [0, 0, 0], [0, 0, 0] ], - "fx": 9, - "sx": 183, - "ix": 255, - "pal": 1, + "fx": 0, + "sx": 128, + "ix": 128, + "pal": 0, + "c1": 128, + "c2": 128, + "c3": 16, "sel": true, "rev": false, - "mi": false + "mi": false, + "o1": false, + "o2": false, + "o3": false, + "si": 0, + "m12": 0 + }, + { + "stop": 0 + }, + { + "stop": 0 + }, + { + "stop": 0 + }, + { + "stop": 0 }, { "stop": 0 @@ -274,31 +465,56 @@ "n": "Preset 1" }, "2": { - "on": false, - "bri": 255, + "on": true, + "bri": 128, "transition": 7, "mainseg": 0, "seg": [ { "id": 0, "start": 0, - "stop": 13, + "stop": 131, "grp": 1, "spc": 0, + "of": 0, "on": true, + "frz": false, "bri": 255, + "cct": 127, + "set": 0, + "n": "", "col": [ - [97, 144, 255], + [51, 88, 255], [0, 0, 0], [0, 0, 0] ], - "fx": 9, - "sx": 183, - "ix": 255, - "pal": 1, + "fx": 0, + "sx": 128, + "ix": 128, + "pal": 0, + "c1": 128, + "c2": 128, + "c3": 16, "sel": true, "rev": false, - "mi": false + "mi": false, + "o1": false, + "o2": false, + "o3": false, + "si": 0, + "m12": 0 + }, + { + "stop": 0 + }, + { + "stop": 0 + }, + { + "stop": 0 + }, + { + "stop": 0 }, { "stop": 0 @@ -339,23 +555,25 @@ "3": { "playlist": { "ps": [1, 2], - "dur": [30, 30], + "dur": [300, 300], "transition": [7, 7], "repeat": 0, - "r": false, - "end": 0 + "end": 0, + "r": 0 }, + "on": true, "n": "Playlist 1" }, "4": { "playlist": { - "ps": [1, 2], - "dur": [30, 30], + "ps": [2, 0], + "dur": [300, 300], "transition": [7, 7], "repeat": 0, - "r": false, - "end": 0 + "end": 0, + "r": 0 }, + "on": true, "n": "Playlist 2" } } diff --git a/tests/components/wled/snapshots/test_button.ambr b/tests/components/wled/snapshots/test_button.ambr index 954350b0fb0..4e6260bc9bd 100644 --- a/tests/components/wled/snapshots/test_button.ambr +++ b/tests/components/wled/snapshots/test_button.ambr @@ -59,7 +59,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -71,14 +71,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- diff --git a/tests/components/wled/snapshots/test_diagnostics.ambr b/tests/components/wled/snapshots/test_diagnostics.ambr index 643e5fe4ad0..fea53e8ac03 100644 --- a/tests/components/wled/snapshots/test_diagnostics.ambr +++ b/tests/components/wled/snapshots/test_diagnostics.ambr @@ -5,22 +5,109 @@ '0': 'Solid', '1': 'Blink', '10': 'Scan', - '11': 'Dual Scan', + '100': 'Heartbeat', + '101': 'Pacifica', + '102': 'Candle Multi', + '103': 'Solid Glitter', + '104': 'Sunrise', + '105': 'Phased', + '106': 'Twinkleup', + '107': 'Noise Pal', + '108': 'Sine', + '109': 'Phased Noise', + '11': 'Scan Dual', + '110': 'Flow', + '111': 'Chunchun', + '112': 'Dancing Shadows', + '113': 'Washing Machine', + '114': 'RSVD', + '115': 'Blends', + '116': 'TV Simulator', + '117': 'Dynamic Smooth', + '118': 'Spaceships', + '119': 'Crazy Bees', '12': 'Fade', - '13': 'Chase', - '14': 'Chase Rainbow', + '120': 'Ghost Rider', + '121': 'Blobs', + '122': 'Scrolling Text', + '123': 'Drift Rose', + '124': 'Distortion Waves', + '125': 'Soap', + '126': 'Octopus', + '127': 'Waving Cell', + '128': 'Pixels', + '129': 'Pixelwave', + '13': 'Theater', + '130': 'Juggles', + '131': 'Matripix', + '132': 'Gravimeter', + '133': 'Plasmoid', + '134': 'Puddles', + '135': 'Midnoise', + '136': 'Noisemeter', + '137': 'Freqwave', + '138': 'Freqmatrix', + '139': 'GEQ', + '14': 'Theater Rainbow', + '140': 'Waterfall', + '141': 'Freqpixels', + '142': 'RSVD', + '143': 'Noisefire', + '144': 'Puddlepeak', + '145': 'Noisemove', + '146': 'Noise2D', + '147': 'Perlin Move', + '148': 'Ripple Peak', + '149': 'Firenoise', '15': 'Running', + '150': 'Squared Swirl', + '151': 'RSVD', + '152': 'DNA', + '153': 'Matrix', + '154': 'Metaballs', + '155': 'Freqmap', + '156': 'Gravcenter', + '157': 'Gravcentric', + '158': 'Gravfreq', + '159': 'DJ Light', '16': 'Saw', + '160': 'Funky Plank', + '161': 'RSVD', + '162': 'Pulser', + '163': 'Blurz', + '164': 'Drift', + '165': 'Waverly', + '166': 'Sun Radiation', + '167': 'Colored Bursts', + '168': 'Julia', + '169': 'RSVD', '17': 'Twinkle', + '170': 'RSVD', + '171': 'RSVD', + '172': 'Game Of Life', + '173': 'Tartan', + '174': 'Polar Lights', + '175': 'Swirl', + '176': 'Lissajous', + '177': 'Frizzles', + '178': 'Plasma Ball', + '179': 'Flow Stripe', '18': 'Dissolve', + '180': 'Hiphotic', + '181': 'Sindots', + '182': 'DNA Spiral', + '183': 'Black Hole', + '184': 'Wavesins', + '185': 'Rocktaves', + '186': 'Akemi', '19': 'Dissolve Rnd', '2': 'Breathe', '20': 'Sparkle', - '21': 'Dark Sparkle', + '21': 'Sparkle Dark', '22': 'Sparkle+', '23': 'Strobe', '24': 'Strobe Rainbow', - '25': 'Mega Strobe', + '25': 'Strobe Mega', '26': 'Blink Rainbow', '27': 'Android', '28': 'Chase', @@ -33,33 +120,33 @@ '34': 'Colorful', '35': 'Traffic Light', '36': 'Sweep Random', - '37': 'Running 2', - '38': 'Red & Blue', + '37': 'Chase 2', + '38': 'Aurora', '39': 'Stream', '4': 'Wipe Random', '40': 'Scanner', '41': 'Lighthouse', '42': 'Fireworks', '43': 'Rain', - '44': 'Merry Christmas', + '44': 'Tetrix', '45': 'Fire Flicker', '46': 'Gradient', '47': 'Loading', - '48': 'In Out', - '49': 'In In', + '48': 'Rolling Balls', + '49': 'Fairy', '5': 'Random Colors', - '50': 'Out Out', - '51': 'Out In', - '52': 'Circus', - '53': 'Halloween', - '54': 'Tri Chase', + '50': 'Two Dots', + '51': 'Fairytwinkle', + '52': 'Running Dual', + '53': 'RSVD', + '54': 'Chase 3', '55': 'Tri Wipe', '56': 'Tri Fade', '57': 'Lightning', '58': 'ICU', '59': 'Multi Comet', '6': 'Sweep', - '60': 'Dual Scanner', + '60': 'Scanner Dual', '61': 'Stream 2', '62': 'Oscillate', '63': 'Pride 2015', @@ -67,55 +154,82 @@ '65': 'Palette', '66': 'Fire 2012', '67': 'Colorwaves', - '68': 'BPM', + '68': 'Bpm', '69': 'Fill Noise', '7': 'Dynamic', '70': 'Noise 1', '71': 'Noise 2', '72': 'Noise 3', '73': 'Noise 4', - '74': 'Colortwinkle', + '74': 'Colortwinkles', '75': 'Lake', '76': 'Meteor', - '77': 'Smooth Meteor', + '77': 'Meteor Smooth', '78': 'Railway', '79': 'Ripple', '8': 'Colorloop', '80': 'Twinklefox', + '81': 'Twinklecat', + '82': 'Halloween Eyes', + '83': 'Solid Pattern', + '84': 'Solid Pattern Tri', + '85': 'Spots', + '86': 'Spots Fade', + '87': 'Glitter', + '88': 'Candle', + '89': 'Fireworks Starburst', '9': 'Rainbow', + '90': 'Fireworks 1D', + '91': 'Bouncing Balls', + '92': 'Sinelon', + '93': 'Sinelon Dual', + '94': 'Sinelon Rainbow', + '95': 'Popcorn', + '96': 'Drip', + '97': 'Plasma', + '98': 'Percent', + '99': 'Ripple Rainbow', }), 'info': dict({ - 'architecture': 'esp8266', - 'arduino_core_version': '2.4.2', + 'arch': 'esp32', 'brand': 'WLED', - 'build_type': 'bin', - 'effect_count': 81, - 'filesystem': None, - 'free_heap': 14600, + 'core': 'v3.3.6-16-gcc5440f6a2', + 'freeheap': 198384, + 'fs': dict({ + 'pmt': 1718827787.0, + 't': 983, + 'u': 12, + }), + 'fxcount': 187, 'ip': '127.0.0.1', 'leds': dict({ - '__type': "", - 'repr': 'Leds(cct=False, count=30, fps=None, light_capabilities=None, max_power=850, max_segments=10, power=470, rgbw=False, wv=True, segment_light_capabilities=None)', + 'count': 30, + 'fps': 5, + 'light_capabilities': 1, + 'max_power': 850, + 'max_segments': 32, + 'power': 515, + 'segment_light_capabilities': list([ + 1, + 1, + ]), }), + 'lip': '', 'live': False, - 'live_ip': 'Unknown', - 'live_mode': 'Unknown', - 'mac_address': 'aabbccddeeff', + 'lm': '', + 'mac': 'aabbccddeeff', 'name': 'WLED RGB Light', - 'pallet_count': 50, - 'product': 'DIY light', - 'udp_port': 21324, - 'uptime': 32, - 'version': '0.8.5', - 'version_id': 1909122, - 'version_latest_beta': '0.13.0b1', - 'version_latest_stable': '0.12.0', - 'websocket': None, + 'palcount': 71, + 'product': 'FOSS', + 'udpport': 21324, + 'uptime': 966, + 'ver': '0.14.4', + 'vid': 2405180, 'wifi': '**REDACTED**', }), 'palettes': dict({ '0': 'Default', - '1': 'Random Cycle', + '1': '* Random Cycle', '10': 'Forest', '11': 'Rainbow', '12': 'Rainbow Bands', @@ -126,18 +240,18 @@ '17': 'Yellowout', '18': 'Analogous', '19': 'Splash', - '2': 'Primary Color', + '2': '* Color 1', '20': 'Pastel', '21': 'Sunset 2', - '22': 'Beech', + '22': 'Beach', '23': 'Vintage', '24': 'Departure', '25': 'Landscape', - '26': 'Beach', + '26': 'Beech', '27': 'Sherbet', '28': 'Hult', '29': 'Hult 64', - '3': 'Based on Primary', + '3': '* Colors 1&2', '30': 'Drywet', '31': 'Jul', '32': 'Grintage', @@ -148,7 +262,7 @@ '37': 'Cyane', '38': 'Light Pink', '39': 'Autumn', - '4': 'Set Colors', + '4': '* Color Gradient', '40': 'Magenta', '41': 'Magred', '42': 'Yelmag', @@ -159,9 +273,30 @@ '47': 'Orangery', '48': 'C9', '49': 'Sakura', - '5': 'Based on Set', + '5': '* Colors Only', + '50': 'Aurora', + '51': 'Atlantica', + '52': 'C9 2', + '53': 'C9 New', + '54': 'Temperature', + '55': 'Aurora 2', + '56': 'Retro Clown', + '57': 'Candy', + '58': 'Toxy Reaf', + '59': 'Fairy Reaf', '6': 'Party', + '60': 'Semi Blue', + '61': 'Pink Candy', + '62': 'Red Reaf', + '63': 'Aqua Flash', + '64': 'Yelblu Hot', + '65': 'Lite Light', + '66': 'Red Flash', + '67': 'Blink Red', + '68': 'Red Shift', + '69': 'Red Tide', '7': 'Cloud', + '70': 'Candy2', '8': 'Lava', '9': 'Ocean', }), @@ -170,30 +305,88 @@ 'presets': dict({ }), 'state': dict({ - 'brightness': 127, + 'bri': 128, 'lor': 0, - 'nightlight': dict({ - '__type': "", - 'repr': 'Nightlight(duration=60, fade=True, on=False, mode=, target_brightness=0)', + 'nl': dict({ + 'dur': 60, + 'mode': 1, + 'on': False, + 'tbri': 0, }), 'on': True, - 'playlist': -1, - 'preset': -1, - 'segments': list([ - dict({ - '__type': "", - 'repr': "Segment(brightness=127, clones=-1, color_primary=(255, 159, 0), color_secondary=(0, 0, 0), color_tertiary=(0, 0, 0), effect=Effect(effect_id=0, name='Solid'), intensity=128, length=20, on=True, palette=Palette(name='Default', palette_id=0), reverse=False, segment_id=0, selected=True, speed=32, start=0, stop=19)", + 'seg': dict({ + '0': dict({ + 'bri': 255, + 'cln': -1, + 'col': list([ + list([ + 127, + 172, + 255, + ]), + list([ + 0, + 0, + 0, + ]), + list([ + 0, + 0, + 0, + ]), + ]), + 'fx': 0, + 'id': 0, + 'ix': 128, + 'len': 15, + 'on': True, + 'pal': 0, + 'rev': False, + 'sel': False, + 'start': 0, + 'stop': 15, + 'sx': 32, }), - dict({ - '__type': "", - 'repr': "Segment(brightness=127, clones=-1, color_primary=(0, 255, 123), color_secondary=(0, 0, 0), color_tertiary=(0, 0, 0), effect=Effect(effect_id=1, name='Blink'), intensity=64, length=10, on=True, palette=Palette(name='Random Cycle', palette_id=1), reverse=True, segment_id=1, selected=True, speed=16, start=20, stop=30)", + '1': dict({ + 'bri': 255, + 'cln': -1, + 'col': list([ + list([ + 255, + 170, + 0, + ]), + list([ + 0, + 0, + 0, + ]), + list([ + 0, + 0, + 0, + ]), + ]), + 'fx': 3, + 'id': 1, + 'ix': 64, + 'len': 15, + 'on': True, + 'pal': 1, + 'rev': True, + 'sel': True, + 'start': 15, + 'stop': 30, + 'sx': 16, }), - ]), - 'sync': dict({ - '__type': "", - 'repr': 'Sync(receive=True, send=False)', }), 'transition': 7, + 'udpn': dict({ + 'recv': True, + 'rgrp': 1, + 'send': False, + 'sgrp': 1, + }), }), }) # --- diff --git a/tests/components/wled/snapshots/test_number.ambr b/tests/components/wled/snapshots/test_number.ambr index 6ed21dd3cbe..0fb6cff3d51 100644 --- a/tests/components/wled/snapshots/test_number.ambr +++ b/tests/components/wled/snapshots/test_number.ambr @@ -67,7 +67,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -79,14 +79,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- @@ -158,7 +158,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -170,183 +170,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', - 'via_device_id': None, - }) -# --- -# name: test_speed_state[number.wled_rgb_light_segment_1_intensity-42-intensity] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'WLED RGB Light Segment 1 Intensity', - 'max': 255, - 'min': 0, - 'mode': , - 'step': 1, - }), - 'context': , - 'entity_id': 'number.wled_rgb_light_segment_1_intensity', - 'last_changed': , - 'last_updated': , - 'state': '64', - }) -# --- -# name: test_speed_state[number.wled_rgb_light_segment_1_intensity-42-intensity].1 - EntityRegistryEntrySnapshot({ - '_display_repr': , - '_partial_repr': , - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'max': 255, - 'min': 0, - 'mode': , - 'step': 1, - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'number', - 'entity_category': , - 'entity_id': 'number.wled_rgb_light_segment_1_intensity', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Segment 1 Intensity', - 'platform': 'wled', - 'supported_features': 0, - 'translation_key': None, - 'unique_id': 'aabbccddeeff_intensity_1', - 'unit_of_measurement': None, - }) -# --- -# name: test_speed_state[number.wled_rgb_light_segment_1_intensity-42-intensity].2 - DeviceRegistryEntrySnapshot({ - 'area_id': None, - 'config_entries': , - 'configuration_url': 'http://127.0.0.1', - 'connections': set({ - tuple( - 'mac', - 'aa:bb:cc:dd:ee:ff', - ), - }), - 'disabled_by': None, - 'entry_type': None, - 'hw_version': 'esp8266', - 'id': , - 'identifiers': set({ - tuple( - 'wled', - 'aabbccddeeff', - ), - }), - 'is_new': False, - 'manufacturer': 'WLED', - 'model': 'DIY light', - 'name': 'WLED RGB Light', - 'name_by_user': None, - 'suggested_area': None, - 'sw_version': '0.8.5', - 'via_device_id': None, - }) -# --- -# name: test_speed_state[number.wled_rgb_light_segment_1_speed-42-speed] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'WLED RGB Light Segment 1 Speed', - 'icon': 'mdi:speedometer', - 'max': 255, - 'min': 0, - 'mode': , - 'step': 1, - }), - 'context': , - 'entity_id': 'number.wled_rgb_light_segment_1_speed', - 'last_changed': , - 'last_updated': , - 'state': '16', - }) -# --- -# name: test_speed_state[number.wled_rgb_light_segment_1_speed-42-speed].1 - EntityRegistryEntrySnapshot({ - '_display_repr': , - '_partial_repr': , - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'max': 255, - 'min': 0, - 'mode': , - 'step': 1, - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'number', - 'entity_category': , - 'entity_id': 'number.wled_rgb_light_segment_1_speed', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': 'mdi:speedometer', - 'original_name': 'Segment 1 Speed', - 'platform': 'wled', - 'supported_features': 0, - 'translation_key': None, - 'unique_id': 'aabbccddeeff_speed_1', - 'unit_of_measurement': None, - }) -# --- -# name: test_speed_state[number.wled_rgb_light_segment_1_speed-42-speed].2 - DeviceRegistryEntrySnapshot({ - 'area_id': None, - 'config_entries': , - 'configuration_url': 'http://127.0.0.1', - 'connections': set({ - tuple( - 'mac', - 'aa:bb:cc:dd:ee:ff', - ), - }), - 'disabled_by': None, - 'entry_type': None, - 'hw_version': 'esp8266', - 'id': , - 'identifiers': set({ - tuple( - 'wled', - 'aabbccddeeff', - ), - }), - 'is_new': False, - 'manufacturer': 'WLED', - 'model': 'DIY light', - 'name': 'WLED RGB Light', - 'name_by_user': None, - 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- diff --git a/tests/components/wled/snapshots/test_select.ambr b/tests/components/wled/snapshots/test_select.ambr index f1a70db88cd..2998583f8b3 100644 --- a/tests/components/wled/snapshots/test_select.ambr +++ b/tests/components/wled/snapshots/test_select.ambr @@ -69,7 +69,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -81,14 +81,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- @@ -97,56 +97,77 @@ 'attributes': ReadOnlyDict({ 'friendly_name': 'WLED RGB Light Segment 1 color palette', 'options': list([ - 'Analogous', - 'April Night', - 'Autumn', - 'Based on Primary', - 'Based on Set', - 'Beach', - 'Beech', - 'Breeze', - 'C9', - 'Cloud', - 'Cyane', 'Default', - 'Departure', - 'Drywet', - 'Fire', - 'Forest', - 'Grintage', - 'Hult', - 'Hult 64', - 'Icefire', - 'Jul', - 'Landscape', - 'Lava', - 'Light Pink', - 'Magenta', - 'Magred', - 'Ocean', - 'Orange & Teal', - 'Orangery', + '* Random Cycle', + '* Color 1', + '* Colors 1&2', + '* Color Gradient', + '* Colors Only', 'Party', - 'Pastel', - 'Primary Color', + 'Cloud', + 'Lava', + 'Ocean', + 'Forest', 'Rainbow', 'Rainbow Bands', - 'Random Cycle', - 'Red & Blue', - 'Rewhi', - 'Rivendell', - 'Sakura', - 'Set Colors', - 'Sherbet', - 'Splash', 'Sunset', - 'Sunset 2', - 'Tertiary', - 'Tiamat', - 'Vintage', - 'Yelblu', + 'Rivendell', + 'Breeze', + 'Red & Blue', 'Yellowout', + 'Analogous', + 'Splash', + 'Pastel', + 'Sunset 2', + 'Beach', + 'Vintage', + 'Departure', + 'Landscape', + 'Beech', + 'Sherbet', + 'Hult', + 'Hult 64', + 'Drywet', + 'Jul', + 'Grintage', + 'Rewhi', + 'Tertiary', + 'Fire', + 'Icefire', + 'Cyane', + 'Light Pink', + 'Autumn', + 'Magenta', + 'Magred', 'Yelmag', + 'Yelblu', + 'Orange & Teal', + 'Tiamat', + 'April Night', + 'Orangery', + 'C9', + 'Sakura', + 'Aurora', + 'Atlantica', + 'C9 2', + 'C9 New', + 'Temperature', + 'Aurora 2', + 'Retro Clown', + 'Candy', + 'Toxy Reaf', + 'Fairy Reaf', + 'Semi Blue', + 'Pink Candy', + 'Red Reaf', + 'Aqua Flash', + 'Yelblu Hot', + 'Lite Light', + 'Red Flash', + 'Blink Red', + 'Red Shift', + 'Red Tide', + 'Candy2', ]), }), 'context': , @@ -154,7 +175,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'Random Cycle', + 'state': '* Random Cycle', }) # --- # name: test_color_palette_state[rgb-select.wled_rgb_light_segment_1_color_palette-Icefire-segment-called_with0].1 @@ -164,56 +185,77 @@ 'area_id': None, 'capabilities': dict({ 'options': list([ - 'Analogous', - 'April Night', - 'Autumn', - 'Based on Primary', - 'Based on Set', - 'Beach', - 'Beech', - 'Breeze', - 'C9', - 'Cloud', - 'Cyane', 'Default', - 'Departure', - 'Drywet', - 'Fire', - 'Forest', - 'Grintage', - 'Hult', - 'Hult 64', - 'Icefire', - 'Jul', - 'Landscape', - 'Lava', - 'Light Pink', - 'Magenta', - 'Magred', - 'Ocean', - 'Orange & Teal', - 'Orangery', + '* Random Cycle', + '* Color 1', + '* Colors 1&2', + '* Color Gradient', + '* Colors Only', 'Party', - 'Pastel', - 'Primary Color', + 'Cloud', + 'Lava', + 'Ocean', + 'Forest', 'Rainbow', 'Rainbow Bands', - 'Random Cycle', - 'Red & Blue', - 'Rewhi', - 'Rivendell', - 'Sakura', - 'Set Colors', - 'Sherbet', - 'Splash', 'Sunset', - 'Sunset 2', - 'Tertiary', - 'Tiamat', - 'Vintage', - 'Yelblu', + 'Rivendell', + 'Breeze', + 'Red & Blue', 'Yellowout', + 'Analogous', + 'Splash', + 'Pastel', + 'Sunset 2', + 'Beach', + 'Vintage', + 'Departure', + 'Landscape', + 'Beech', + 'Sherbet', + 'Hult', + 'Hult 64', + 'Drywet', + 'Jul', + 'Grintage', + 'Rewhi', + 'Tertiary', + 'Fire', + 'Icefire', + 'Cyane', + 'Light Pink', + 'Autumn', + 'Magenta', + 'Magred', 'Yelmag', + 'Yelblu', + 'Orange & Teal', + 'Tiamat', + 'April Night', + 'Orangery', + 'C9', + 'Sakura', + 'Aurora', + 'Atlantica', + 'C9 2', + 'C9 New', + 'Temperature', + 'Aurora 2', + 'Retro Clown', + 'Candy', + 'Toxy Reaf', + 'Fairy Reaf', + 'Semi Blue', + 'Pink Candy', + 'Red Reaf', + 'Aqua Flash', + 'Yelblu Hot', + 'Lite Light', + 'Red Flash', + 'Blink Red', + 'Red Shift', + 'Red Tide', + 'Candy2', ]), }), 'config_entry_id': , @@ -256,7 +298,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -268,14 +310,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- @@ -293,7 +335,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'Playlist 1', + 'state': 'unknown', }) # --- # name: test_color_palette_state[rgbw-select.wled_rgbw_light_playlist-Playlist 2-playlist-called_with2].1 @@ -330,7 +372,7 @@ 'previous_unique_id': None, 'supported_features': 0, 'translation_key': 'playlist', - 'unique_id': 'aabbccddee11_playlist', + 'unique_id': 'aabbccddeeff_playlist', 'unit_of_measurement': None, }) # --- @@ -342,31 +384,31 @@ 'connections': set({ tuple( 'mac', - 'aa:bb:cc:dd:ee:11', + 'aa:bb:cc:dd:ee:ff', ), }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( 'wled', - 'aabbccddee11', + 'aabbccddeeff', ), }), 'is_new': False, 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGBW Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.6b4', + 'sw_version': '0.99.0b1', 'via_device_id': None, }) # --- @@ -384,7 +426,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'Preset 1', + 'state': 'unknown', }) # --- # name: test_color_palette_state[rgbw-select.wled_rgbw_light_preset-Preset 2-preset-called_with3].1 @@ -421,7 +463,7 @@ 'previous_unique_id': None, 'supported_features': 0, 'translation_key': 'preset', - 'unique_id': 'aabbccddee11_preset', + 'unique_id': 'aabbccddeeff_preset', 'unit_of_measurement': None, }) # --- @@ -433,31 +475,31 @@ 'connections': set({ tuple( 'mac', - 'aa:bb:cc:dd:ee:11', + 'aa:bb:cc:dd:ee:ff', ), }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( 'wled', - 'aabbccddee11', + 'aabbccddeeff', ), }), 'is_new': False, 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGBW Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.6b4', + 'sw_version': '0.99.0b1', 'via_device_id': None, }) # --- diff --git a/tests/components/wled/snapshots/test_switch.ambr b/tests/components/wled/snapshots/test_switch.ambr index fb604dcdaec..ee3a72ba872 100644 --- a/tests/components/wled/snapshots/test_switch.ambr +++ b/tests/components/wled/snapshots/test_switch.ambr @@ -3,7 +3,6 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ 'duration': 60, - 'fade': True, 'friendly_name': 'WLED RGB Light Nightlight', 'target_brightness': 0, }), @@ -61,7 +60,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -73,14 +72,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- @@ -143,7 +142,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -155,14 +154,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- @@ -226,7 +225,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -238,14 +237,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- @@ -309,7 +308,7 @@ }), 'disabled_by': None, 'entry_type': None, - 'hw_version': 'esp8266', + 'hw_version': 'esp32', 'id': , 'identifiers': set({ tuple( @@ -321,14 +320,14 @@ 'labels': set({ }), 'manufacturer': 'WLED', - 'model': 'DIY light', + 'model': 'FOSS', 'model_id': None, 'name': 'WLED RGB Light', 'name_by_user': None, 'primary_config_entry': , 'serial_number': None, 'suggested_area': None, - 'sw_version': '0.8.5', + 'sw_version': '0.14.4', 'via_device_id': None, }) # --- diff --git a/tests/components/wled/test_config_flow.py b/tests/components/wled/test_config_flow.py index a1529eda1c7..a1cf515a24b 100644 --- a/tests/components/wled/test_config_flow.py +++ b/tests/components/wled/test_config_flow.py @@ -33,9 +33,7 @@ async def test_full_user_flow_implementation(hass: HomeAssistant) -> None: assert result.get("title") == "WLED RGB Light" assert result.get("type") is FlowResultType.CREATE_ENTRY - assert "data" in result assert result["data"][CONF_HOST] == "192.168.1.123" - assert "result" in result assert result["result"].unique_id == "aabbccddeeff" @@ -167,23 +165,6 @@ async def test_user_device_exists_abort( assert result.get("reason") == "already_configured" -async def test_user_with_cct_channel_abort( - hass: HomeAssistant, - mock_wled: MagicMock, -) -> None: - """Test we abort user flow if WLED device uses a CCT channel.""" - mock_wled.update.return_value.info.leds.cct = True - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, - data={CONF_HOST: "192.168.1.123"}, - ) - - assert result.get("type") is FlowResultType.ABORT - assert result.get("reason") == "cct_unsupported" - - @pytest.mark.usefixtures("mock_wled") async def test_zeroconf_without_mac_device_exists_abort( hass: HomeAssistant, @@ -234,31 +215,6 @@ async def test_zeroconf_with_mac_device_exists_abort( assert result.get("reason") == "already_configured" -async def test_zeroconf_with_cct_channel_abort( - hass: HomeAssistant, - mock_wled: MagicMock, -) -> None: - """Test we abort zeroconf flow if WLED device uses a CCT channel.""" - mock_wled.update.return_value.info.leds.cct = True - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_ZEROCONF}, - data=zeroconf.ZeroconfServiceInfo( - ip_address=ip_address("192.168.1.123"), - ip_addresses=[ip_address("192.168.1.123")], - hostname="example.local.", - name="mock_name", - port=None, - properties={CONF_MAC: "aabbccddeeff"}, - type="mock_type", - ), - ) - - assert result.get("type") is FlowResultType.ABORT - assert result.get("reason") == "cct_unsupported" - - async def test_options_flow( hass: HomeAssistant, mock_config_entry: MockConfigEntry ) -> None: diff --git a/tests/components/wled/test_init.py b/tests/components/wled/test_init.py index f6f1da0d41e..9dfcabd55e3 100644 --- a/tests/components/wled/test_init.py +++ b/tests/components/wled/test_init.py @@ -7,7 +7,6 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest from wled import WLEDConnectionError -from homeassistant.components.wled.const import DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant @@ -44,7 +43,6 @@ async def test_load_unload_config_entry( # Ensure everything is cleaned up nicely and are disconnected assert mock_wled.disconnect.call_count == 1 - assert not hass.data.get(DOMAIN) @patch( @@ -69,21 +67,3 @@ async def test_setting_unique_id( """Test we set unique ID if not set yet.""" assert init_integration.runtime_data assert init_integration.unique_id == "aabbccddeeff" - - -async def test_error_config_entry_with_cct_channel( - hass: HomeAssistant, - mock_config_entry: MockConfigEntry, - mock_wled: AsyncMock, - caplog: pytest.LogCaptureFixture, -) -> None: - """Test the WLED fails entry setup with a CCT channel.""" - mock_wled.update.return_value.info.leds.cct = True - - mock_config_entry.add_to_hass(hass) - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() - - # Ensure config entry is errored and are connected and disconnected - assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR - assert "has a CCT channel, which is not supported" in caplog.text diff --git a/tests/components/wled/test_light.py b/tests/components/wled/test_light.py index 2b64619e306..032035f0141 100644 --- a/tests/components/wled/test_light.py +++ b/tests/components/wled/test_light.py @@ -1,6 +1,5 @@ """Tests for the WLED light platform.""" -import json from unittest.mock import MagicMock from freezegun.api import FrozenDateTimeFactory @@ -9,14 +8,21 @@ from wled import Device as WLEDDevice, WLEDConnectionError, WLEDError from homeassistant.components.light import ( ATTR_BRIGHTNESS, + ATTR_COLOR_MODE, ATTR_EFFECT, ATTR_HS_COLOR, ATTR_RGB_COLOR, ATTR_RGBW_COLOR, + ATTR_SUPPORTED_COLOR_MODES, ATTR_TRANSITION, DOMAIN as LIGHT_DOMAIN, + ColorMode, +) +from homeassistant.components.wled.const import ( + CONF_KEEP_MAIN_LIGHT, + DOMAIN, + SCAN_INTERVAL, ) -from homeassistant.components.wled.const import CONF_KEEP_MAIN_LIGHT, SCAN_INTERVAL from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_ICON, @@ -30,7 +36,11 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er -from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture +from tests.common import ( + MockConfigEntry, + async_fire_time_changed, + load_json_object_fixture, +) pytestmark = pytest.mark.usefixtures("init_integration") @@ -41,9 +51,9 @@ async def test_rgb_light_state( """Test the creation and values of the WLED lights.""" # First segment of the strip assert (state := hass.states.get("light.wled_rgb_light")) - assert state.attributes.get(ATTR_BRIGHTNESS) == 127 + assert state.attributes.get(ATTR_BRIGHTNESS) == 255 assert state.attributes.get(ATTR_EFFECT) == "Solid" - assert state.attributes.get(ATTR_HS_COLOR) == (37.412, 100.0) + assert state.attributes.get(ATTR_HS_COLOR) == (218.906, 50.196) assert state.attributes.get(ATTR_ICON) is None assert state.state == STATE_ON @@ -52,9 +62,9 @@ async def test_rgb_light_state( # Second segment of the strip assert (state := hass.states.get("light.wled_rgb_light_segment_1")) - assert state.attributes.get(ATTR_BRIGHTNESS) == 127 - assert state.attributes.get(ATTR_EFFECT) == "Blink" - assert state.attributes.get(ATTR_HS_COLOR) == (148.941, 100.0) + assert state.attributes.get(ATTR_BRIGHTNESS) == 255 + assert state.attributes.get(ATTR_EFFECT) == "Wipe" + assert state.attributes.get(ATTR_HS_COLOR) == (40.0, 100.0) assert state.attributes.get(ATTR_ICON) is None assert state.state == STATE_ON @@ -63,7 +73,7 @@ async def test_rgb_light_state( # Test main control of the lightstrip assert (state := hass.states.get("light.wled_rgb_light_main")) - assert state.attributes.get(ATTR_BRIGHTNESS) == 127 + assert state.attributes.get(ATTR_BRIGHTNESS) == 128 assert state.state == STATE_ON assert (entry := entity_registry.async_get("light.wled_rgb_light_main")) @@ -188,8 +198,8 @@ async def test_dynamically_handle_segments( assert not hass.states.get("light.wled_rgb_light_segment_1") return_value = mock_wled.update.return_value - mock_wled.update.return_value = WLEDDevice( - json.loads(load_fixture("wled/rgb.json")) + mock_wled.update.return_value = WLEDDevice.from_dict( + load_json_object_fixture("rgb.json", DOMAIN) ) freezer.tick(SCAN_INTERVAL) @@ -327,6 +337,8 @@ async def test_rgbw_light(hass: HomeAssistant, mock_wled: MagicMock) -> None: """Test RGBW support for WLED.""" assert (state := hass.states.get("light.wled_rgbw_light")) assert state.state == STATE_ON + assert state.attributes.get(ATTR_SUPPORTED_COLOR_MODES) == [ColorMode.RGBW] + assert state.attributes.get(ATTR_COLOR_MODE) == ColorMode.RGBW assert state.attributes.get(ATTR_RGBW_COLOR) == (255, 0, 0, 139) await hass.services.async_call( diff --git a/tests/components/wled/test_number.py b/tests/components/wled/test_number.py index b692de37282..344eb03bc06 100644 --- a/tests/components/wled/test_number.py +++ b/tests/components/wled/test_number.py @@ -1,6 +1,5 @@ """Tests for the WLED number platform.""" -import json from unittest.mock import MagicMock from freezegun.api import FrozenDateTimeFactory @@ -13,13 +12,13 @@ from homeassistant.components.number import ( DOMAIN as NUMBER_DOMAIN, SERVICE_SET_VALUE, ) -from homeassistant.components.wled.const import SCAN_INTERVAL +from homeassistant.components.wled.const import DOMAIN, SCAN_INTERVAL from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr, entity_registry as er -from tests.common import async_fire_time_changed, load_fixture +from tests.common import async_fire_time_changed, load_json_object_fixture pytestmark = pytest.mark.usefixtures("init_integration") @@ -128,8 +127,8 @@ async def test_speed_dynamically_handle_segments( # Test adding a segment dynamically... return_value = mock_wled.update.return_value - mock_wled.update.return_value = WLEDDevice( - json.loads(load_fixture("wled/rgb.json")) + mock_wled.update.return_value = WLEDDevice.from_dict( + load_json_object_fixture("rgb.json", DOMAIN) ) freezer.tick(SCAN_INTERVAL) diff --git a/tests/components/wled/test_select.py b/tests/components/wled/test_select.py index 380af1a286a..364e5fc2034 100644 --- a/tests/components/wled/test_select.py +++ b/tests/components/wled/test_select.py @@ -1,6 +1,5 @@ """Tests for the WLED select platform.""" -import json from unittest.mock import MagicMock from freezegun.api import FrozenDateTimeFactory @@ -9,18 +8,13 @@ from syrupy.assertion import SnapshotAssertion from wled import Device as WLEDDevice, WLEDConnectionError, WLEDError from homeassistant.components.select import ATTR_OPTION, DOMAIN as SELECT_DOMAIN -from homeassistant.components.wled.const import SCAN_INTERVAL -from homeassistant.const import ( - ATTR_ENTITY_ID, - SERVICE_SELECT_OPTION, - STATE_UNAVAILABLE, - STATE_UNKNOWN, -) +from homeassistant.components.wled.const import DOMAIN, SCAN_INTERVAL +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_SELECT_OPTION, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr, entity_registry as er -from tests.common import async_fire_time_changed, load_fixture +from tests.common import async_fire_time_changed, load_json_object_fixture pytestmark = pytest.mark.usefixtures("init_integration") @@ -135,8 +129,8 @@ async def test_color_palette_dynamically_handle_segments( assert not hass.states.get("select.wled_rgb_light_segment_1_color_palette") return_value = mock_wled.update.return_value - mock_wled.update.return_value = WLEDDevice( - json.loads(load_fixture("wled/rgb.json")) + mock_wled.update.return_value = WLEDDevice.from_dict( + load_json_object_fixture("rgb.json", DOMAIN) ) freezer.tick(SCAN_INTERVAL) @@ -148,7 +142,7 @@ async def test_color_palette_dynamically_handle_segments( assert ( segment1 := hass.states.get("select.wled_rgb_light_segment_1_color_palette") ) - assert segment1.state == "Random Cycle" + assert segment1.state == "* Random Cycle" # Test adding if segment shows up again, including the master entity mock_wled.update.return_value = return_value @@ -174,39 +168,3 @@ async def test_playlist_unavailable_without_playlists(hass: HomeAssistant) -> No """Test WLED playlist entity is unavailable when playlists are not available.""" assert (state := hass.states.get("select.wled_rgb_light_playlist")) assert state.state == STATE_UNAVAILABLE - - -@pytest.mark.parametrize("device_fixture", ["rgbw"]) -async def test_old_style_preset_active( - hass: HomeAssistant, - freezer: FrozenDateTimeFactory, - mock_wled: MagicMock, -) -> None: - """Test unknown preset returned (when old style/unknown) preset is active.""" - # Set device preset state to a random number - mock_wled.update.return_value.state.preset = 99 - - freezer.tick(SCAN_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - assert (state := hass.states.get("select.wled_rgbw_light_preset")) - assert state.state == STATE_UNKNOWN - - -@pytest.mark.parametrize("device_fixture", ["rgbw"]) -async def test_old_style_playlist_active( - hass: HomeAssistant, - freezer: FrozenDateTimeFactory, - mock_wled: MagicMock, -) -> None: - """Test when old style playlist cycle is active.""" - # Set device playlist to 0, which meant "cycle" previously. - mock_wled.update.return_value.state.playlist = 0 - - freezer.tick(SCAN_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - assert (state := hass.states.get("select.wled_rgbw_light_playlist")) - assert state.state == STATE_UNKNOWN diff --git a/tests/components/wled/test_sensor.py b/tests/components/wled/test_sensor.py index 319622e7cb3..8bd5431cf59 100644 --- a/tests/components/wled/test_sensor.py +++ b/tests/components/wled/test_sensor.py @@ -44,7 +44,7 @@ async def test_sensors( == UnitOfElectricCurrent.MILLIAMPERE ) assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.CURRENT - assert state.state == "470" + assert state.state == "515" assert ( entry := entity_registry.async_get("sensor.wled_rgb_light_estimated_current") @@ -55,7 +55,7 @@ async def test_sensors( assert (state := hass.states.get("sensor.wled_rgb_light_uptime")) assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TIMESTAMP assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None - assert state.state == "2019-11-11T09:10:00+00:00" + assert state.state == "2019-11-11T08:54:26+00:00" assert (entry := entity_registry.async_get("sensor.wled_rgb_light_uptime")) assert entry.unique_id == "aabbccddeeff_uptime" @@ -64,7 +64,7 @@ async def test_sensors( assert (state := hass.states.get("sensor.wled_rgb_light_free_memory")) assert state.attributes.get(ATTR_ICON) is None assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfInformation.BYTES - assert state.state == "14600" + assert state.state == "198384" assert entry.entity_category is EntityCategory.DIAGNOSTIC assert (entry := entity_registry.async_get("sensor.wled_rgb_light_free_memory")) @@ -74,7 +74,7 @@ async def test_sensors( assert (state := hass.states.get("sensor.wled_rgb_light_wi_fi_signal")) assert state.attributes.get(ATTR_ICON) is None assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE - assert state.state == "76" + assert state.state == "100" assert entry.entity_category is EntityCategory.DIAGNOSTIC assert (entry := entity_registry.async_get("sensor.wled_rgb_light_wi_fi_signal")) @@ -87,7 +87,7 @@ async def test_sensors( state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SIGNAL_STRENGTH_DECIBELS_MILLIWATT ) - assert state.state == "-62" + assert state.state == "-43" assert (entry := entity_registry.async_get("sensor.wled_rgb_light_wi_fi_rssi")) assert entry.unique_id == "aabbccddeeff_wifi_rssi" diff --git a/tests/components/wled/test_switch.py b/tests/components/wled/test_switch.py index 6dfd62e363f..48331ffa9cc 100644 --- a/tests/components/wled/test_switch.py +++ b/tests/components/wled/test_switch.py @@ -1,6 +1,5 @@ """Tests for the WLED switch platform.""" -import json from unittest.mock import MagicMock from freezegun.api import FrozenDateTimeFactory @@ -9,7 +8,7 @@ from syrupy.assertion import SnapshotAssertion from wled import Device as WLEDDevice, WLEDConnectionError, WLEDError from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN -from homeassistant.components.wled.const import SCAN_INTERVAL +from homeassistant.components.wled.const import DOMAIN, SCAN_INTERVAL from homeassistant.const import ( ATTR_ENTITY_ID, SERVICE_TURN_OFF, @@ -22,7 +21,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr, entity_registry as er -from tests.common import async_fire_time_changed, load_fixture +from tests.common import async_fire_time_changed, load_json_object_fixture pytestmark = pytest.mark.usefixtures("init_integration") @@ -144,8 +143,8 @@ async def test_switch_dynamically_handle_segments( # Test adding a segment dynamically... return_value = mock_wled.update.return_value - mock_wled.update.return_value = WLEDDevice( - json.loads(load_fixture("wled/rgb.json")) + mock_wled.update.return_value = WLEDDevice.from_dict( + load_json_object_fixture("rgb.json", DOMAIN) ) freezer.tick(SCAN_INTERVAL) diff --git a/tests/components/wled/test_update.py b/tests/components/wled/test_update.py index c576cdf16f9..a27aa918385 100644 --- a/tests/components/wled/test_update.py +++ b/tests/components/wled/test_update.py @@ -2,8 +2,9 @@ from unittest.mock import MagicMock +from freezegun.api import FrozenDateTimeFactory import pytest -from wled import WLEDError +from wled import Releases, WLEDError from homeassistant.components.update import ( ATTR_INSTALLED_VERSION, @@ -16,6 +17,7 @@ from homeassistant.components.update import ( UpdateDeviceClass, UpdateEntityFeature, ) +from homeassistant.components.wled.const import RELEASES_SCAN_INTERVAL from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, @@ -31,6 +33,8 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from tests.common import async_fire_time_changed + pytestmark = pytest.mark.usefixtures("init_integration") @@ -45,12 +49,12 @@ async def test_update_available( state.attributes[ATTR_ENTITY_PICTURE] == "https://brands.home-assistant.io/_/wled/icon.png" ) - assert state.attributes[ATTR_INSTALLED_VERSION] == "0.8.5" - assert state.attributes[ATTR_LATEST_VERSION] == "0.12.0" + assert state.attributes[ATTR_INSTALLED_VERSION] == "0.14.4" + assert state.attributes[ATTR_LATEST_VERSION] == "0.99.0" assert state.attributes[ATTR_RELEASE_SUMMARY] is None assert ( state.attributes[ATTR_RELEASE_URL] - == "https://github.com/Aircoookie/WLED/releases/tag/v0.12.0" + == "https://github.com/Aircoookie/WLED/releases/tag/v0.99.0" ) assert ( state.attributes[ATTR_SUPPORTED_FEATURES] @@ -64,15 +68,26 @@ async def test_update_available( assert entry.entity_category is EntityCategory.CONFIG -@pytest.mark.parametrize("device_fixture", ["rgb_no_update"]) async def test_update_information_available( - hass: HomeAssistant, entity_registry: er.EntityRegistry + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + entity_registry: er.EntityRegistry, + mock_wled_releases: MagicMock, ) -> None: """Test having no update information available at all.""" + mock_wled_releases.releases.return_value = Releases( + beta=None, + stable=None, + ) + + freezer.tick(RELEASES_SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + assert (state := hass.states.get("update.wled_rgb_light_firmware")) assert state.attributes.get(ATTR_DEVICE_CLASS) == UpdateDeviceClass.FIRMWARE assert state.state == STATE_UNKNOWN - assert state.attributes[ATTR_INSTALLED_VERSION] is None + assert state.attributes[ATTR_INSTALLED_VERSION] == "0.14.4" assert state.attributes[ATTR_LATEST_VERSION] is None assert state.attributes[ATTR_RELEASE_SUMMARY] is None assert state.attributes[ATTR_RELEASE_URL] is None @@ -98,12 +113,12 @@ async def test_no_update_available( assert (state := hass.states.get("update.wled_websocket_firmware")) assert state.state == STATE_OFF assert state.attributes.get(ATTR_DEVICE_CLASS) == UpdateDeviceClass.FIRMWARE - assert state.attributes[ATTR_INSTALLED_VERSION] == "0.12.0-b2" - assert state.attributes[ATTR_LATEST_VERSION] == "0.12.0-b2" + assert state.attributes[ATTR_INSTALLED_VERSION] == "0.99.0" + assert state.attributes[ATTR_LATEST_VERSION] == "0.99.0" assert state.attributes[ATTR_RELEASE_SUMMARY] is None assert ( state.attributes[ATTR_RELEASE_URL] - == "https://github.com/Aircoookie/WLED/releases/tag/v0.12.0-b2" + == "https://github.com/Aircoookie/WLED/releases/tag/v0.99.0" ) assert ( state.attributes[ATTR_SUPPORTED_FEATURES] @@ -151,8 +166,8 @@ async def test_update_stay_stable( """ assert (state := hass.states.get("update.wled_rgb_light_firmware")) assert state.state == STATE_ON - assert state.attributes[ATTR_INSTALLED_VERSION] == "0.8.5" - assert state.attributes[ATTR_LATEST_VERSION] == "0.12.0" + assert state.attributes[ATTR_INSTALLED_VERSION] == "0.14.4" + assert state.attributes[ATTR_LATEST_VERSION] == "0.99.0" await hass.services.async_call( UPDATE_DOMAIN, @@ -161,7 +176,7 @@ async def test_update_stay_stable( blocking=True, ) assert mock_wled.upgrade.call_count == 1 - mock_wled.upgrade.assert_called_with(version="0.12.0") + mock_wled.upgrade.assert_called_with(version="0.99.0") @pytest.mark.parametrize("device_fixture", ["rgbw"]) @@ -177,8 +192,8 @@ async def test_update_beta_to_stable( """ assert (state := hass.states.get("update.wled_rgbw_light_firmware")) assert state.state == STATE_ON - assert state.attributes[ATTR_INSTALLED_VERSION] == "0.8.6b4" - assert state.attributes[ATTR_LATEST_VERSION] == "0.8.6" + assert state.attributes[ATTR_INSTALLED_VERSION] == "0.99.0b1" + assert state.attributes[ATTR_LATEST_VERSION] == "0.99.0" await hass.services.async_call( UPDATE_DOMAIN, @@ -187,7 +202,7 @@ async def test_update_beta_to_stable( blocking=True, ) assert mock_wled.upgrade.call_count == 1 - mock_wled.upgrade.assert_called_with(version="0.8.6") + mock_wled.upgrade.assert_called_with(version="0.99.0") @pytest.mark.parametrize("device_fixture", ["rgb_single_segment"]) @@ -202,8 +217,8 @@ async def test_update_stay_beta( """ assert (state := hass.states.get("update.wled_rgb_light_firmware")) assert state.state == STATE_ON - assert state.attributes[ATTR_INSTALLED_VERSION] == "0.8.6b1" - assert state.attributes[ATTR_LATEST_VERSION] == "0.8.6b2" + assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0b4" + assert state.attributes[ATTR_LATEST_VERSION] == "1.0.0b5" await hass.services.async_call( UPDATE_DOMAIN, @@ -212,4 +227,4 @@ async def test_update_stay_beta( blocking=True, ) assert mock_wled.upgrade.call_count == 1 - mock_wled.upgrade.assert_called_with(version="0.8.6b2") + mock_wled.upgrade.assert_called_with(version="1.0.0b5")