Repository: XKNX/xknx
Pull request #799 (2021-11-10 21:29:52)

Fix light with global switch and brightness address
<!--
  You are awesome! Thanks for contributing to our project!
  Please, DO NOT DELETE ANY TEXT from this template!.
-->
## Description
<!--
Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context.
List any dependencies that are required for this change.
-->
Only send to global switch or brightness address, not individual colors, for turning on/off or changing brightness when all are configured.
See https://community.home-assistant.io/t/knx-dali-controller-last-set-color-always-overwritten/354163

Fixes # (issue)

## Type of change
<!--
Please tick the applicable options.
NOTE: Ticking multiple options most likely indicates
that your change is to big and it is suggested to split it into several smaller PRs.
-->

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update

## Checklist:

- [x] I have performed a self-review of my own code
- [x] The documentation has been adjusted accordingly
- [x] The changes generate no new warnings
- [x] Tests have been added that prove the fix is effective or that the feature works
- [x] The changes are documented in the changelog
- [ ] The Homeassistant plugin has been adjusted in case of new config options


codecov[bot]: # [Codecov](https://codecov.io/gh/XKNX/xknx/pull/799?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) Report
> Merging [#799](https://codecov.io/gh/XKNX/xknx/pull/799?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) (ff7238b) into [main](https://codecov.io/gh/XKNX/xknx/commit/158420b34694448e4733eb15bdaecae18577395f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) (158420b) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/XKNX/xknx/pull/799/graphs/tree.svg?width=650&height=150&src=pr&token=irWbIygS84&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX)](https://codecov.io/gh/XKNX/xknx/pull/799?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX)

```diff
@@           Coverage Diff           @@
##             main     #799   +/-   ##
=======================================
  Coverage   94.75%   94.75%           
=======================================
  Files         109      109           
  Lines        6808     6812    +4     
=======================================
+ Hits         6451     6455    +4     
  Misses        357      357           
```


| [Impacted Files](https://codecov.io/gh/XKNX/xknx/pull/799?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) | Coverage Δ | |
|---|---|---|
| [xknx/devices/light.py](https://codecov.io/gh/XKNX/xknx/pull/799/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2xpZ2h0LnB5) | `99.56% <100.00%> (+<0.01%)` | :arrow_up: |


Patch:
diff --git a/changelog.md b/changelog.md
index aeb548a0..4d463709 100644
--- a/changelog.md
+++ b/changelog.md
@@ -2,6 +2,10 @@
 
 ## Unreleased changes
 
+### Devices
+
+- Light: Only send to global switch or brightness address if individual colors are also configured
+
 ## 0.18.12 Add always callback to NumericValue and RawValue 2021-11-01
 
 ### Internals
diff --git a/xknx/devices/light.py b/xknx/devices/light.py
index 24b177f0..0e46773f 100644
--- a/xknx/devices/light.py
+++ b/xknx/devices/light.py
@@ -92,16 +92,18 @@ class _SwitchAndBrightness:
 
     async def set_on(self) -> None:
         """Switch light on."""
-        if self.switch.initialized:
+        if self.switch.writable:
             await self.switch.on()
-        elif self.brightness.initialized:
+            return
+        if self.brightness.writable:
             await self.brightness.set(self.brightness.range_to)
 
     async def set_off(self) -> None:
         """Switch light off."""
-        if self.switch.initialized:
+        if self.switch.writable:
             await self.switch.off()
-        elif self.brightness.initialized:
+            return
+        if self.brightness.writable:
             await self.brightness.set(0)
 
     def __eq__(self, other: object) -> bool:
@@ -375,15 +377,17 @@ class Light(Device):
 
     async def set_on(self) -> None:
         """Switch light on."""
-        if self.switch.initialized:
+        if self.switch.writable:
             await self.switch.on()
+            return
         for color in self._iter_individual_colors():
             await color.set_on()
 
     async def set_off(self) -> None:
         """Switch light off."""
-        if self.switch.initialized:
+        if self.switch.writable:
             await self.switch.off()
+            return
         for color in self._iter_individual_colors():
             await color.set_off()
 


Test patch:
diff --git a/test/devices_tests/light_test.py b/test/devices_tests/light_test.py
index 86f7d384..bd9fad9a 100644
--- a/test/devices_tests/light_test.py
+++ b/test/devices_tests/light_test.py
@@ -684,6 +684,52 @@ class TestLight:
                 "Dimming not supported for device %s", "TestLight"
             )
 
+    async def test_set_individual_color_with_gloabl_switch(self):
+        """Test switching on and dimming a Light with global addresses."""
+        xknx = XKNX()
+        light = Light(
+            xknx,
+            "Diningroom.Light_1",
+            group_address_switch="1/0/0",
+            group_address_brightness="1/0/1",
+            group_address_switch_red="1/1/1",
+            group_address_switch_red_state="1/1/2",
+            group_address_brightness_red="1/1/3",
+            group_address_brightness_red_state="1/1/4",
+            group_address_switch_green="1/1/5",
+            group_address_switch_green_state="1/1/6",
+            group_address_brightness_green="1/1/7",
+            group_address_brightness_green_state="1/1/8",
+            group_address_switch_blue="1/1/9",
+            group_address_switch_blue_state="1/1/10",
+            group_address_brightness_blue="1/1/11",
+            group_address_brightness_blue_state="1/1/12",
+            group_address_switch_white="1/1/13",
+            group_address_switch_white_state="1/1/14",
+            group_address_brightness_white="1/1/15",
+            group_address_brightness_white_state="1/1/16",
+        )
+        assert light.state is None
+        for color in light._iter_individual_colors():
+            assert color.is_on is None
+        # turn on
+        await light.set_on()
+        assert xknx.telegrams.qsize() == 1
+
+        telegram = xknx.telegrams.get_nowait()
+        assert telegram == Telegram(
+            destination_address=GroupAddress("1/0/0"),
+            payload=GroupValueWrite(DPTBinary(True)),
+        )
+        # brightness
+        await light.set_brightness(23)
+        assert xknx.telegrams.qsize() == 1
+        telegram = xknx.telegrams.get_nowait()
+        assert telegram == Telegram(
+            destination_address=GroupAddress("1/0/1"),
+            payload=GroupValueWrite(DPTArray(23)),
+        )
+
     #
     # TEST SET COLOR
     #