From 694b9bad24dccb798f3f230fe2c204e088b4172a Mon Sep 17 00:00:00 2001 From: ztimson Date: Wed, 24 Jun 2026 15:31:00 -0400 Subject: [PATCH] Added daytime property --- server/src/forecast.mjs | 11 ++++++++++- server/src/openmeteo.mjs | 17 ++++++++++++++++- server/src/server.mjs | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/server/src/forecast.mjs b/server/src/forecast.mjs index d5fecd9..00d993a 100644 --- a/server/src/forecast.mjs +++ b/server/src/forecast.mjs @@ -153,6 +153,7 @@ export async function get24HourForecast(currentSensors) { const snapshot = { time: time.toISOString().slice(0, 16), // "YYYY-MM-DDTHH:MM" + daytime: false, temperature, humidity, humidity_abs: absoluteHumidity(temperature, humidity), @@ -173,6 +174,13 @@ export async function get24HourForecast(currentSensors) { // Second pass — apply solar heating now that we have sun_elevation per slot for (const slot of enriched) { + if (slot.sunrise && slot.sunset) { + const t = new Date(slot.time).getTime(); + slot.daytime = t >= new Date(slot.sunrise).getTime() && t < new Date(slot.sunset).getTime(); + } else { + slot.daytime = (slot.sun_elevation ?? 0) > 0; + } + const solar = solarTempDelta(slot.sun_elevation ?? 0, slot.clouds); const cool = slot.daytime ? 0 : nocturnalCooling(slot.clouds); slot.temperature = Math.round((slot.temperature + solar - cool) * 10) / 10; @@ -198,7 +206,8 @@ function summarise(slots) { // Most frequent label/code by occurrence const labelCount = {} for (const s of slots) labelCount[s.label] = (labelCount[s.label] || 0) + 1 - const label = Object.entries(labelCount).sort((a, b) => b[1] - a[1])[0][0] + const label = Object.entries(labelCount).filter(row => row.daytime) + .sort((a, b) => b[1] - a[1])[0][0] const dominant = slots.find(s => s.label === label) return { diff --git a/server/src/openmeteo.mjs b/server/src/openmeteo.mjs index 5e5c068..8d88c3f 100644 --- a/server/src/openmeteo.mjs +++ b/server/src/openmeteo.mjs @@ -136,10 +136,11 @@ export async function dailyWeather(lat, lon, start, end) { const clouds = null // not available in daily return { - time, label: WMO[code] || 'Unknown', icon, code, + time, + daytime: !!data.daily.sunrise[i], temperature: temp, temperature_max: temp, temperature_min: data.daily.temperature_2m_min[i], @@ -183,7 +184,20 @@ export async function hourlyWeather(lat, lon, start, end) { const data = await cachedFetch(`hourly_${lat}_${lon}_${startStr}_${endStr}`, url) if (!data?.hourly?.time) return [] + const sunMap = {} + if (data.daily?.time) { + data.daily.time.forEach((date, i) => { + sunMap[date] = { sunrise: data.daily.sunrise[i], sunset: data.daily.sunset[i] } + }) + } + return Promise.all(data.hourly.time.map(async (time, i) => { + const date = time.slice(0, 10) + const sun = sunMap[date] ?? {} + const t = new Date(time).getTime() + const daytime = sun.sunrise && sun.sunset + ? t >= new Date(sun.sunrise).getTime() && t < new Date(sun.sunset).getTime() + : false const code = data.hourly.weathercode[i] const icon = await ensureIcon(code).catch(() => null) const temp = data.hourly.temperature_2m[i] @@ -193,6 +207,7 @@ export async function hourlyWeather(lat, lon, start, end) { return { time: time.slice(0, 16), + daytime, label: WMO[code] || 'Unknown', icon, code, diff --git a/server/src/server.mjs b/server/src/server.mjs index 105fc20..bfb5b09 100644 --- a/server/src/server.mjs +++ b/server/src/server.mjs @@ -47,6 +47,7 @@ app.get('/api/current', async (req, res) => { // Merge forecast summary fields — sensor readings take priority const merged = { + time: new Date(), ...(summary ? { precipitation_chance: summary.precipitation_chance, temperature_max: summary.temperature_max,