mirror of
https://github.com/Threnklyn/esphome-dev.git
synced 2026-05-25 23:28:28 +02:00
3c243e663f
* dashboard: fire events when entry is updated or state changes * dashboard: fire events when entry is updated or state changes * dashboard: fire events when entry is updated or state changes * tweaks * fixes * remove typing_extensions * rename for asyncio * rename for asyncio * rename for asyncio * preen * lint * lint * move dict converter * lint
113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
from esphome.zeroconf import (
|
|
ESPHOME_SERVICE_TYPE,
|
|
AsyncEsphomeZeroconf,
|
|
DashboardBrowser,
|
|
DashboardImportDiscovery,
|
|
DashboardStatus,
|
|
)
|
|
|
|
from ..const import SENTINEL
|
|
from ..core import DASHBOARD
|
|
from ..entries import bool_to_entry_state
|
|
|
|
|
|
class MDNSStatus:
|
|
"""Class that updates the mdns status."""
|
|
|
|
def __init__(self) -> None:
|
|
"""Initialize the MDNSStatus class."""
|
|
super().__init__()
|
|
self.aiozc: AsyncEsphomeZeroconf | None = None
|
|
# This is the current mdns state for each host (True, False, None)
|
|
self.host_mdns_state: dict[str, bool | None] = {}
|
|
# This is the hostnames to path mapping
|
|
self.host_name_to_path: dict[str, str] = {}
|
|
self.path_to_host_name: dict[str, str] = {}
|
|
# This is a set of host names to track (i.e no_mdns = false)
|
|
self.host_name_with_mdns_enabled: set[set] = set()
|
|
self._loop = asyncio.get_running_loop()
|
|
|
|
def get_path_to_host_name(self, path: str) -> str | None:
|
|
"""Resolve a path to an address in a thread-safe manner."""
|
|
return self.path_to_host_name.get(path)
|
|
|
|
async def async_resolve_host(self, host_name: str) -> str | None:
|
|
"""Resolve a host name to an address in a thread-safe manner."""
|
|
if aiozc := self.aiozc:
|
|
return await aiozc.async_resolve_host(host_name)
|
|
return None
|
|
|
|
async def async_refresh_hosts(self):
|
|
"""Refresh the hosts to track."""
|
|
dashboard = DASHBOARD
|
|
current_entries = dashboard.entries.async_all()
|
|
host_name_with_mdns_enabled = self.host_name_with_mdns_enabled
|
|
host_mdns_state = self.host_mdns_state
|
|
host_name_to_path = self.host_name_to_path
|
|
path_to_host_name = self.path_to_host_name
|
|
entries = dashboard.entries
|
|
|
|
for entry in current_entries:
|
|
name = entry.name
|
|
# If no_mdns is set, remove it from the set
|
|
if entry.no_mdns:
|
|
host_name_with_mdns_enabled.discard(name)
|
|
continue
|
|
|
|
# We are tracking this host
|
|
host_name_with_mdns_enabled.add(name)
|
|
path = entry.path
|
|
|
|
# If we just adopted/imported this host, we likely
|
|
# already have a state for it, so we should make sure
|
|
# to set it so the dashboard shows it as online
|
|
if (online := host_mdns_state.get(name, SENTINEL)) != SENTINEL:
|
|
entries.async_set_state(entry, bool_to_entry_state(online))
|
|
|
|
# Make sure the mapping is up to date
|
|
# so when we get an mdns update we can map it back
|
|
# to the filename
|
|
host_name_to_path[name] = path
|
|
path_to_host_name[path] = name
|
|
|
|
async def async_run(self) -> None:
|
|
dashboard = DASHBOARD
|
|
entries = dashboard.entries
|
|
aiozc = AsyncEsphomeZeroconf()
|
|
self.aiozc = aiozc
|
|
host_mdns_state = self.host_mdns_state
|
|
host_name_to_path = self.host_name_to_path
|
|
host_name_with_mdns_enabled = self.host_name_with_mdns_enabled
|
|
|
|
def on_update(dat: dict[str, bool | None]) -> None:
|
|
"""Update the entry state."""
|
|
for name, result in dat.items():
|
|
host_mdns_state[name] = result
|
|
if name not in host_name_with_mdns_enabled:
|
|
continue
|
|
if entry := entries.get(host_name_to_path[name]):
|
|
entries.async_set_state(entry, bool_to_entry_state(result))
|
|
|
|
stat = DashboardStatus(on_update)
|
|
imports = DashboardImportDiscovery()
|
|
dashboard.import_result = imports.import_state
|
|
|
|
browser = DashboardBrowser(
|
|
aiozc.zeroconf,
|
|
ESPHOME_SERVICE_TYPE,
|
|
[stat.browser_callback, imports.browser_callback],
|
|
)
|
|
|
|
while not dashboard.stop_event.is_set():
|
|
await self.async_refresh_hosts()
|
|
await dashboard.ping_request.wait()
|
|
dashboard.ping_request.clear()
|
|
|
|
await browser.async_cancel()
|
|
await aiozc.async_close()
|
|
self.aiozc = None
|