From 22e72953e543ec3d5727f07d98c1668fc6d3d6a2 Mon Sep 17 00:00:00 2001
From: Marcel van der Veldt <m.vanderveldt@outlook.com>
Date: Tue, 28 Jan 2025 15:24:15 +0100
Subject: [PATCH] Adjust Matter discovery logic to disallow the primary
 value(s) to be None (#136712)

---
 homeassistant/components/matter/discovery.py | 9 ++++++++-
 homeassistant/components/matter/models.py    | 3 +++
 homeassistant/components/matter/number.py    | 8 ++++++++
 homeassistant/components/matter/select.py    | 2 ++
 homeassistant/components/matter/update.py    | 1 +
 homeassistant/components/matter/vacuum.py    | 1 +
 6 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/homeassistant/components/matter/discovery.py b/homeassistant/components/matter/discovery.py
index de03d250836..7ca64482763 100644
--- a/homeassistant/components/matter/discovery.py
+++ b/homeassistant/components/matter/discovery.py
@@ -4,7 +4,7 @@ from __future__ import annotations
 
 from collections.abc import Generator
 
-from chip.clusters.Objects import ClusterAttributeDescriptor
+from chip.clusters.ClusterObjects import ClusterAttributeDescriptor, NullValue
 from matter_server.client.models.node import MatterEndpoint
 
 from homeassistant.const import Platform
@@ -121,6 +121,13 @@ def async_discover_entities(
         ):
             continue
 
+        # check if value exists but is none/null
+        if not schema.allow_none_value and any(
+            endpoint.get_attribute_value(None, val_schema) in (None, NullValue)
+            for val_schema in schema.required_attributes
+        ):
+            continue
+
         # check for required value in (primary) attribute
         primary_attribute = schema.required_attributes[0]
         primary_value = endpoint.get_attribute_value(None, primary_attribute)
diff --git a/homeassistant/components/matter/models.py b/homeassistant/components/matter/models.py
index f1fd7ca9fa3..ea80d0eb903 100644
--- a/homeassistant/components/matter/models.py
+++ b/homeassistant/components/matter/models.py
@@ -128,3 +128,6 @@ class MatterDiscoverySchema:
     # [optional] bool to specify if this primary value may be discovered
     # by multiple platforms
     allow_multi: bool = False
+
+    # [optional] the primary attribute value may not be null/None
+    allow_none_value: bool = False
diff --git a/homeassistant/components/matter/number.py b/homeassistant/components/matter/number.py
index 4518e83e9d0..93b6b8f75c9 100644
--- a/homeassistant/components/matter/number.py
+++ b/homeassistant/components/matter/number.py
@@ -86,6 +86,8 @@ DISCOVERY_SCHEMAS = [
         ),
         entity_class=MatterNumber,
         required_attributes=(clusters.LevelControl.Attributes.OnLevel,),
+        # allow None value to account for 'default' value
+        allow_none_value=True,
     ),
     MatterDiscoverySchema(
         platform=Platform.NUMBER,
@@ -103,6 +105,8 @@ DISCOVERY_SCHEMAS = [
         ),
         entity_class=MatterNumber,
         required_attributes=(clusters.LevelControl.Attributes.OnTransitionTime,),
+        # allow None value to account for 'default' value
+        allow_none_value=True,
     ),
     MatterDiscoverySchema(
         platform=Platform.NUMBER,
@@ -120,6 +124,8 @@ DISCOVERY_SCHEMAS = [
         ),
         entity_class=MatterNumber,
         required_attributes=(clusters.LevelControl.Attributes.OffTransitionTime,),
+        # allow None value to account for 'default' value
+        allow_none_value=True,
     ),
     MatterDiscoverySchema(
         platform=Platform.NUMBER,
@@ -137,6 +143,8 @@ DISCOVERY_SCHEMAS = [
         ),
         entity_class=MatterNumber,
         required_attributes=(clusters.LevelControl.Attributes.OnOffTransitionTime,),
+        # allow None value to account for 'default' value
+        allow_none_value=True,
     ),
     MatterDiscoverySchema(
         platform=Platform.NUMBER,
diff --git a/homeassistant/components/matter/select.py b/homeassistant/components/matter/select.py
index 1018bed6af0..b10f4e0e484 100644
--- a/homeassistant/components/matter/select.py
+++ b/homeassistant/components/matter/select.py
@@ -267,6 +267,8 @@ DISCOVERY_SCHEMAS = [
         ),
         entity_class=MatterAttributeSelectEntity,
         required_attributes=(clusters.OnOff.Attributes.StartUpOnOff,),
+        # allow None value for previous state
+        allow_none_value=True,
     ),
     MatterDiscoverySchema(
         platform=Platform.SELECT,
diff --git a/homeassistant/components/matter/update.py b/homeassistant/components/matter/update.py
index f31dd7b3aa3..5ee9b2e5fa0 100644
--- a/homeassistant/components/matter/update.py
+++ b/homeassistant/components/matter/update.py
@@ -261,5 +261,6 @@ DISCOVERY_SCHEMAS = [
             clusters.OtaSoftwareUpdateRequestor.Attributes.UpdateState,
             clusters.OtaSoftwareUpdateRequestor.Attributes.UpdateStateProgress,
         ),
+        allow_none_value=True,
     ),
 ]
diff --git a/homeassistant/components/matter/vacuum.py b/homeassistant/components/matter/vacuum.py
index 511b32d3182..de4a885d8fb 100644
--- a/homeassistant/components/matter/vacuum.py
+++ b/homeassistant/components/matter/vacuum.py
@@ -208,5 +208,6 @@ DISCOVERY_SCHEMAS = [
             clusters.PowerSource.Attributes.BatPercentRemaining,
         ),
         device_type=(device_types.RoboticVacuumCleaner,),
+        allow_none_value=True,
     ),
 ]
-- 
GitLab