88 lines
3.0 KiB
TypeScript
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);
|
|
}
|