Updated forecast summary

This commit is contained in:
2026-06-24 15:10:30 -04:00
parent 5794eca9f1
commit a69867406b
4 changed files with 15 additions and 14 deletions

View File

@@ -137,11 +137,11 @@ onMounted(async () => {
<div class="flex-c fg-muted"> <div class="flex-c fg-muted">
<div class="hi"> <div class="hi">
<div v-if="!data" class="d-inline-block pos-rel br-2 overflow-hidden" style="width: 25px; height: 1em"><Loading/></div> <div v-if="!data" class="d-inline-block pos-rel br-2 overflow-hidden" style="width: 25px; height: 1em"><Loading/></div>
<template v-else> {{ 0 }}°</template> <template v-else> {{ ~~(data.temperature_max) }}°</template>
</div> </div>
<div class="lo"> <div class="lo">
<div v-if="!data" class="d-inline-block pos-rel br-2 overflow-hidden" style="width: 25px; height: 1em"><Loading/></div> <div v-if="!data" class="d-inline-block pos-rel br-2 overflow-hidden" style="width: 25px; height: 1em"><Loading/></div>
<template v-else> {{ 0 }}°</template> <template v-else> {{ ~~(data.temperature_min) }}°</template>
</div> </div>
</div> </div>
</div> </div>
@@ -153,7 +153,7 @@ onMounted(async () => {
<div class="stat"> <div class="stat">
<span class="stat-label">Precipitation</span> <span class="stat-label">Precipitation</span>
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div> <div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
<span v-else class="stat-value">{{ !data.precipitation && data.raining == 'True' ? 'Spitting' : data.precipitation.toFixed(1) + 'mm'}}</span> <span v-else class="stat-value">{{ data.raining == 'False' ? (data.precipitation_chance + '%') : (data.percipitation > 0 ? data.precipitation.toFixed(1) + 'mm' : 'Spitting')}}</span>
</div> </div>
<div class="stat"> <div class="stat">
<span class="stat-label">Humidity</span> <span class="stat-label">Humidity</span>

View File

@@ -61,12 +61,12 @@ function dir(deg: number) {
<div class="forecast-wrap"> <div class="forecast-wrap">
<div v-if="days?.length" class="strip"> <div v-if="days?.length" class="strip">
<div v-for="d in days" class="day"> <div v-for="d in days" class="day">
<div class="day-name">{{ formatDate('ddd, MMM d', new Date(d.time + 'T00:00:00')) }}</div> <div class="day-name">{{ formatDate('ddd, MMM D', new Date(d.time + 'T00:00:00')) }}</div>
<img :src="BASE + d.icon" class="day-icon" :alt="(d.label?.toString() || '')" /> <img :src="BASE + d.icon" class="day-icon" :alt="(d.label?.toString() || '')" />
<div class="day-label">{{ d.label }}</div> <div class="day-label">{{ d.label }}</div>
<div class="day-temps"> <div class="day-temps">
<span>{{ d.temperature_max || '—' }}</span> <span>{{ ~~(d.temperature_max) + '°' || '—' }}</span>
<span class="day-low">{{ d.temperature_min || '—' }}</span> <span class="day-low">{{ ~~(d.temperature_min) + '°' || '—' }}</span>
</div> </div>
<div class="day-humid">🌡 {{ d.humidity || 0 }}%</div> <div class="day-humid">🌡 {{ d.humidity || 0 }}%</div>
<div class="day-wind">🍃 {{ ~~(d.wind_gusts as any) || 0 }} Kph ({{dir(d.wind_dir as any)}})</div> <div class="day-wind">🍃 {{ ~~(d.wind_gusts as any) || 0 }} Kph ({{dir(d.wind_dir as any)}})</div>

View File

@@ -1,6 +1,7 @@
// forecast.mjs // forecast.mjs
import {queryHourly, getCoords, queryCurrent} from './influx.mjs'; import {queryHourly, getCoords, queryCurrent} from './influx.mjs';
import { getCelestialForecast } from './celestial.mjs'; import { getCelestialForecast } from './celestial.mjs';
import {getWeatherCondition} from './openweather.mjs';
export let lastForecast = { ts: 0, slots: [], summary: null } export let lastForecast = { ts: 0, slots: [], summary: null }
const TTL = 10 * 60 * 1000 const TTL = 10 * 60 * 1000
@@ -150,7 +151,7 @@ export async function get24HourForecast(currentSensors) {
const humidity = forecastHumidity(seedAbsHum, temperature); const humidity = forecastHumidity(seedAbsHum, temperature);
const wind_speed = forecastWind(seedWind, pressureTrend); const wind_speed = forecastWind(seedWind, pressureTrend);
return { const snapshot = {
time: time.toISOString().slice(0, 16), // "YYYY-MM-DDTHH:MM" time: time.toISOString().slice(0, 16), // "YYYY-MM-DDTHH:MM"
temperature, temperature,
humidity, humidity,
@@ -161,10 +162,10 @@ export async function get24HourForecast(currentSensors) {
pressure_hpa: Math.round(pressure * 100) / 100, pressure_hpa: Math.round(pressure * 100) / 100,
wind_speed, wind_speed,
clouds, clouds,
precip_chance: Math.round(weather.precipChance * (1 - i * 0.02) * 100), // confidence decays precipitation_chance: Math.round(weather.precipChance * (1 - i * 0.02) * 100), // confidence decays
label: weather.label,
code: weather.code,
}; };
return Object.assign(snapshot, getWeatherCondition(snapshot));
}); });
// Pass through getCelestialForecast to enrich sun/moon data // Pass through getCelestialForecast to enrich sun/moon data
@@ -188,7 +189,7 @@ export async function get24HourForecast(currentSensors) {
function summarise(slots) { function summarise(slots) {
if (!slots.length) return null if (!slots.length) return null
const temps = slots.map(s => s.temperature).filter(Number.isFinite) const temps = slots.map(s => s.temperature).filter(Number.isFinite)
const precips = slots.map(s => s.precip_chance).filter(Number.isFinite) const precips = slots.map(s => s.precipitation_chance).filter(Number.isFinite)
const winds = slots.map(s => s.wind_speed).filter(Number.isFinite) const winds = slots.map(s => s.wind_speed).filter(Number.isFinite)
const gusts = slots.map(s => s.wind_gusts).filter(Number.isFinite) const gusts = slots.map(s => s.wind_gusts).filter(Number.isFinite)
const uvs = slots.map(s => s.uv_index).filter(Number.isFinite) const uvs = slots.map(s => s.uv_index).filter(Number.isFinite)
@@ -202,13 +203,13 @@ function summarise(slots) {
return { return {
time: slots[0].time.slice(0, 10), time: slots[0].time.slice(0, 10),
label, label: dominant.label,
code: dominant.code, code: dominant.code,
icon: dominant.icon ?? null, icon: dominant.icon ?? null,
temperature: Math.max(...temps), temperature: Math.max(...temps),
temperature_max: Math.max(...temps), temperature_max: Math.max(...temps),
temperature_min: Math.min(...temps), temperature_min: Math.min(...temps),
precip_chance: Math.round(Math.max(...precips)), precipitation_chance: Math.round(Math.max(...precips)),
wind_speed: Math.round(Math.max(...winds) * 10) / 10, wind_speed: Math.round(Math.max(...winds) * 10) / 10,
wind_gusts: gusts.length ? Math.round(Math.max(...gusts) * 10) / 10 : null, wind_gusts: gusts.length ? Math.round(Math.max(...gusts) * 10) / 10 : null,
uv_index: uvs.length ? Math.max(...uvs) : null, uv_index: uvs.length ? Math.max(...uvs) : null,

View File

@@ -48,7 +48,7 @@ app.get('/api/current', async (req, res) => {
// Merge forecast summary fields — sensor readings take priority // Merge forecast summary fields — sensor readings take priority
const merged = { const merged = {
...(summary ? { ...(summary ? {
precipitation_chance: summary.precip_chance, precipitation_chance: summary.precipitation_chance,
temperature_max: summary.temperature_max, temperature_max: summary.temperature_max,
temperature_min: summary.temperature_min, temperature_min: summary.temperature_min,
uv_index_max: summary.uv_index, uv_index_max: summary.uv_index,