fix: added energy-management
This commit is contained in:
87
energy-management/backend/src/homeassistant/devices.ts
Normal file
87
energy-management/backend/src/homeassistant/devices.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
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<void> {
|
||||
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<DeviceStatus> {
|
||||
// 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<void> {
|
||||
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<void> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user