Skip to content
Prev Previous commit
Next Next commit
Also deserialize objects after restart
  • Loading branch information
TheJulianJES committed Mar 16, 2026
commit 22a0983290d19ff30e436fa5c2d44c87d1dc6c6c
12 changes: 12 additions & 0 deletions tests/test_appdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,18 @@ class AttributeDefs(BaseAttributeDefs):
assert isinstance(row[0], bytes)
assert row[0] == test_value.serialize()

# Load the database again and verify the value is deserialized back
app2 = await make_app_with_db(db)
dev2 = app2.get_device(t.EUI64.convert("00:1f:ee:00:00:00:96:f5"))
ubisys2 = dev2.endpoints[232].in_clusters[0xFC00]

loaded_value = ubisys2.get_cached_value(
UbisysCluster.AttributeDefs.output_configurations
)
assert list(loaded_value) == list(test_value)

await app2.shutdown()


def test_save_attribute_cache_skips_unserializable() -> None:
"""Test that _serialize_for_db raises ValueError for unserializable types,
Expand Down
26 changes: 25 additions & 1 deletion zigpy/appdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,30 @@ def _serialize_for_db(value: Any) -> None | int | float | str | bytes:
)


def _deserialize_from_db(value: Any, attr_type: type | None) -> Any:
"""Attempt to deserialize a bytes value loaded from the database back into its
original ZCL type, if applicable.
"""
if (
not isinstance(value, bytes)
or attr_type is None
or not hasattr(attr_type, "deserialize")
or issubclass(attr_type, bytes)
):
return value

try:
result, _ = attr_type.deserialize(value) # type: ignore[attr-defined]
except (ValueError, KeyError):
LOGGER.debug(
"Failed to deserialize cached value for type %s, using raw bytes",
attr_type,
)
return value

return result


def decode_str_attribute(value: str | bytes) -> str:
if isinstance(value, str):
return value
Expand Down Expand Up @@ -880,7 +904,7 @@ async def _populate_attribute_cache(
if row.status == Status.SUCCESS:
cluster._attr_cache.set_value(
attr_def,
row.value,
_deserialize_from_db(row.value, attr_def.type),
last_updated=datetime.fromtimestamp(row.last_updated, UTC),
)
else:
Expand Down