Skip to content

Commit 6669709

Browse files
Fix Nullable values in write attributes procedure (#566)
Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
1 parent e9f8540 commit 6669709

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

matter_server/common/helpers/util.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,13 @@ def parse_value(
108108
value_type: Any,
109109
default: Any = MISSING,
110110
allow_none: bool = True,
111+
allow_sdk_types: bool = False,
111112
) -> Any:
112-
"""Try to parse a value from raw (json) data and type annotations."""
113+
"""
114+
Try to parse a value from raw (json) data and type annotations.
115+
116+
If allow_sdk_types is False, any SDK specific custom data types will be converted.
117+
"""
113118
# pylint: disable=too-many-return-statements,too-many-branches
114119

115120
if isinstance(value_type, str):
@@ -131,9 +136,9 @@ def parse_value(
131136
return default
132137
if value is None and value_type is NoneType:
133138
return None
134-
if value is None and allow_none:
135-
return None
136139
if value is None and value_type is Nullable:
140+
return Nullable() if allow_sdk_types else None
141+
if value is None and allow_none:
137142
return None
138143
if is_dataclass(value_type) and isinstance(value, dict):
139144
return dataclass_from_dict(value_type, value)
@@ -220,12 +225,12 @@ def parse_value(
220225
if value_type is uint and (
221226
isinstance(value, int) or (isinstance(value, str) and value.isnumeric())
222227
):
223-
return uint(value)
228+
return uint(value) if allow_sdk_types else int(value)
224229
if value_type is float32 and (
225230
isinstance(value, (float, int))
226231
or (isinstance(value, str) and value.isnumeric())
227232
):
228-
return float32(value)
233+
return float32(value) if allow_sdk_types else float(value)
229234

230235
# If we reach this point, we could not match the value with the type and we raise
231236
if not isinstance(value, value_type):
@@ -236,7 +241,9 @@ def parse_value(
236241
return value
237242

238243

239-
def dataclass_from_dict(cls: type[_T], dict_obj: dict, strict: bool = False) -> _T:
244+
def dataclass_from_dict(
245+
cls: type[_T], dict_obj: dict, strict: bool = False, allow_sdk_types: bool = False
246+
) -> _T:
240247
"""
241248
Create (instance of) a dataclass by providing a dict with values.
242249
@@ -259,6 +266,7 @@ def dataclass_from_dict(cls: type[_T], dict_obj: dict, strict: bool = False) ->
259266
type_hints[field.name],
260267
field.default,
261268
allow_none=not strict,
269+
allow_sdk_types=allow_sdk_types,
262270
)
263271
for field in dc_fields
264272
if field.init

matter_server/server/device_controller.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
dataclass_from_dict,
3838
dataclass_to_dict,
3939
parse_attribute_path,
40+
parse_value,
4041
)
4142
from ..common.models import (
4243
APICommand,
@@ -529,7 +530,7 @@ async def send_device_command(
529530
raise NodeNotReady(f"Node {node_id} is not (yet) available.")
530531
cluster_cls: Cluster = ALL_CLUSTERS[cluster_id]
531532
command_cls = getattr(cluster_cls.Commands, command_name)
532-
command = dataclass_from_dict(command_cls, payload)
533+
command = dataclass_from_dict(command_cls, payload, allow_sdk_types=True)
533534
node_lock = self._get_node_lock(node_id)
534535
async with node_lock:
535536
return await self.chip_controller.SendCommand(
@@ -592,8 +593,16 @@ async def write_attribute(
592593
if (node := self._nodes.get(node_id)) is None or not node.available:
593594
raise NodeNotReady(f"Node {node_id} is not (yet) available.")
594595
endpoint_id, cluster_id, attribute_id = parse_attribute_path(attribute_path)
595-
attribute = ALL_ATTRIBUTES[cluster_id][attribute_id]()
596-
attribute.value = Clusters.NullValue if value is None else value
596+
attribute = cast(
597+
Clusters.ClusterAttributeDescriptor,
598+
ALL_ATTRIBUTES[cluster_id][attribute_id](),
599+
)
600+
attribute.value = parse_value(
601+
name=attribute_path,
602+
value=value,
603+
value_type=attribute.attribute_type.Type,
604+
allow_sdk_types=True,
605+
)
597606
return await self.chip_controller.WriteAttribute(
598607
nodeid=node_id,
599608
attributes=[(endpoint_id, attribute)],

0 commit comments

Comments
 (0)