From 215c7e0e14c7fa7f5f12a2a4e8fdfc158e5bd58c Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sun, 7 Jun 2020 23:37:58 +0200 Subject: [PATCH] Fix WLED power and brightness with WLED 0.10+ (#36529) --- homeassistant/components/wled/light.py | 163 ++++++++++--- homeassistant/components/wled/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/wled/test_light.py | 240 ++++++++++++++++---- 5 files changed, 337 insertions(+), 72 deletions(-) diff --git a/homeassistant/components/wled/light.py b/homeassistant/components/wled/light.py index 77f8960ada2..6a22bf6852f 100644 --- a/homeassistant/components/wled/light.py +++ b/homeassistant/components/wled/light.py @@ -83,20 +83,78 @@ async def async_setup_entry( update_segments() -class WLEDLight(LightEntity, WLEDDeviceEntity): - """Defines a WLED light.""" +class WLEDMasterLight(LightEntity, WLEDDeviceEntity): + """Defines a WLED master light.""" + + def __init__(self, entry_id: str, coordinator: WLEDDataUpdateCoordinator): + """Initialize WLED master light.""" + super().__init__( + entry_id=entry_id, + coordinator=coordinator, + name=f"{coordinator.data.info.name} Master", + icon="mdi:led-strip-variant", + ) + + @property + def unique_id(self) -> str: + """Return the unique ID for this sensor.""" + return f"{self.coordinator.data.info.mac_address}" + + @property + def supported_features(self) -> int: + """Flag supported features.""" + return SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION + + @property + def brightness(self) -> Optional[int]: + """Return the brightness of this light between 1..255.""" + return self.coordinator.data.state.brightness + + @property + def is_on(self) -> bool: + """Return the state of the light.""" + return bool(self.coordinator.data.state.on) + + @wled_exception_handler + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn off the light.""" + data = {ATTR_ON: False} + + if ATTR_TRANSITION in kwargs: + # WLED uses 100ms per unit, so 10 = 1 second. + data[ATTR_TRANSITION] = round(kwargs[ATTR_TRANSITION] * 10) + + await self.coordinator.wled.master(**data) + + @wled_exception_handler + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn on the light.""" + data = {ATTR_ON: True} + + if ATTR_TRANSITION in kwargs: + # WLED uses 100ms per unit, so 10 = 1 second. + data[ATTR_TRANSITION] = round(kwargs[ATTR_TRANSITION] * 10) + + if ATTR_BRIGHTNESS in kwargs: + data[ATTR_BRIGHTNESS] = kwargs[ATTR_BRIGHTNESS] + + await self.coordinator.wled.master(**data) + + +class WLEDSegmentLight(LightEntity, WLEDDeviceEntity): + """Defines a WLED light based on a segment.""" def __init__( self, entry_id: str, coordinator: WLEDDataUpdateCoordinator, segment: int ): - """Initialize WLED light.""" + """Initialize WLED segment light.""" self._rgbw = coordinator.data.info.leds.rgbw self._segment = segment - # Only apply the segment ID if it is not the first segment - name = coordinator.data.info.name - if segment != 0: - name += f" {segment}" + # If this is the one and only segment, use a simpler name + name = f"{coordinator.data.info.name} Segment {self._segment}" + if len(coordinator.data.state.segments) == 1: + name = coordinator.data.info.name super().__init__( entry_id=entry_id, @@ -155,7 +213,16 @@ class WLEDLight(LightEntity, WLEDDeviceEntity): @property def brightness(self) -> Optional[int]: """Return the brightness of this light between 1..255.""" - return self.coordinator.data.state.brightness + state = self.coordinator.data.state + + # If this is the one and only segment, calculate brightness based + # on the master and segment brightness + if len(state.segments) == 1: + return int( + (state.segments[self._segment].brightness * state.brightness) / 255 + ) + + return state.segments[self._segment].brightness @property def white_value(self) -> Optional[int]: @@ -187,18 +254,30 @@ class WLEDLight(LightEntity, WLEDDeviceEntity): @property def is_on(self) -> bool: """Return the state of the light.""" - return bool(self.coordinator.data.state.on) + state = self.coordinator.data.state + + # If there is a single segment, take master into account + if len(state.segments) == 1 and not state.on: + return False + + return bool(state.segments[self._segment].on) @wled_exception_handler async def async_turn_off(self, **kwargs: Any) -> None: """Turn off the light.""" - data = {ATTR_ON: False, ATTR_SEGMENT_ID: self._segment} + data = {ATTR_ON: False} if ATTR_TRANSITION in kwargs: # WLED uses 100ms per unit, so 10 = 1 second. data[ATTR_TRANSITION] = round(kwargs[ATTR_TRANSITION] * 10) - await self.coordinator.wled.light(**data) + # If there is a single segment, control via the master + if len(self.coordinator.data.state.segments) == 1: + await self.coordinator.wled.master(**data) + return + + data[ATTR_SEGMENT_ID] = self._segment + await self.coordinator.wled.segment(**data) @wled_exception_handler async def async_turn_on(self, **kwargs: Any) -> None: @@ -248,7 +327,23 @@ class WLEDLight(LightEntity, WLEDDeviceEntity): else: data[ATTR_COLOR_PRIMARY] += (self.white_value,) - await self.coordinator.wled.light(**data) + # When only 1 segment is present, switch along the master, and use + # the master for power/brightness control. + if len(self.coordinator.data.state.segments) == 1: + master_data = {ATTR_ON: True} + if ATTR_BRIGHTNESS in data: + master_data[ATTR_BRIGHTNESS] = data[ATTR_BRIGHTNESS] + data[ATTR_BRIGHTNESS] = 255 + + if ATTR_TRANSITION in data: + master_data[ATTR_TRANSITION] = data[ATTR_TRANSITION] + del data[ATTR_TRANSITION] + + await self.coordinator.wled.segment(**data) + await self.coordinator.wled.master(**master_data) + return + + await self.coordinator.wled.segment(**data) @wled_exception_handler async def async_effect( @@ -273,45 +368,59 @@ class WLEDLight(LightEntity, WLEDDeviceEntity): if speed is not None: data[ATTR_SPEED] = speed - await self.coordinator.wled.light(**data) + await self.coordinator.wled.segment(**data) @callback def async_update_segments( entry: ConfigEntry, coordinator: WLEDDataUpdateCoordinator, - current: Dict[int, WLEDLight], + current: Dict[int, WLEDSegmentLight], async_add_entities, ) -> None: """Update segments.""" segment_ids = {light.segment_id for light in coordinator.data.state.segments} current_ids = set(current) - # Process new segments, add them to Home Assistant - new_segments = [] - for segment_id in segment_ids - current_ids: - current[segment_id] = WLEDLight(entry.entry_id, coordinator, segment_id) - new_segments.append(current[segment_id]) + # Discard master (if present) + current_ids.discard(-1) - if new_segments: - async_add_entities(new_segments) + # Process new segments, add them to Home Assistant + new_entities = [] + for segment_id in segment_ids - current_ids: + current[segment_id] = WLEDSegmentLight(entry.entry_id, coordinator, segment_id) + new_entities.append(current[segment_id]) + + # More than 1 segment now? Add master controls + if len(current_ids) < 2 and len(segment_ids) > 1: + current[-1] = WLEDMasterLight(entry.entry_id, coordinator) + new_entities.append(current[-1]) + + if new_entities: + async_add_entities(new_entities) # Process deleted segments, remove them from Home Assistant for segment_id in current_ids - segment_ids: coordinator.hass.async_create_task( - async_remove_segment(segment_id, coordinator, current) + async_remove_entity(segment_id, coordinator, current) + ) + + # Remove master if there is only 1 segment left + if len(current_ids) > 1 and len(segment_ids) < 2: + coordinator.hass.async_create_task( + async_remove_entity(-1, coordinator, current) ) -async def async_remove_segment( - segment_id: int, +async def async_remove_entity( + index: int, coordinator: WLEDDataUpdateCoordinator, - current: Dict[int, WLEDLight], + current: Dict[int, WLEDSegmentLight], ) -> None: """Remove WLED segment light from Home Assistant.""" - entity = current[segment_id] + entity = current[index] await entity.async_remove() registry = await async_get_entity_registry(coordinator.hass) if entity.entity_id in registry.entities: registry.async_remove(entity.entity_id) - del current[segment_id] + del current[index] diff --git a/homeassistant/components/wled/manifest.json b/homeassistant/components/wled/manifest.json index aa3f944ed1e..1653ecf1365 100644 --- a/homeassistant/components/wled/manifest.json +++ b/homeassistant/components/wled/manifest.json @@ -3,7 +3,7 @@ "name": "WLED", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/wled", - "requirements": ["wled==0.4.1"], + "requirements": ["wled==0.4.2"], "zeroconf": ["_wled._tcp.local."], "codeowners": ["@frenck"], "quality_scale": "platinum" diff --git a/requirements_all.txt b/requirements_all.txt index 20b8299c1a4..eafa4553c81 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2201,7 +2201,7 @@ wirelesstagpy==0.4.0 withings-api==2.1.3 # homeassistant.components.wled -wled==0.4.1 +wled==0.4.2 # homeassistant.components.xbee xbee-helper==0.0.7 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8c196019a5e..96dbb7104d1 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -910,7 +910,7 @@ wiffi==1.0.0 withings-api==2.1.3 # homeassistant.components.wled -wled==0.4.1 +wled==0.4.2 # homeassistant.components.bluesound # homeassistant.components.rest diff --git a/tests/components/wled/test_light.py b/tests/components/wled/test_light.py index 8854b00ff83..35e8ea0f7ef 100644 --- a/tests/components/wled/test_light.py +++ b/tests/components/wled/test_light.py @@ -29,6 +29,7 @@ from homeassistant.const import ( ATTR_ICON, SERVICE_TURN_OFF, SERVICE_TURN_ON, + STATE_OFF, STATE_ON, STATE_UNAVAILABLE, ) @@ -50,7 +51,7 @@ async def test_rgb_light_state( entity_registry = await hass.helpers.entity_registry.async_get_registry() # First segment of the strip - state = hass.states.get("light.wled_rgb_light") + state = hass.states.get("light.wled_rgb_light_segment_0") assert state assert state.attributes.get(ATTR_BRIGHTNESS) == 127 assert state.attributes.get(ATTR_EFFECT) == "Solid" @@ -64,12 +65,12 @@ async def test_rgb_light_state( assert state.attributes.get(ATTR_SPEED) == 32 assert state.state == STATE_ON - entry = entity_registry.async_get("light.wled_rgb_light") + entry = entity_registry.async_get("light.wled_rgb_light_segment_0") assert entry assert entry.unique_id == "aabbccddeeff_0" # Second segment of the strip - state = hass.states.get("light.wled_rgb_light_1") + state = hass.states.get("light.wled_rgb_light_segment_1") assert state assert state.attributes.get(ATTR_BRIGHTNESS) == 127 assert state.attributes.get(ATTR_EFFECT) == "Blink" @@ -83,22 +84,32 @@ async def test_rgb_light_state( assert state.attributes.get(ATTR_SPEED) == 16 assert state.state == STATE_ON - entry = entity_registry.async_get("light.wled_rgb_light_1") + entry = entity_registry.async_get("light.wled_rgb_light_segment_1") assert entry assert entry.unique_id == "aabbccddeeff_1" + # Test master control of the lightstrip + state = hass.states.get("light.wled_rgb_light_master") + assert state + assert state.attributes.get(ATTR_BRIGHTNESS) == 127 + assert state.state == STATE_ON -async def test_switch_change_state( + entry = entity_registry.async_get("light.wled_rgb_light_master") + assert entry + assert entry.unique_id == "aabbccddeeff" + + +async def test_segment_change_state( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, caplog ) -> None: - """Test the change of state of the WLED switches.""" + """Test the change of state of the WLED segments.""" await init_integration(hass, aioclient_mock) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: "light.wled_rgb_light", ATTR_TRANSITION: 5}, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_TRANSITION: 5}, blocking=True, ) await hass.async_block_till_done() @@ -106,14 +117,14 @@ async def test_switch_change_state( on=False, segment_id=0, transition=50, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_ON, { ATTR_BRIGHTNESS: 42, ATTR_EFFECT: "Chase", - ATTR_ENTITY_ID: "light.wled_rgb_light", + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_RGB_COLOR: [255, 0, 0], ATTR_TRANSITION: 5, }, @@ -129,11 +140,11 @@ async def test_switch_change_state( transition=50, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_ON, - {ATTR_ENTITY_ID: "light.wled_rgb_light", ATTR_COLOR_TEMP: 400}, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_COLOR_TEMP: 400}, blocking=True, ) await hass.async_block_till_done() @@ -142,33 +153,178 @@ async def test_switch_change_state( ) +async def test_master_change_state( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, caplog +) -> None: + """Test the change of state of the WLED master light control.""" + await init_integration(hass, aioclient_mock) + + with patch("wled.WLED.master") as light_mock: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "light.wled_rgb_light_master", ATTR_TRANSITION: 5}, + blocking=True, + ) + await hass.async_block_till_done() + light_mock.assert_called_once_with( + on=False, transition=50, + ) + + with patch("wled.WLED.master") as light_mock: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + { + ATTR_BRIGHTNESS: 42, + ATTR_ENTITY_ID: "light.wled_rgb_light_master", + ATTR_TRANSITION: 5, + }, + blocking=True, + ) + await hass.async_block_till_done() + light_mock.assert_called_once_with( + brightness=42, on=True, transition=50, + ) + + with patch("wled.WLED.master") as light_mock: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "light.wled_rgb_light_master", ATTR_TRANSITION: 5}, + blocking=True, + ) + await hass.async_block_till_done() + light_mock.assert_called_once_with( + on=False, transition=50, + ) + + with patch("wled.WLED.master") as light_mock: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + { + ATTR_BRIGHTNESS: 42, + ATTR_ENTITY_ID: "light.wled_rgb_light_master", + ATTR_TRANSITION: 5, + }, + blocking=True, + ) + await hass.async_block_till_done() + light_mock.assert_called_once_with( + brightness=42, on=True, transition=50, + ) + + async def test_dynamically_handle_segments( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test if a new/deleted segment is dynamically added/removed.""" await init_integration(hass, aioclient_mock) - assert hass.states.get("light.wled_rgb_light") - assert hass.states.get("light.wled_rgb_light_1") + assert hass.states.get("light.wled_rgb_light_master") + assert hass.states.get("light.wled_rgb_light_segment_0") + assert hass.states.get("light.wled_rgb_light_segment_1") data = json.loads(load_fixture("wled/rgb_single_segment.json")) device = WLEDDevice(data) - # Test removal if segment went missing + # Test removal if segment went missing, including the master entity with patch( "homeassistant.components.wled.WLED.update", return_value=device, ): async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) await hass.async_block_till_done() - assert hass.states.get("light.wled_rgb_light") - assert not hass.states.get("light.wled_rgb_light_1") + assert hass.states.get("light.wled_rgb_light_segment_0") + assert not hass.states.get("light.wled_rgb_light_segment_1") + assert not hass.states.get("light.wled_rgb_light_master") - # Test adding if segment shows up again + # Test adding if segment shows up again, including the master entity async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) await hass.async_block_till_done() - assert hass.states.get("light.wled_rgb_light") - assert hass.states.get("light.wled_rgb_light_1") + assert hass.states.get("light.wled_rgb_light_master") + assert hass.states.get("light.wled_rgb_light_segment_0") + assert hass.states.get("light.wled_rgb_light_segment_1") + + +async def test_single_segment_behavior( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, caplog +) -> None: + """Test the behavior of the integration with a single segment.""" + await init_integration(hass, aioclient_mock) + + data = json.loads(load_fixture("wled/rgb_single_segment.json")) + device = WLEDDevice(data) + + # Test absent master + with patch( + "homeassistant.components.wled.WLED.update", return_value=device, + ): + async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) + await hass.async_block_till_done() + + assert not hass.states.get("light.wled_rgb_light_master") + + state = hass.states.get("light.wled_rgb_light_segment_0") + assert state + assert state.state == STATE_ON + + # Test segment brightness takes master into account + device.state.brightness = 100 + device.state.segments[0].brightness = 255 + with patch( + "homeassistant.components.wled.WLED.update", return_value=device, + ): + async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) + await hass.async_block_till_done() + + state = hass.states.get("light.wled_rgb_light_segment_0") + assert state + assert state.attributes.get(ATTR_BRIGHTNESS) == 100 + + # Test segment is off when master is off + device.state.on = False + with patch( + "homeassistant.components.wled.WLED.update", return_value=device, + ): + async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) + await hass.async_block_till_done() + state = hass.states.get("light.wled_rgb_light_segment_0") + assert state + assert state.state == STATE_OFF + + # Test master is turned off when turning off a single segment + with patch("wled.WLED.master") as master_mock: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_TRANSITION: 5}, + blocking=True, + ) + await hass.async_block_till_done() + master_mock.assert_called_once_with( + on=False, transition=50, + ) + + # Test master is turned on when turning on a single segment, and segment + # brightness is set to 255. + with patch("wled.WLED.master") as master_mock, patch( + "wled.WLED.segment" + ) as segment_mock: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + { + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", + ATTR_TRANSITION: 5, + ATTR_BRIGHTNESS: 42, + }, + blocking=True, + ) + await hass.async_block_till_done() + master_mock.assert_called_once_with(on=True, transition=50, brightness=42) + segment_mock.assert_called_once_with(on=True, segment_id=0, brightness=255) async def test_light_error( @@ -182,12 +338,12 @@ async def test_light_error( await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: "light.wled_rgb_light"}, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0"}, blocking=True, ) await hass.async_block_till_done() - state = hass.states.get("light.wled_rgb_light") + state = hass.states.get("light.wled_rgb_light_segment_0") assert state.state == STATE_ON assert "Invalid response from API" in caplog.text @@ -199,17 +355,17 @@ async def test_light_connection_error( await init_integration(hass, aioclient_mock) with patch("homeassistant.components.wled.WLED.update"), patch( - "homeassistant.components.wled.WLED.light", side_effect=WLEDConnectionError + "homeassistant.components.wled.WLED.segment", side_effect=WLEDConnectionError ): await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: "light.wled_rgb_light"}, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0"}, blocking=True, ) await hass.async_block_till_done() - state = hass.states.get("light.wled_rgb_light") + state = hass.states.get("light.wled_rgb_light_segment_0") assert state.state == STATE_UNAVAILABLE @@ -224,7 +380,7 @@ async def test_rgbw_light( assert state.attributes.get(ATTR_HS_COLOR) == (0.0, 100.0) assert state.attributes.get(ATTR_WHITE_VALUE) == 139 - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_ON, @@ -236,7 +392,7 @@ async def test_rgbw_light( on=True, segment_id=0, color_primary=(255, 159, 70, 139), ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_ON, @@ -248,7 +404,7 @@ async def test_rgbw_light( color_primary=(255, 0, 0, 100), on=True, segment_id=0, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_ON, @@ -271,13 +427,13 @@ async def test_effect_service( """Test the effect service of a WLED light.""" await init_integration(hass, aioclient_mock) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( DOMAIN, SERVICE_EFFECT, { ATTR_EFFECT: "Rainbow", - ATTR_ENTITY_ID: "light.wled_rgb_light", + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_INTENSITY: 200, ATTR_REVERSE: True, ATTR_SPEED: 100, @@ -289,11 +445,11 @@ async def test_effect_service( effect="Rainbow", intensity=200, reverse=True, segment_id=0, speed=100, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( DOMAIN, SERVICE_EFFECT, - {ATTR_ENTITY_ID: "light.wled_rgb_light", ATTR_EFFECT: 9}, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_EFFECT: 9}, blocking=True, ) await hass.async_block_till_done() @@ -301,12 +457,12 @@ async def test_effect_service( segment_id=0, effect=9, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( DOMAIN, SERVICE_EFFECT, { - ATTR_ENTITY_ID: "light.wled_rgb_light", + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_INTENSITY: 200, ATTR_REVERSE: True, ATTR_SPEED: 100, @@ -318,13 +474,13 @@ async def test_effect_service( intensity=200, reverse=True, segment_id=0, speed=100, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( DOMAIN, SERVICE_EFFECT, { ATTR_EFFECT: "Rainbow", - ATTR_ENTITY_ID: "light.wled_rgb_light", + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_REVERSE: True, ATTR_SPEED: 100, }, @@ -335,13 +491,13 @@ async def test_effect_service( effect="Rainbow", reverse=True, segment_id=0, speed=100, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( DOMAIN, SERVICE_EFFECT, { ATTR_EFFECT: "Rainbow", - ATTR_ENTITY_ID: "light.wled_rgb_light", + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_INTENSITY: 200, ATTR_SPEED: 100, }, @@ -352,13 +508,13 @@ async def test_effect_service( effect="Rainbow", intensity=200, segment_id=0, speed=100, ) - with patch("wled.WLED.light") as light_mock: + with patch("wled.WLED.segment") as light_mock: await hass.services.async_call( DOMAIN, SERVICE_EFFECT, { ATTR_EFFECT: "Rainbow", - ATTR_ENTITY_ID: "light.wled_rgb_light", + ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_INTENSITY: 200, ATTR_REVERSE: True, }, @@ -381,11 +537,11 @@ async def test_effect_service_error( await hass.services.async_call( DOMAIN, SERVICE_EFFECT, - {ATTR_ENTITY_ID: "light.wled_rgb_light", ATTR_EFFECT: 9}, + {ATTR_ENTITY_ID: "light.wled_rgb_light_segment_0", ATTR_EFFECT: 9}, blocking=True, ) await hass.async_block_till_done() - state = hass.states.get("light.wled_rgb_light") + state = hass.states.get("light.wled_rgb_light_segment_0") assert state.state == STATE_ON assert "Invalid response from API" in caplog.text