Die IP ist der Wert, den man beim Suchen einer Lampe zuerst braucht - als abgeschaltete Diagnose-Entitaet war sie genau dann nicht da.
85 lines
3.6 KiB
Python
85 lines
3.6 KiB
Python
"""Diagnostic sensors."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import timedelta
|
|
from typing import Any
|
|
|
|
from freezegun.api import FrozenDateTimeFactory
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers import entity_registry as er
|
|
from homeassistant.util import dt as dt_util
|
|
from pytest_homeassistant_custom_component.common import MockConfigEntry, async_fire_time_changed
|
|
|
|
from tests.helpers import entity_id_for
|
|
|
|
DISABLED_KEYS = ("free_heap", "last_ota_error", "boot_time")
|
|
|
|
|
|
async def _enable_all(
|
|
hass: HomeAssistant, entry: MockConfigEntry, freezer: FrozenDateTimeFactory
|
|
) -> None:
|
|
registry = er.async_get(hass)
|
|
for key in DISABLED_KEYS:
|
|
registry.async_update_entity(entity_id_for(hass, "sensor", key), disabled_by=None)
|
|
await hass.config_entries.async_reload(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
# HA 2026.9: registry.async_update_entity(disabled_by=None) also arms the config entry's
|
|
# own debounced reload (config_entries.RELOAD_AFTER_UPDATE_DELAY = 30 s), independent of
|
|
# the explicit reload above. Left alone, that second reload fires mid-test - typically
|
|
# right on top of the first _poll() below - and silently replaces the boot-time entity,
|
|
# defeating the jitter-tolerance assertion. Drain it here so the entities are settled
|
|
# before the test takes its "first" reading.
|
|
freezer.tick(timedelta(seconds=31))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
async def _poll(hass: HomeAssistant, freezer: FrozenDateTimeFactory, seconds: int) -> None:
|
|
freezer.tick(timedelta(seconds=seconds))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
async def test_signal_and_ip_enabled_others_disabled_by_default(
|
|
hass: HomeAssistant, init_integration
|
|
) -> None:
|
|
registry = er.async_get(hass)
|
|
assert hass.states.get(entity_id_for(hass, "sensor", "rssi")).state == "-61"
|
|
assert hass.states.get(entity_id_for(hass, "sensor", "ip_address")).state == "192.168.2.22"
|
|
for key in DISABLED_KEYS:
|
|
entry = registry.async_get(entity_id_for(hass, "sensor", key))
|
|
assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION, key
|
|
|
|
|
|
async def test_diagnostic_values(
|
|
hass: HomeAssistant, init_integration: MockConfigEntry, freezer
|
|
) -> None:
|
|
await _enable_all(hass, init_integration, freezer)
|
|
assert hass.states.get(entity_id_for(hass, "sensor", "ip_address")).state == "192.168.2.22"
|
|
assert hass.states.get(entity_id_for(hass, "sensor", "free_heap")).state == "119872"
|
|
assert hass.states.get(entity_id_for(hass, "sensor", "last_ota_error")).state == "unknown"
|
|
expected_boot = dt_util.utcnow() - timedelta(seconds=129832)
|
|
boot = dt_util.parse_datetime(hass.states.get(entity_id_for(hass, "sensor", "boot_time")).state)
|
|
assert abs((boot - expected_boot).total_seconds()) < 2
|
|
|
|
|
|
async def test_boot_time_ignores_jitter_but_follows_reboots(
|
|
hass: HomeAssistant,
|
|
init_integration: MockConfigEntry,
|
|
lamp_info: dict[str, Any],
|
|
freezer: FrozenDateTimeFactory,
|
|
) -> None:
|
|
await _enable_all(hass, init_integration, freezer)
|
|
entity_id = entity_id_for(hass, "sensor", "boot_time")
|
|
first = hass.states.get(entity_id).state
|
|
|
|
lamp_info["uptime"] += 31 + 20 # clock drift of 20 s: below the 60 s threshold
|
|
await _poll(hass, freezer, 31)
|
|
assert hass.states.get(entity_id).state == first
|
|
|
|
lamp_info["uptime"] = 12 # the lamp rebooted
|
|
await _poll(hass, freezer, 31)
|
|
rebooted = dt_util.parse_datetime(hass.states.get(entity_id).state)
|
|
assert abs((rebooted - (dt_util.utcnow() - timedelta(seconds=12))).total_seconds()) < 2
|