Files
dashboard/components/iotPanel/hvacSetpointResolve.ts
T
Alberto-Audrix 32a36cceff
CI / lint-and-test (push) Canceled after 0s
first commit
2026-07-28 08:55:05 +07:00

88 lines
3.0 KiB
TypeScript

import type { SetpointSnapshotData } from './fan1SetpointResolve.ts';
import { resolveCoolerDisplayTargetCelsius } from './coolerSetpointResolve.ts';
export type HeaterDeviceKey = 'H' | 'H2';
export type HvacDeviceKey = HeaterDeviceKey | 'C';
export type HeaterTargetDelta = { targetOn?: number; targetOff?: number };
function normalizeHouseSetpointCelsius(raw: number | string | null | undefined): number | null {
const n = Number(raw);
if (!Number.isFinite(n)) return null;
return n;
}
function normalizeHeaterDelta(raw: number | string | null | undefined): number | null {
const n = Number(raw);
if (!Number.isFinite(n)) return null;
return n;
}
export function heaterTargetFromSnapshot(
inner: SetpointSnapshotData | undefined,
deviceKey: HeaterDeviceKey
): HeaterTargetDelta | null {
const heaterNumber = deviceKey === 'H' ? 1 : 2;
const rows = Array.isArray(inner?.setting?.heater) ? inner.setting.heater : [];
for (const heater of rows) {
const name = String(heater?.name || '').trim();
const match = new RegExp(`^Heater\\s+${heaterNumber}$`, 'i').exec(name);
if (!match) continue;
const targetOn = normalizeHeaterDelta(heater?.target_on);
const targetOff = normalizeHeaterDelta(heater?.target_off);
if (targetOn === null && targetOff === null) return null;
return {
...(targetOn !== null && { targetOn }),
...(targetOff !== null && { targetOff }),
};
}
return null;
}
/** Same rule as live panel `computeDashboard` for heaters. */
export function heaterDisplayTargetCelsius(
baseSetPoint: number | null,
heaterTarget: HeaterTargetDelta | null,
isActive: boolean
): number | null {
if (!heaterTarget) return null;
const heaterDelta = isActive ? heaterTarget.targetOff : heaterTarget.targetOn;
if (heaterDelta === null || heaterDelta === undefined || !Number.isFinite(Number(heaterDelta))) {
return null;
}
if (baseSetPoint !== null && Math.abs(Number(heaterDelta)) <= 10) {
return baseSetPoint + Number(heaterDelta);
}
return Number(heaterDelta);
}
export function heaterSetpointFromSnapshot(
inner: SetpointSnapshotData | undefined,
deviceKey: HeaterDeviceKey,
isActive: boolean
): number | null {
const baseSetPoint = normalizeHouseSetpointCelsius(inner?.setpoint_sekarang?.current_setpoint);
const heaterTarget = heaterTargetFromSnapshot(inner, deviceKey);
return heaterDisplayTargetCelsius(baseSetPoint, heaterTarget, isActive);
}
export function coolerSetpointFromSnapshot(
inner: SetpointSnapshotData | undefined,
avgInsideTemp: number | null,
isActive: boolean
): number | null {
if (!isActive) return null;
return resolveCoolerDisplayTargetCelsius(avgInsideTemp, inner?.setting?.cooler);
}
export function hvacSetpointFromSnapshot(
inner: SetpointSnapshotData | undefined,
deviceKey: HvacDeviceKey,
options: { avgInsideTemp: number | null; isActive: boolean }
): number | null {
if (deviceKey === 'C') {
return coolerSetpointFromSnapshot(inner, options.avgInsideTemp, options.isActive);
}
return heaterSetpointFromSnapshot(inner, deviceKey, options.isActive);
}