Two fixes for issue #9 (WW90T634DHE washer): - washer dosing selects: the four detergent/softener dosing selects read their current value from `<Prefix>LevelCtrl_<code>` (un-padded, e.g. "3") but their options from `Supported<Prefix>LevelCtrl_<hexpairs>` (zero-padded, e.g. "03"). HA's SelectEntity renders a select "unknown" whenever current_option is not in options, so all four sat "unknown" (idle and running) even though every other select worked -- which is why it was only those four. Normalize the current value to the supported code with the same integer value so it matches an option (and its translation); convert back to the device's native un-padded format on write. - diagnostics: pkg_version("smartthings-local") reads package metadata off disk (listdir + open + read_text), tripping HA's event-loop blocking-call detector. Offload it to the executor. Audited the rest of the package: config_flow's socket/crypto and every coordinator DTLS call are already offloaded via async_add_executor_job -- this was the only blocking call left on the loop. Also documents air-conditioner support in the README (device table, capability module list, platform list), missed when that support landed. Updates the washer dosing tests to the corrected value/write format and adds a current-option-is-a-valid-option regression; adds a diagnostics test asserting the version lookup runs off the event loop.
50 lines
2.1 KiB
Python
50 lines
2.1 KiB
Python
"""Diagnostics support for Local Things.
|
|
|
|
Downloadable from Settings > Devices & Services > this integration's
|
|
device > the menu > Download diagnostics. This is what the Repairs issue
|
|
(raised in coordinator.py when capability coverage is incomplete) points
|
|
users at: a redacted snapshot of the device's raw /device/0 state, plus
|
|
enough version/coverage metadata to reproduce and diagnose the gap.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from importlib.metadata import version as pkg_version
|
|
from typing import Any
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.loader import async_get_integration
|
|
|
|
from .const import DOMAIN
|
|
from .coordinator import LocalThingsCoordinator
|
|
from .registry.redact import redact_resources
|
|
|
|
|
|
async def async_get_config_entry_diagnostics(
|
|
hass: HomeAssistant, entry: ConfigEntry
|
|
) -> dict[str, Any]:
|
|
coordinator: LocalThingsCoordinator = hass.data[DOMAIN][entry.entry_id]
|
|
integration = await async_get_integration(hass, DOMAIN)
|
|
|
|
# importlib.metadata.version() reads the installed package's metadata off
|
|
# disk (listdir + open + read_text), which trips HA's event-loop blocking
|
|
# detector when called inline here. Offload it to the executor.
|
|
stl_version = await hass.async_add_executor_job(pkg_version, "smartthings-local")
|
|
|
|
return {
|
|
"device_type": coordinator.device_type_name or "unknown",
|
|
"one_ui_version": coordinator.one_ui_version,
|
|
"unbound_hrefs": sorted(coordinator._unbound_hrefs),
|
|
"resources": redact_resources(coordinator.last_resources),
|
|
"integration_version": integration.version,
|
|
"smartthings_local_version": stl_version,
|
|
"observe_mode": coordinator.observe_mode,
|
|
"observe_subscribed_hrefs": sorted(coordinator._observe.subscribed_hrefs),
|
|
"observe_fallback_hrefs": sorted(coordinator._observe.fallback_hrefs),
|
|
"observe_last_mode_change": coordinator._observe.last_mode_change_wall,
|
|
"observe_href_freshness_s": {
|
|
href: coordinator._cache.freshness_s(href)
|
|
for href in coordinator._observe.subscribed_hrefs
|
|
},
|
|
}
|