import type { DeviceConfig, DeviceStatus } from "../types.js"; import type { HomeAssistantClient } from "./client.js"; function normalizeHaValue(kind: DeviceConfig["kind"], state: string): number | null { if (kind === "switch") { if (state === "on") return 1; if (state === "off") return 0; return null; } const n = Number(state); return Number.isFinite(n) ? n : null; } /** True when both directions are driven by custom endpoints rather than Home Assistant. */ function isExternallyControlled(device: DeviceConfig): boolean { return device.enableUrl !== null && device.disableUrl !== null; } async function callEndpoint(url: string): Promise { const res = await fetch(url, { method: "POST" }); if (!res.ok) { throw new Error(`custom endpoint request failed: POST ${url} -> ${res.status} ${await res.text()}`); } } export async function getDeviceStatus( ha: HomeAssistantClient, device: DeviceConfig, shed: boolean, lastChangedAt: string | null, ): Promise { // Externally controlled devices have no Home Assistant entity to poll; state is // whatever we last commanded via the custom endpoints. if (isExternallyControlled(device)) { return { ...device, currentValue: shed ? (device.kind === "switch" ? 0 : device.minValue) : device.kind === "switch" ? 1 : device.maxValue, shed, lastChangedAt, available: true, }; } try { const haState = await ha.getState(device.entityId); return { ...device, currentValue: normalizeHaValue(device.kind, haState.state), shed, lastChangedAt, available: haState.state !== "unavailable" && haState.state !== "unknown", }; } catch { return { ...device, currentValue: null, shed, lastChangedAt, available: false, }; } } /** Sheds (reduces load of) a device: turns a switch off, or lowers a number to its floor. */ export async function shedDevice(ha: HomeAssistantClient, device: DeviceConfig): Promise { if (device.disableUrl) { await callEndpoint(device.disableUrl); return; } if (device.kind === "switch") { await ha.setSwitch(device.entityId, false); } else { await ha.setNumber(device.entityId, device.minValue); } } /** Restores a device to its normal operating value. */ export async function restoreDevice(ha: HomeAssistantClient, device: DeviceConfig): Promise { if (device.enableUrl) { await callEndpoint(device.enableUrl); return; } if (device.kind === "switch") { await ha.setSwitch(device.entityId, true); } else { await ha.setNumber(device.entityId, device.maxValue); } }