Files
core/homeassistant/components/zha/diagnostics.py
puddly 8760a82dfa Bump ZHA to 0.0.57 (#143963)
* Use new (internal) cluster handler IDs in unit tests

* Always add a profile_id to created endpoints

* Use new library decimal formatting

* Implement the ENUM device class for sensors

* Use the suggested display precision hint

* Revert "Implement the ENUM device class for sensors"

This reverts commit d11ab268121b7ffe67c81e45fdc46004fb57a22a.

* Bump ZHA to 0.0.57

* Add strings for v2 quirk entities

* Use ZHA library diagnostics

* Update snapshot

* Revert ZHA change that reports a cover state of `open` if either lift or tilt axes are `open`

This is an interim change to address issues with some cover 'relay' type devices which falsely report support for both lift and tilt. In reality these only support one axes or the other, with users using yaml overrides to restrict functionality in HA.

Devices that genuinely support both movement axes will behave the same as they did prior to https://github.com/zigpy/zha/pull/376
https://github.com/home-assistant/core/pull/141447

A subsequent PR will be made to allow users to override the covering type in a way that allows the entity handler to be aware of the configuration, calculating the state accordingly.

* Spelling mistake

---------

Co-authored-by: TheJulianJES <TheJulianJES@users.noreply.github.com>
Co-authored-by: Jack <46714706+jeverley@users.noreply.github.com>
2025-04-30 19:43:38 +02:00

116 lines
3.5 KiB
Python

"""Provides diagnostics for ZHA."""
from __future__ import annotations
import dataclasses
from importlib.metadata import version
from typing import Any
from zha.application.const import ATTR_IEEE
from zha.application.gateway import Gateway
from zigpy.config import CONF_NWK_EXTENDED_PAN_ID
from zigpy.types import Channels
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_UNIQUE_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from .const import CONF_ALARM_MASTER_CODE
from .helpers import (
ZHADeviceProxy,
async_get_zha_device_proxy,
get_zha_data,
get_zha_gateway,
)
KEYS_TO_REDACT = {
ATTR_IEEE,
CONF_UNIQUE_ID,
CONF_ALARM_MASTER_CODE,
"network_key",
CONF_NWK_EXTENDED_PAN_ID,
"partner_ieee",
"device_ieee",
}
ATTRIBUTES = "attributes"
CLUSTER_DETAILS = "cluster_details"
UNSUPPORTED_ATTRIBUTES = "unsupported_attributes"
BELLOWS_VERSION = version("bellows")
ZIGPY_VERSION = version("zigpy")
ZIGPY_DECONZ_VERSION = version("zigpy-deconz")
ZIGPY_XBEE_VERSION = version("zigpy-xbee")
ZIGPY_ZNP_VERSION = version("zigpy-znp")
ZIGPY_ZIGATE_VERSION = version("zigpy-zigate")
ZHA_QUIRKS_VERSION = version("zha-quirks")
ZHA_VERSION = version("zha")
def shallow_asdict(obj: Any) -> dict:
"""Return a shallow copy of a dataclass as a dict."""
if hasattr(obj, "__dataclass_fields__"):
result = {}
for field in dataclasses.fields(obj):
result[field.name] = shallow_asdict(getattr(obj, field.name))
return result
if hasattr(obj, "as_dict"):
return obj.as_dict()
return obj
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
zha_data = get_zha_data(hass)
gateway: Gateway = get_zha_gateway(hass)
app = gateway.application_controller
energy_scan = await app.energy_scan(
channels=Channels.ALL_CHANNELS, duration_exp=4, count=1
)
return async_redact_data(
{
"config": zha_data.yaml_config,
"config_entry": config_entry.as_dict(),
"application_state": shallow_asdict(app.state),
"energy_scan": {
channel: 100 * energy / 255 for channel, energy in energy_scan.items()
},
"versions": {
"bellows": BELLOWS_VERSION,
"zigpy": ZIGPY_VERSION,
"zigpy_deconz": ZIGPY_DECONZ_VERSION,
"zigpy_xbee": ZIGPY_XBEE_VERSION,
"zigpy_znp": ZIGPY_ZNP_VERSION,
"zigpy_zigate": ZIGPY_ZIGATE_VERSION,
"zhaquirks": ZHA_QUIRKS_VERSION,
"zha": ZHA_VERSION,
},
"devices": [
{
"manufacturer": device.manufacturer,
"model": device.model,
"logical_type": device.device_type,
}
for device in gateway.devices.values()
],
},
KEYS_TO_REDACT,
)
async def async_get_device_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry, device: dr.DeviceEntry
) -> dict[str, Any]:
"""Return diagnostics for a device."""
zha_device_proxy: ZHADeviceProxy = async_get_zha_device_proxy(hass, device.id)
diagnostics_json: dict[str, Any] = zha_device_proxy.device.get_diagnostics_json()
return async_redact_data(diagnostics_json, KEYS_TO_REDACT)