Support ignoring discovered devices from the dashboard (#7665)

This commit is contained in:
Jesse Hills 2024-10-25 07:55:14 +13:00 committed by GitHub
parent 5b5c2fe71b
commit ca5c73d170
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 0 deletions

View file

@ -5,10 +5,14 @@ from collections.abc import Coroutine
import contextlib
from dataclasses import dataclass
from functools import partial
import json
import logging
from pathlib import Path
import threading
from typing import TYPE_CHECKING, Any, Callable
from esphome.storage_json import ignored_devices_storage_path
from ..zeroconf import DiscoveredImport
from .dns import DNSCache
from .entries import DashboardEntries
@ -20,6 +24,8 @@ if TYPE_CHECKING:
_LOGGER = logging.getLogger(__name__)
IGNORED_DEVICES_STORAGE_PATH = "ignored-devices.json"
@dataclass
class Event:
@ -74,6 +80,7 @@ class ESPHomeDashboard:
"settings",
"dns_cache",
"_background_tasks",
"ignored_devices",
)
def __init__(self) -> None:
@ -89,12 +96,30 @@ class ESPHomeDashboard:
self.settings = DashboardSettings()
self.dns_cache = DNSCache()
self._background_tasks: set[asyncio.Task] = set()
self.ignored_devices: set[str] = set()
async def async_setup(self) -> None:
"""Setup the dashboard."""
self.loop = asyncio.get_running_loop()
self.ping_request = asyncio.Event()
self.entries = DashboardEntries(self)
self.load_ignored_devices()
def load_ignored_devices(self) -> None:
storage_path = Path(ignored_devices_storage_path())
try:
with storage_path.open("r", encoding="utf-8") as f_handle:
data = json.load(f_handle)
self.ignored_devices = set(data.get("ignored_devices", set()))
except FileNotFoundError:
pass
def save_ignored_devices(self) -> None:
storage_path = Path(ignored_devices_storage_path())
with storage_path.open("w", encoding="utf-8") as f_handle:
json.dump(
{"ignored_devices": sorted(self.ignored_devices)}, indent=2, fp=f_handle
)
async def async_run(self) -> None:
"""Run the dashboard."""

View file

@ -541,6 +541,46 @@ class ImportRequestHandler(BaseHandler):
self.finish()
class IgnoreDeviceRequestHandler(BaseHandler):
@authenticated
def post(self) -> None:
dashboard = DASHBOARD
try:
args = json.loads(self.request.body.decode())
device_name = args["name"]
ignore = args["ignore"]
except (json.JSONDecodeError, KeyError):
self.set_status(400)
self.set_header("content-type", "application/json")
self.write(json.dumps({"error": "Invalid payload"}))
return
ignored_device = next(
(
res
for res in dashboard.import_result.values()
if res.device_name == device_name
),
None,
)
if ignored_device is None:
self.set_status(404)
self.set_header("content-type", "application/json")
self.write(json.dumps({"error": "Device not found"}))
return
if ignore:
dashboard.ignored_devices.add(ignored_device.device_name)
else:
dashboard.ignored_devices.discard(ignored_device.device_name)
dashboard.save_ignored_devices()
self.set_status(204)
self.finish()
class DownloadListRequestHandler(BaseHandler):
@authenticated
@bind_config
@ -688,6 +728,7 @@ class ListDevicesHandler(BaseHandler):
"project_name": res.project_name,
"project_version": res.project_version,
"network": res.network,
"ignored": res.device_name in dashboard.ignored_devices,
}
for res in dashboard.import_result.values()
if res.device_name not in configured
@ -1156,6 +1197,7 @@ def make_app(debug=get_bool_env(ENV_DEV)) -> tornado.web.Application:
(f"{rel}prometheus-sd", PrometheusServiceDiscoveryHandler),
(f"{rel}boards/([a-z0-9]+)", BoardsRequestHandler),
(f"{rel}version", EsphomeVersionHandler),
(f"{rel}ignore-device", IgnoreDeviceRequestHandler),
],
**app_settings,
)

View file

@ -28,6 +28,10 @@ def esphome_storage_path() -> str:
return os.path.join(CORE.data_dir, "esphome.json")
def ignored_devices_storage_path() -> str:
return os.path.join(CORE.data_dir, "ignored-devices.json")
def trash_storage_path() -> str:
return CORE.relative_config_path("trash")