Add test checking ZHA light restores with  `None` attributes
diff --git a/tests/components/zha/conftest.py b/tests/components/zha/conftest.py
index 9d9d74e72dfeab..a4ff5a3b20549e 100644
--- a/tests/components/zha/conftest.py
+++ b/tests/components/zha/conftest.py
@@ -26,7 +26,9 @@
 import homeassistant.components.zha.core.const as zha_const
 import homeassistant.components.zha.core.device as zha_core_device
 from homeassistant.components.zha.core.helpers import get_zha_gateway
+from homeassistant.helpers import restore_state
 from homeassistant.setup import async_setup_component
+import homeassistant.util.dt as dt_util
 
 from .common import patch_cluster as common_patch_cluster
 
@@ -498,3 +500,35 @@ def network_backup() -> zigpy.backups.NetworkBackup:
             },
         }
     )
+
+
+@pytest.fixture
+def core_rs(hass_storage):
+    """Core.restore_state fixture."""
+
+    def _storage(entity_id, state, attributes={}):
+        now = dt_util.utcnow().isoformat()
+
+        hass_storage[restore_state.STORAGE_KEY] = {
+            "version": restore_state.STORAGE_VERSION,
+            "key": restore_state.STORAGE_KEY,
+            "data": [
+                {
+                    "state": {
+                        "entity_id": entity_id,
+                        "state": str(state),
+                        "attributes": attributes,
+                        "last_changed": now,
+                        "last_updated": now,
+                        "context": {
+                            "id": "3c2243ff5f30447eb12e7348cfd5b8ff",
+                            "user_id": None,
+                        },
+                    },
+                    "last_seen": now,
+                }
+            ],
+        }
+        return
+
+    return _storage
diff --git a/tests/components/zha/test_binary_sensor.py b/tests/components/zha/test_binary_sensor.py
index b41499dada7789..5dd7a5653ecd79 100644
--- a/tests/components/zha/test_binary_sensor.py
+++ b/tests/components/zha/test_binary_sensor.py
@@ -9,8 +9,6 @@
 
 from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, Platform
 from homeassistant.core import HomeAssistant
-from homeassistant.helpers import restore_state
-from homeassistant.util import dt as dt_util
 
 from .common import (
     async_enable_traffic,
@@ -152,38 +150,6 @@ async def test_binary_sensor(
     assert hass.states.get(entity_id).state == STATE_OFF
 
 
-@pytest.fixture
-def core_rs(hass_storage):
-    """Core.restore_state fixture."""
-
-    def _storage(entity_id, attributes, state):
-        now = dt_util.utcnow().isoformat()
-
-        hass_storage[restore_state.STORAGE_KEY] = {
-            "version": restore_state.STORAGE_VERSION,
-            "key": restore_state.STORAGE_KEY,
-            "data": [
-                {
-                    "state": {
-                        "entity_id": entity_id,
-                        "state": str(state),
-                        "attributes": attributes,
-                        "last_changed": now,
-                        "last_updated": now,
-                        "context": {
-                            "id": "3c2243ff5f30447eb12e7348cfd5b8ff",
-                            "user_id": None,
-                        },
-                    },
-                    "last_seen": now,
-                }
-            ],
-        }
-        return
-
-    return _storage
-
-
 @pytest.mark.parametrize(
     "restored_state",
     [
diff --git a/tests/components/zha/test_light.py b/tests/components/zha/test_light.py
index 1ec70b74735389..bd799187a19728 100644
--- a/tests/components/zha/test_light.py
+++ b/tests/components/zha/test_light.py
@@ -40,7 +40,10 @@
 )
 from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
 
-from tests.common import async_fire_time_changed
+from tests.common import (
+    async_fire_time_changed,
+    async_mock_load_restore_state_from_storage,
+)
 
 IEEE_GROUPABLE_DEVICE = "01:2d:6f:00:0a:90:69:e8"
 IEEE_GROUPABLE_DEVICE2 = "02:2d:6f:00:0a:90:69:e9"
@@ -1921,3 +1924,76 @@ async def test_group_member_assume_state(
         await zha_gateway.async_remove_zigpy_group(zha_group.group_id)
         assert hass.states.get(group_entity_id) is None
         assert entity_registry.async_get(group_entity_id) is None
+
+
+@pytest.mark.parametrize(
+    ("restored_state", "expected_state"),
+    [
+        (
+            STATE_ON,
+            {
+                "brightness": None,
+                "off_with_transition": None,
+                "off_brightness": None,
+                "color_mode": ColorMode.XY,  # color_mode defaults to what the light supports when restored with ON state
+                "color_temp": None,
+                "xy_color": None,
+                "hs_color": None,
+                "effect": None,
+            },
+        ),
+        (
+            STATE_OFF,
+            {
+                "brightness": None,
+                "off_with_transition": None,
+                "off_brightness": None,
+                "color_mode": None,
+                "color_temp": None,
+                "xy_color": None,
+                "hs_color": None,
+                "effect": None,
+            },
+        ),
+    ],
+)
+async def test_restore_light_state(
+    hass: HomeAssistant,
+    zigpy_device_mock,
+    core_rs,
+    zha_device_restored,
+    restored_state,
+    expected_state,
+) -> None:
+    """Test ZHA light restores without throwing an error when attributes are None."""
+
+    # restore state with None values
+    attributes = {
+        "brightness": None,
+        "off_with_transition": None,
+        "off_brightness": None,
+        "color_mode": None,
+        "color_temp": None,
+        "xy_color": None,
+        "hs_color": None,
+        "effect": None,
+    }
+
+    entity_id = "light.fakemanufacturer_fakemodel_light"
+    core_rs(
+        entity_id,
+        state=restored_state,
+        attributes=attributes,
+    )
+    await async_mock_load_restore_state_from_storage(hass)
+
+    zigpy_device = zigpy_device_mock(LIGHT_COLOR)
+    zha_device = await zha_device_restored(zigpy_device)
+    entity_id = find_entity_id(Platform.LIGHT, zha_device, hass)
+
+    assert entity_id is not None
+    assert hass.states.get(entity_id).state == restored_state
+
+    # compare actual restored state to expected state
+    for attribute, expected_value in expected_state.items():
+        assert hass.states.get(entity_id).attributes.get(attribute) == expected_value

## Proposed change
This adds a regression test to make sure ZHA doesn't throw an exception when `None` attributes are restored for lights.

- The issue was originally discovered in: https://github.com/home-assistant/core/issues/102599
- A patch was made here: https://github.com/home-assistant/core/pull/102774
- The PR that caused this issue to appear in ZHA: https://github.com/home-assistant/core/pull/101946

I've moved the `core_rs` fixture from `test_binary_sensor.py` to `conftest.py` to also re-use it for the added test in `test_light.py`.

## Type of change

- [ ] Dependency upgrade
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New integration (thank you!)
- [ ] New feature (which adds functionality to an existing integration)
- [ ] Deprecation (breaking change to happen in the future)
- [ ] Breaking change (fix/feature causing existing functionality to break)
- [x] Code quality improvements to existing code or addition of tests

## Additional information

- This PR fixes or closes issue: fixes #
- This PR is related to issue: 
- Link to documentation pull request: 

## Checklist

- [ ] The code change is tested and works locally.
- [x] Local tests pass. **Your PR cannot be merged unless tests pass**
- [ ] There is no commented out code in this PR.
- [ ] I have followed the [development checklist][dev-checklist]
- [ ] I have followed the [perfect PR recommendations][perfect-pr]
- [ ] The code has been formatted using Black (`black --fast homeassistant tests`)
- [ ] Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

- [ ] Documentation added/updated for [www.home-assistant.io][docs-repository]

If the code communicates with devices, web services, or third-party tools:

- [ ] The [manifest file][manifest-docs] has all fields filled out correctly.  
      Updated and included derived files by running: `python3 -m script.hassfest`.
- [ ] New or updated dependencies have been added to `requirements_all.txt`.  
      Updated by running `python3 -m script.gen_requirements_all`.
- [ ] For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.
- [ ] Untested files have been added to `.coveragerc`.

To help with the load of incoming pull requests:

- [ ] I have reviewed two other [open pull requests][prs] in this repository.

[prs]: https://github.com/home-assistant/core/pulls?q=is%3Aopen+is%3Apr+-author%3A%40me+-draft%3Atrue+-label%3Awaiting-for-upstream+sort%3Acreated-desc+review%3Anone+-status%3Afailure

[dev-checklist]: https://developers.home-assistant.io/docs/development_checklist/
[manifest-docs]: https://developers.home-assistant.io/docs/creating_integration_manifest/
[quality-scale]: https://developers.home-assistant.io/docs/integration_quality_scale_index/
[docs-repository]: https://github.com/home-assistant/home-assistant.io
[perfect-pr]: https://developers.home-assistant.io/docs/review-process/#creating-the-perfect-pr
