A new plugin reads Home Assistant with a read-only token every 5 minutes and shows which Core, OS and add-on updates are waiting and how old the last backup is. Install takes a backup through a local-only webhook, confirms Home Assistant's last-backup time moved, installs, and follows the update to its end, through Home Assistant's and Steward's own restarts. One runs at a time. Each ends as one timeline entry. Steward holds nothing that can act on the house: the webhook's automation can only take a backup or install an allowed update (System 231's ruling). A refused token stops polling, as Home Assistant bans an address after a few refusals. Milestone 576 steps 1 to 5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
1.1 KiB
Python
46 lines
1.1 KiB
Python
# plugins/homeassistant/__init__.py
|
|
from __future__ import annotations
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from quart import Quart
|
|
|
|
_app: "Quart | None" = None
|
|
|
|
|
|
def setup(app: "Quart") -> None:
|
|
global _app
|
|
_app = app
|
|
from .models import HomeAssistantConnection, HomeAssistantUpdate # noqa: F401 — registers the tables
|
|
from .timeline import register
|
|
register()
|
|
|
|
|
|
def get_scheduled_tasks() -> list:
|
|
from .scheduler import make_tick_task
|
|
return [make_tick_task(_app)]
|
|
|
|
|
|
def get_blueprint():
|
|
from .routes import homeassistant_bp
|
|
return homeassistant_bp
|
|
|
|
|
|
def get_nav() -> list[dict]:
|
|
return [{"label": "Home Assistant", "href": "/plugins/homeassistant/"}]
|
|
|
|
|
|
def get_alert_metrics() -> dict[str, list[str]]:
|
|
"""What the poll records, all under the resource "homeassistant"."""
|
|
return {"homeassistant": ["is_up", "backup_age_hours", "updates_waiting"]}
|
|
|
|
|
|
def register_mcp_tools(register) -> None:
|
|
from .mcp_tools import register_tools
|
|
register_tools(register)
|
|
|
|
|
|
async def mcp_overview(db) -> list[dict]:
|
|
from .mcp_tools import mcp_overview as findings
|
|
return await findings(db)
|