From ff749940e6287eec58286946ada9862b25a90441 Mon Sep 17 00:00:00 2001 From: "willem.serruys" Date: Sat, 22 Aug 2026 19:56:31 +0200 Subject: [PATCH] fix: when no solar energy, do not enable consumers --- .../backend/src/control/runner.ts | 18 ++++++++++++++---- energy-management/backend/src/types.ts | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/energy-management/backend/src/control/runner.ts b/energy-management/backend/src/control/runner.ts index 3451ed9..789a887 100644 --- a/energy-management/backend/src/control/runner.ts +++ b/energy-management/backend/src/control/runner.ts @@ -37,7 +37,7 @@ export class ControlLoopRunner { const quarterHour = computeQuarterHourStatus(samples, nowMs, targetW); const current: CurrentReadings = { powerW: latestPower?.watts ?? null, - solarW: latestSolar?.watts ?? null, + solarW: this.env.SOLAR_INFLUX_ENTITY_ID ? (latestSolar?.watts ?? 0) : null, }; return { quarterHour, devices, current }; @@ -56,17 +56,27 @@ export class ControlLoopRunner { /** * Whether the solar inverter is currently producing power, used to gate * `onlyWhenSun` devices. Reads the configured InfluxDB solar production - * series and compares its latest sample against SOLAR_PRODUCTION_THRESHOLD_W. + * series and compares its latest sample (treating no reading within the + * lookback window as 0W) against SOLAR_PRODUCTION_THRESHOLD_W. * Falls back to HA's sun.sun (astronomical above/below horizon) when no - * solar production series is configured, or if either read fails. + * solar production series is configured at all, or if the Influx read + * itself fails. */ private async isSolarProducing(): Promise { + if (!this.env.SOLAR_INFLUX_ENTITY_ID) { + return this.fallbackToSunUp(); + } try { const sample = await fetchLatestSolarProductionSample(this.queryApi, this.env); - if (sample) return sample.watts >= this.env.SOLAR_PRODUCTION_THRESHOLD_W; + const watts = sample?.watts ?? 0; + return watts >= this.env.SOLAR_PRODUCTION_THRESHOLD_W; } catch (err) { this.log.error({ err }, "failed to read solar production series; falling back to sun.sun"); + return this.fallbackToSunUp(); } + } + + private fallbackToSunUp(): Promise { return this.ha.isSunUp().catch((err) => { this.log.error({ err }, "failed to read sun.sun state; treating as unrestricted"); return true; diff --git a/energy-management/backend/src/types.ts b/energy-management/backend/src/types.ts index ea8cdd8..bb379ac 100644 --- a/energy-management/backend/src/types.ts +++ b/energy-management/backend/src/types.ts @@ -41,7 +41,7 @@ export interface QuarterHourStatus { export interface CurrentReadings { powerW: number | null; // most recent house power sample, null if none within lookback - solarW: number | null; // most recent solar production sample, null if unconfigured or none within lookback + solarW: number | null; // most recent solar production sample; 0 if configured but no reading within lookback, null if unconfigured } export interface ControlAction {