Files
HomeAssistantVS/custom_components/maintenance_supporter/websocket/battery_fleet.py
T
2026-07-21 11:19:17 -04:00

88 lines
3.4 KiB
Python

"""WebSocket commands for the Battery Fleet.
``battery_fleet/overview`` (read) returns the live aggregated view — low now,
grouped shopping needs, forecast — for the fleet task's detail. ``setup``
(admin write) creates the fleet object + type-parts + the single task.
"""
from __future__ import annotations
from typing import Any
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant
from ..const import DOMAIN, MAX_ENTITY_ID_LENGTH
from ..helpers.battery_fleet import compute_overview, has_batteries, has_battery_notes
from ..helpers.battery_fleet_setup import (
async_mark_replaced,
async_setup_battery_fleet,
find_fleet_entry,
fleet_task_trigger_ok,
)
from ..helpers.permissions import require_write
@websocket_api.websocket_command({vol.Required("type"): f"{DOMAIN}/battery_fleet/overview"})
@websocket_api.async_response
async def ws_battery_fleet_overview(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any]) -> None:
"""Return the live fleet overview (low now, needs grouped, forecast)."""
ov = compute_overview(hass)
fleet = find_fleet_entry(hass)
connection.send_result(
msg["id"],
{
"available": has_batteries(hass),
"has_battery_notes": has_battery_notes(hass),
"configured": fleet is not None,
# False when the fleet task was deleted or its trigger was wiped
# (issue #106) — the detail section offers a one-click repair,
# which re-runs the idempotent setup.
"task_ok": fleet is not None and fleet_task_trigger_ok(fleet),
"entry_id": fleet.entry_id if fleet else None,
"total": ov.total,
"low": ov.low,
"soon": ov.soon,
"needs_now": dict(ov.needs_now),
"needs_soon": dict(ov.needs_soon),
"types": ov.types,
},
)
@websocket_api.websocket_command(
{
vol.Required("type"): f"{DOMAIN}/battery_fleet/setup",
# The caller's UI language (same contract as the template WS) —
# the created object/task/part names are localized through _T.
vol.Optional("language"): vol.All(str, vol.Length(max=10)),
}
)
@require_write
@websocket_api.async_response
async def ws_battery_fleet_setup(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any]) -> None:
"""Create (or reconcile) the Battery Fleet object + type-parts + task."""
if not has_batteries(hass):
connection.send_error(msg["id"], "not_available", "No battery devices found")
return
result = await async_setup_battery_fleet(hass, language=msg.get("language"))
connection.send_result(msg["id"], result)
@websocket_api.websocket_command(
{
vol.Required("type"): f"{DOMAIN}/battery_fleet/mark_replaced",
# battery_plus entity_ids to mark; omit to mark ALL currently low.
vol.Optional("entity_ids"): [vol.All(str, vol.Length(max=MAX_ENTITY_ID_LENGTH))],
}
)
@require_write
@websocket_api.async_response
async def ws_battery_fleet_mark_replaced(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any]
) -> None:
"""Mark batteries replaced (press their button + consume the type-parts)."""
result = await async_mark_replaced(hass, msg.get("entity_ids"))
connection.send_result(msg["id"], result)