Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import json
import logging
import pathlib
import re
import time
from typing import Any
from unittest.mock import AsyncMock
Expand Down Expand Up @@ -683,12 +684,34 @@ def create_mock_zigpy_device(
return device


# Types whose `repr` is a bytes literal
JSON_BYTES_TYPES = frozenset(
{
"<class 'bytes'>",
"<class 'zigpy.types.basic.LVBytes'>",
"<class 'zigpy.types.basic.LimitedLVBytes.<locals>.LimitedLVBytes'>",
"<class 'sonoff_tp_wgzba.RawBytes'>",
"<class 'sonoff_tp_wgzba.Uint8ArrayPayload'>",
}
)
JSON_ARRAY_TYPE = "<class 'zigpy.zcl.foundation.Array'>"
ARRAY_REPR_REGEX = re.compile(r"Array\(type=\w+, value=(?P<value>\[.*\])\)")


def decode_json_value(value: Any) -> Any:
"""Decode a value encoded by Home Assistant diagnostics or `ZhaJsonEncoder`."""
if isinstance(value, dict) and value.keys() == {"__type", "repr"}:
if not (isinstance(value, dict) and value.keys() == {"__type", "repr"}):
return value

if value["__type"] in JSON_BYTES_TYPES:
return ast.literal_eval(value["repr"])

return value
if value["__type"] == JSON_ARRAY_TYPE:
# The element type is lost, only the elements can be recovered
match = ARRAY_REPR_REGEX.fullmatch(value["repr"])
return ast.literal_eval(match.group("value"))
Comment thread
puddly marked this conversation as resolved.
Resolved

raise ValueError(f"Cannot decode JSON value: {value!r}")


class ZhaJsonEncoder(json.JSONEncoder):
Expand Down
320 changes: 320 additions & 0 deletions tests/data/devices/a89g12c-arteco.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
{
"version": 3,
"ieee": "ab:cd:ef:12:34:84:4b:90",
"nwk": "0xC88F",
"manufacturer": "A89G12C",
"model": "Arteco",
"friendly_manufacturer": "A89G12C",
"friendly_model": "Arteco",
"name": "A89G12C Arteco",
"quirk_applied": false,
"quirk_class": "zigpy.device.ZigbeeDevice",
"exposes_features": [],
"manufacturer_code": 4417,
"power_source": "Battery or Unknown",
"lqi": 160,
"rssi": -60,
"last_seen": "2026-07-17T06:47:06.492194+00:00",
"available": true,
"device_type": "EndDevice",
"active_coordinator": false,
"node_descriptor": {
"logical_type": "EndDevice",
"complex_descriptor_available": false,
"user_descriptor_available": false,
"reserved": 0,
"aps_flags": 0,
"frequency_band": 8,
"mac_capability_flags": 128,
"manufacturer_code": 4417,
"maximum_buffer_size": 74,
"maximum_incoming_transfer_size": 404,
"server_mask": 10752,
"maximum_outgoing_transfer_size": 404,
"descriptor_capability_field": 0
},
"endpoints": {
"1": {
"profile_id": 260,
"device_type": {
"name": "TEMPERATURE_SENSOR",
"id": 770
},
"in_clusters": [
{
"cluster_id": "0x0000",
"endpoint_attribute": "basic",
"attributes": [
{
"id": "0x0004",
"name": "manufacturer",
"zcl_type": "string",
"value": "A89G12C"
},
{
"id": "0x0005",
"name": "model",
"zcl_type": "string",
"value": "Arteco"
}
]
},
{
"cluster_id": "0x0001",
"endpoint_attribute": "power",
"attributes": [
{
"id": "0x0021",
"name": "battery_percentage_remaining",
"zcl_type": "uint8",
"value": 186
},
{
"id": "0x0020",
"name": "battery_voltage",
"zcl_type": "uint8",
"value": 30
}
]
},
{
"cluster_id": "0x0003",
"endpoint_attribute": "identify",
"attributes": []
},
{
"cluster_id": "0x0402",
"endpoint_attribute": "temperature",
"attributes": [
{
"id": "0x0000",
"name": "measured_value",
"zcl_type": "int16",
"value": 2690
}
]
},
{
"cluster_id": "0x0405",
"endpoint_attribute": "humidity",
"attributes": []
},
{
"cluster_id": "0xef00",
"endpoint_attribute": null,
"attributes": []
}
],
"out_clusters": [
{
"cluster_id": "0x0003",
"endpoint_attribute": "identify",
"attributes": []
},
{
"cluster_id": "0x1000",
"endpoint_attribute": "lightlink",
"attributes": []
},
{
"cluster_id": "0xef00",
"endpoint_attribute": null,
"attributes": []
}
]
}
},
"original_signature": {
"manufacturer": "A89G12C",
"model": "Arteco",
"node_desc": {
"logical_type": 2,
"complex_descriptor_available": 0,
"user_descriptor_available": 0,
"reserved": 0,
"aps_flags": 0,
"frequency_band": 8,
"mac_capability_flags": 128,
"manufacturer_code": 4417,
"maximum_buffer_size": 74,
"maximum_incoming_transfer_size": 404,
"server_mask": 10752,
"maximum_outgoing_transfer_size": 404,
"descriptor_capability_field": 0
},
"endpoints": {
"1": {
"profile_id": "0x0104",
"device_type": "0x0302",
"input_clusters": [
"0x0000",
"0x0003",
"0xef00",
"0x0402",
"0x0405",
"0x0001"
],
"output_clusters": [
"0x0003",
"0xef00",
"0x1000"
]
}
}
},
"zha_lib_entities": {
"button": [
{
"fallback_name": null,
"unique_id": "ab:cd:ef:12:34:84:4b:90-1-3",
"migrate_unique_ids": [],
"platform": "button",
"class_name": "IdentifyButton",
"translation_key": null,
"translation_placeholders": null,
"device_class": "identify",
"state_class": null,
"entity_category": "diagnostic",
"entity_registry_enabled_default": true,
"enabled": true,
"primary": false,
"extra_state_attribute_names": [],
"device_ieee": "ab:cd:ef:12:34:84:4b:90",
"endpoint_id": 1,
"available": true,
"group_id": null,
"command": "identify",
"args": [
5
],
"kwargs": {}
}
],
"sensor": [
{
"fallback_name": null,
"unique_id": "ab:cd:ef:12:34:84:4b:90-1-0-lqi",
"migrate_unique_ids": [],
"platform": "sensor",
"class_name": "LQISensor",
"translation_key": "lqi",
"translation_placeholders": null,
"device_class": null,
"state_class": "measurement",
"entity_category": "diagnostic",
"entity_registry_enabled_default": false,
"enabled": true,
"primary": false,
"extra_state_attribute_names": [],
"device_ieee": "ab:cd:ef:12:34:84:4b:90",
"endpoint_id": null,
Comment thread
puddly marked this conversation as resolved.
Resolved
"available": true,
"group_id": null,
"native_value": 160,
"suggested_display_precision": null,
"unit": null
},
{
"fallback_name": null,
"unique_id": "ab:cd:ef:12:34:84:4b:90-1-0-rssi",
"migrate_unique_ids": [],
"platform": "sensor",
"class_name": "RSSISensor",
"translation_key": "rssi",
"translation_placeholders": null,
"device_class": "signal_strength",
"state_class": "measurement",
"entity_category": "diagnostic",
"entity_registry_enabled_default": false,
"enabled": true,
"primary": false,
"extra_state_attribute_names": [],
"device_ieee": "ab:cd:ef:12:34:84:4b:90",
"endpoint_id": null,
"available": true,
"group_id": null,
"native_value": -60,
"suggested_display_precision": null,
"unit": "dBm"
},
{
"fallback_name": null,
"unique_id": "ab:cd:ef:12:34:84:4b:90-1-1",
"migrate_unique_ids": [],
"platform": "sensor",
"class_name": "Battery",
"translation_key": null,
"translation_placeholders": null,
"device_class": "battery",
"state_class": "measurement",
"entity_category": "diagnostic",
"entity_registry_enabled_default": true,
"enabled": true,
"primary": false,
"extra_state_attribute_names": [
"battery_quantity",
"battery_size",
"battery_voltage"
],
"device_ieee": "ab:cd:ef:12:34:84:4b:90",
"endpoint_id": 1,
"available": true,
"group_id": null,
"native_value": 93.0,
"suggested_display_precision": 0,
"unit": "%",
"battery_size": null,
"battery_quantity": null,
"battery_voltage": 3.0
},
{
"fallback_name": null,
"unique_id": "ab:cd:ef:12:34:84:4b:90-1-1026",
"migrate_unique_ids": [],
"platform": "sensor",
"class_name": "Temperature",
"translation_key": null,
"translation_placeholders": null,
"device_class": "temperature",
"state_class": "measurement",
"entity_category": null,
"entity_registry_enabled_default": true,
"enabled": true,
"primary": false,
"extra_state_attribute_names": [],
"device_ieee": "ab:cd:ef:12:34:84:4b:90",
"endpoint_id": 1,
"available": true,
"group_id": null,
"native_value": 26.9,
"suggested_display_precision": null,
"unit": "\u00b0C"
},
{
"fallback_name": null,
"unique_id": "ab:cd:ef:12:34:84:4b:90-1-1029",
"migrate_unique_ids": [],
"platform": "sensor",
"class_name": "Humidity",
"translation_key": null,
"translation_placeholders": null,
"device_class": "humidity",
"state_class": "measurement",
"entity_category": null,
"entity_registry_enabled_default": true,
"enabled": true,
"primary": false,
"extra_state_attribute_names": [],
"device_ieee": "ab:cd:ef:12:34:84:4b:90",
"endpoint_id": 1,
"available": true,
"group_id": null,
"native_value": null,
"suggested_display_precision": null,
"unit": "%"
}
]
},
"neighbors": [],
"routes": []
}
Loading
Loading