backfill all data points
This commit is contained in:
@@ -311,7 +311,7 @@ def read_ltr(c, sensor, temp=None, dew_point=None, rh=None, aqi=None, lat=0.0, l
|
|||||||
|
|
||||||
if temp is not None and dew_point is not None:
|
if temp is not None and dew_point is not None:
|
||||||
cloud, sun_elev = estimate_cloud_cover(c, lux, temp, dew_point, lat, lon)
|
cloud, sun_elev = estimate_cloud_cover(c, lux, temp, dew_point, lat, lon)
|
||||||
fields['cloud_cover'] = cloud
|
fields['clouds'] = cloud
|
||||||
fields['sun_elevation'] = sun_elev
|
fields['sun_elevation'] = sun_elev
|
||||||
|
|
||||||
if rh is not None:
|
if rh is not None:
|
||||||
|
|||||||
@@ -5,6 +5,14 @@ import {localDateStr} from './config.mjs';
|
|||||||
export let lastForecast = { ts: 0, slots: [], summary: null }
|
export let lastForecast = { ts: 0, slots: [], summary: null }
|
||||||
export const forecastTTL = 5 * 60 * 60_000
|
export const forecastTTL = 5 * 60 * 60_000
|
||||||
|
|
||||||
|
function estimatePrecipitation(precipChance, clouds) {
|
||||||
|
if (precipChance < 30) return 0;
|
||||||
|
const intensity = (precipChance / 100) * clouds;
|
||||||
|
if (intensity > 0.7) return Math.round(intensity * 15 * 10) / 10;
|
||||||
|
if (intensity > 0.4) return Math.round(intensity * 6 * 10) / 10;
|
||||||
|
return Math.round(intensity * 2 * 10) / 10;
|
||||||
|
}
|
||||||
|
|
||||||
function estimateUV(sunElevation, cloudFraction) {
|
function estimateUV(sunElevation, cloudFraction) {
|
||||||
if (sunElevation <= 0) return 0;
|
if (sunElevation <= 0) return 0;
|
||||||
const clearSkyUV = Math.sin((sunElevation * Math.PI) / 180) * 12;
|
const clearSkyUV = Math.sin((sunElevation * Math.PI) / 180) * 12;
|
||||||
@@ -115,14 +123,17 @@ export async function get24HourForecast(currentSensors) {
|
|||||||
const time = new Date(now.getTime() + (i + 1) * 3600 * 1000);
|
const time = new Date(now.getTime() + (i + 1) * 3600 * 1000);
|
||||||
time.setMinutes(0, 0, 0);
|
time.setMinutes(0, 0, 0);
|
||||||
|
|
||||||
const pressureDamping = Math.exp(-i * 0.08);
|
const pressureDamping = Math.exp(-i * 0.08);
|
||||||
const pressure = seedPressure + pressureTrend * (i + 1) * pressureDamping;
|
const pressure = seedPressure + pressureTrend * (i + 1) * pressureDamping;
|
||||||
const pressure_slp = Math.round((pressure + (coords.altitude ?? 0) / 8.5) * 100) / 100;
|
const pressure_slp = Math.round((pressure + (coords.altitude ?? 0) / 8.5) * 100) / 100;
|
||||||
const clouds = estimateClouds(seedHumidity + humidityTrend * i, pressureTrend);
|
const clouds = estimateClouds(seedHumidity + humidityTrend * i, pressureTrend);
|
||||||
const bgTemp = seedTemp + tempTrend * (i + 1);
|
const bgTemp = seedTemp + tempTrend * (i + 1);
|
||||||
const temperature = Math.round(bgTemp * 10) / 10;
|
const temperature = Math.round(bgTemp * 10) / 10;
|
||||||
const humidity = forecastHumidity(seedAbsHum, temperature);
|
const humidity = forecastHumidity(seedAbsHum, temperature);
|
||||||
const wind_speed = forecastWind(seedWind, pressureTrend);
|
const wind_speed = forecastWind(seedWind, pressureTrend);
|
||||||
|
const precipitation_chance = Math.round(weather.precipitation_chance * (1 - i * 0.02) * 100);
|
||||||
|
const raining = precipitation_chance > 60 ? 'True' : 'False';
|
||||||
|
const precipitation = estimatePrecipitation(precipitation_chance, clouds);
|
||||||
|
|
||||||
const celestial = getCelestialCurrent(coords.latitude, coords.longitude, time);
|
const celestial = getCelestialCurrent(coords.latitude, coords.longitude, time);
|
||||||
const uv_index = estimateUV(celestial.sun_elevation ?? 0, clouds);
|
const uv_index = estimateUV(celestial.sun_elevation ?? 0, clouds);
|
||||||
@@ -143,14 +154,16 @@ export async function get24HourForecast(currentSensors) {
|
|||||||
wind_gusts: Math.round(wind_speed * 1.4 * 10) / 10,
|
wind_gusts: Math.round(wind_speed * 1.4 * 10) / 10,
|
||||||
wind_direction: currentSensors.wind_direction ?? 0,
|
wind_direction: currentSensors.wind_direction ?? 0,
|
||||||
clouds,
|
clouds,
|
||||||
precipitation_chance: Math.round(weather.precipitation_chance * (1 - i * 0.02) * 100),
|
raining,
|
||||||
|
precipitation,
|
||||||
|
precipitation_chance,
|
||||||
accumulation: 0,
|
accumulation: 0,
|
||||||
uv_index,
|
uv_index,
|
||||||
uv_dose: 0,
|
uv_dose: 0,
|
||||||
solar_wm2: 0,
|
solar_wm2: 0,
|
||||||
daily_light_integral: 0,
|
daily_light_integral: 0,
|
||||||
lux: 0,
|
lux: 0,
|
||||||
visibility: 50,
|
visibility: 50,
|
||||||
...celestial,
|
...celestial,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -174,12 +187,12 @@ export async function get24HourForecast(currentSensors) {
|
|||||||
slot.vapor_pressure_deficit = vaporPressureDeficit(slot.temperature, slot.humidity);
|
slot.vapor_pressure_deficit = vaporPressureDeficit(slot.temperature, slot.humidity);
|
||||||
slot.humidity_abs = absoluteHumidity(slot.temperature, slot.humidity);
|
slot.humidity_abs = absoluteHumidity(slot.temperature, slot.humidity);
|
||||||
|
|
||||||
slot.solar_wm2 = slot.sun_elevation > 0
|
slot.solar_wm2 = slot.sun_elevation > 0
|
||||||
? Math.round(Math.sin((slot.sun_elevation * Math.PI) / 180) * 1000 * (1 - slot.clouds * 0.75) * 100) / 100
|
? Math.round(Math.sin((slot.sun_elevation * Math.PI) / 180) * 1000 * (1 - slot.clouds * 0.75) * 100) / 100
|
||||||
: 0;
|
: 0;
|
||||||
slot.daily_light_integral = Math.round(slot.solar_wm2 * 3600 / 1_000_000 * 4.57 * 100) / 100;
|
slot.daily_light_integral = Math.round(slot.solar_wm2 * 3600 / 1_000_000 * 4.57 * 100) / 100;
|
||||||
slot.lux = slot.solar_wm2 > 0 ? Math.round(slot.solar_wm2 * 120) : 0;
|
slot.lux = slot.solar_wm2 > 0 ? Math.round(slot.solar_wm2 * 120) : 0;
|
||||||
slot.visibility = slot.clouds > 0.85 ? 10 : 50;
|
slot.visibility = slot.clouds > 0.85 ? 10 : 50;
|
||||||
|
|
||||||
Object.assign(slot, getWeatherCondition(slot));
|
Object.assign(slot, getWeatherCondition(slot));
|
||||||
}
|
}
|
||||||
@@ -216,6 +229,7 @@ function summarise(slots) {
|
|||||||
return {
|
return {
|
||||||
time: slots[0].time,
|
time: slots[0].time,
|
||||||
label: dominant.label,
|
label: dominant.label,
|
||||||
|
code: dominant.code ?? null,
|
||||||
icon: dominant.icon,
|
icon: dominant.icon,
|
||||||
temperature: peak(fin('temperature')),
|
temperature: peak(fin('temperature')),
|
||||||
temperature_max: peak(finAll('temperature')),
|
temperature_max: peak(finAll('temperature')),
|
||||||
@@ -233,6 +247,8 @@ function summarise(slots) {
|
|||||||
wind_gusts: peak(fin('wind_gusts')),
|
wind_gusts: peak(fin('wind_gusts')),
|
||||||
wind_direction: avg(fin('wind_direction')),
|
wind_direction: avg(fin('wind_direction')),
|
||||||
clouds: avg(fin('clouds')),
|
clouds: avg(fin('clouds')),
|
||||||
|
raining: peak(fin('precipitation_chance')) > 60 ? 'True' : 'False',
|
||||||
|
precipitation: avg(fin('precipitation')),
|
||||||
precipitation_chance: Math.round(peak(fin('precipitation_chance'))),
|
precipitation_chance: Math.round(peak(fin('precipitation_chance'))),
|
||||||
accumulation: 0,
|
accumulation: 0,
|
||||||
uv_index: peak(fin('uv_index')),
|
uv_index: peak(fin('uv_index')),
|
||||||
@@ -240,18 +256,18 @@ function summarise(slots) {
|
|||||||
solar_wm2: avg(fin('solar_wm2')),
|
solar_wm2: avg(fin('solar_wm2')),
|
||||||
daily_light_integral: Math.round(finAll('daily_light_integral').reduce((a, b) => a + b, 0) * 100) / 100,
|
daily_light_integral: Math.round(finAll('daily_light_integral').reduce((a, b) => a + b, 0) * 100) / 100,
|
||||||
lux: peak(fin('lux')),
|
lux: peak(fin('lux')),
|
||||||
visibility: avg(fin('visibility')),
|
visibility: avg(fin('visibility')),
|
||||||
sunrise: slots.find(s => s.sunrise)?.sunrise ?? null,
|
sunrise: slots.find(s => s.sunrise)?.sunrise ?? null,
|
||||||
sunset: slots.find(s => s.sunset)?.sunset ?? null,
|
sunset: slots.find(s => s.sunset)?.sunset ?? null,
|
||||||
daylight: slots.find(s => s.daylight)?.daylight ?? null,
|
daylight: slots.find(s => s.daylight)?.daylight ?? null,
|
||||||
moon_phase: dominant.moon_phase ?? null,
|
moon_phase: dominant.moon_phase ?? null,
|
||||||
moon_illumination: dominant.moon_illumination ?? null,
|
moon_illumination: dominant.moon_illumination ?? null,
|
||||||
moon_elevation: dominant.moon_elevation ?? null,
|
moon_elevation: dominant.moon_elevation ?? null,
|
||||||
moon_azimuth: dominant.moon_azimuth ?? null,
|
moon_azimuth: dominant.moon_azimuth ?? null,
|
||||||
moon_new: dominant.moon_new ?? null,
|
moon_new: dominant.moon_new ?? null,
|
||||||
moon_full: dominant.moon_full ?? null,
|
moon_full: dominant.moon_full ?? null,
|
||||||
moonrise: slots.find(s => s.moonrise)?.moonrise ?? null,
|
moonrise: slots.find(s => s.moonrise)?.moonrise ?? null,
|
||||||
moonset: slots.find(s => s.moonset)?.moonset ?? null,
|
moonset: slots.find(s => s.moonset)?.moonset ?? null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,21 +287,20 @@ export async function getForecast() {
|
|||||||
|
|
||||||
export function getWeatherCondition(data) {
|
export function getWeatherCondition(data) {
|
||||||
if(data.lightning_rate > 0 && data.raining === 'True') {
|
if(data.lightning_rate > 0 && data.raining === 'True') {
|
||||||
return {label: 'Thunderstorm', icon: '11d'};
|
return {label: 'Thunderstorm', icon: '11d', code: 211};
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data.raining === 'True') {
|
if(data.raining === 'True') {
|
||||||
if(data.precipitation > 7.6) return {label: 'Heavy Rain', icon: '10d'};
|
if(data.precipitation > 7.6) return {label: 'Heavy Rain', icon: '10d', code: 502};
|
||||||
if(data.precipitation > 2.5) return {label: 'Moderate Rain', icon: '10d'};
|
if(data.precipitation > 2.5) return {label: 'Moderate Rain', icon: '10d', code: 501};
|
||||||
return {label: 'Light Rain', icon: '09d'};
|
return {label: 'Light Rain', icon: '09d', code: 500};
|
||||||
}
|
}
|
||||||
|
if(data.visibility < 10) return {label: 'Mist', icon: '50d', code: 701};
|
||||||
if(data.visibility < 10) return {label: 'Mist', icon: '50d'};
|
|
||||||
|
|
||||||
const dayNight = data.daytime ? 'd' : 'n';
|
const dayNight = data.daytime ? 'd' : 'n';
|
||||||
if(data.clouds > 0.85) return {label: 'Overcast Clouds', icon: `04${dayNight}`};
|
const c = data.clouds > 1 ? data.clouds / 100 : data.clouds;
|
||||||
if(data.clouds > 0.50) return {label: 'Broken Clouds', icon: `04${dayNight}`};
|
if(c > 0.85) return {label: 'Overcast Clouds', icon: `04${dayNight}`, code: 804};
|
||||||
if(data.clouds > 0.25) return {label: 'Scattered Clouds', icon: `03${dayNight}`};
|
if(c > 0.50) return {label: 'Broken Clouds', icon: `04${dayNight}`, code: 803};
|
||||||
if(data.clouds > 0.10) return {label: 'Few Clouds', icon: `02${dayNight}`};
|
if(c > 0.25) return {label: 'Scattered Clouds', icon: `03${dayNight}`, code: 802};
|
||||||
return {label: 'Clear Sky', icon: `01${dayNight}`};
|
if(c > 0.10) return {label: 'Few Clouds', icon: `02${dayNight}`, code: 801};
|
||||||
|
return {label: 'Clear Sky', icon: `01${dayNight}`, code: 800};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user