Re-implement Travel Forecast under OpenMeteo
This commit is contained in:
parent
9ddbef4784
commit
ff30f68013
2 changed files with 40 additions and 22 deletions
|
|
@ -1,13 +1,14 @@
|
|||
// travel forecast display
|
||||
import STATUS from './status.mjs';
|
||||
import { safeJson, safePromiseAll } from './utils/fetch.mjs';
|
||||
import { getSmallIcon } from './icons.mjs';
|
||||
import { safePromiseAll } from './utils/fetch.mjs';
|
||||
import { getSmallIconFromWmoCode } from './icons.mjs';
|
||||
import { DateTime } from '../vendor/auto/luxon.mjs';
|
||||
import WeatherDisplay from './weatherdisplay.mjs';
|
||||
import { registerDisplay } from './navigation.mjs';
|
||||
import settings from './settings.mjs';
|
||||
import calculateScrollTiming from './utils/scroll-timing.mjs';
|
||||
import { debugFlag } from './utils/debug.mjs';
|
||||
import { temperature } from './utils/units.mjs';
|
||||
import { getAggregatedOpenMeteoForecast } from './utils/weather.mjs';
|
||||
|
||||
class TravelForecast extends WeatherDisplay {
|
||||
constructor(navId, elemId, defaultActive) {
|
||||
|
|
@ -34,28 +35,18 @@ class TravelForecast extends WeatherDisplay {
|
|||
async getData(weatherParameters, refresh) {
|
||||
// super checks for enabled
|
||||
if (!super.getData(weatherParameters, refresh)) return;
|
||||
if (!this.weatherParameters?.supportsNoaaDisplays) {
|
||||
this.data = [];
|
||||
this.timing.totalScreens = 0;
|
||||
this.setStatus(STATUS.loaded);
|
||||
return;
|
||||
}
|
||||
|
||||
// clear stored data if not refresh
|
||||
if (!refresh) {
|
||||
this.previousData = [];
|
||||
}
|
||||
|
||||
const temperatureConverter = temperature();
|
||||
|
||||
const forecastPromises = TravelCities.map(async (city, index) => {
|
||||
try {
|
||||
// get point then forecast
|
||||
if (!city.point) throw new Error('No pre-loaded point');
|
||||
let forecast;
|
||||
forecast = await safeJson(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/forecast`, {
|
||||
data: {
|
||||
units: settings.units.value,
|
||||
},
|
||||
});
|
||||
forecast = await getAggregatedOpenMeteoForecast(city.Latitude, city.Longitude);
|
||||
|
||||
if (forecast) {
|
||||
// store for the next run
|
||||
|
|
@ -73,15 +64,23 @@ class TravelForecast extends WeatherDisplay {
|
|||
}
|
||||
return { name: city.Name, error: true };
|
||||
}
|
||||
// determine today or tomorrow (shift periods by 1 if tomorrow)
|
||||
const todayShift = forecast.properties.periods[0].isDaytime ? 0 : 1;
|
||||
|
||||
const [todayKey, tomorrowKey] = Object.keys(forecast.aggregatedForecast);
|
||||
const todayForecast = forecast.aggregatedForecast[todayKey];
|
||||
const tomorrowForecast = forecast.aggregatedForecast[tomorrowKey] ?? todayForecast;
|
||||
if (!todayForecast) {
|
||||
throw new Error('No aggregated travel forecast available');
|
||||
}
|
||||
|
||||
const firstHour = todayForecast.hours[0] ?? {};
|
||||
const today = Boolean(firstHour.is_day ?? 1);
|
||||
// return a pared-down forecast
|
||||
return {
|
||||
today: todayShift === 0,
|
||||
high: forecast.properties.periods[todayShift].temperature,
|
||||
low: forecast.properties.periods[todayShift + 1].temperature,
|
||||
today,
|
||||
high: temperatureConverter(todayForecast.temperature_2m_max),
|
||||
low: temperatureConverter(tomorrowForecast.temperature_2m_min),
|
||||
name: city.Name,
|
||||
icon: getSmallIcon(forecast.properties.periods[todayShift].icon),
|
||||
icon: getSmallIconFromWmoCode(todayForecast.weather_code, today),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Unexpected error getting Travel Forecast for ${city.Name}: ${error.message}`);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,24 @@ const getOpenMeteoForecast = async (lat, lon) => {
|
|||
return forecast;
|
||||
};
|
||||
|
||||
const getAggregatedOpenMeteoForecast = async (lat, lon) => {
|
||||
const forecast = await getOpenMeteoForecast(lat, lon);
|
||||
if (!forecast) return false;
|
||||
|
||||
const aggregatedForecast = aggregateWeatherForecastData(forecast);
|
||||
if (!aggregatedForecast) {
|
||||
if (debugFlag('verbose-failures')) {
|
||||
console.warn(`Unable to aggregate Open-Meteo forecast for ${lat},${lon}`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
forecast,
|
||||
aggregatedForecast,
|
||||
};
|
||||
};
|
||||
|
||||
const weatherConditions = [
|
||||
{ codes: [0], text: ['Clear sky'] },
|
||||
{ codes: [1, 2, 3], text: ['Mainly clear', 'Partly cloudy', 'Overcast'] },
|
||||
|
|
@ -124,6 +142,7 @@ const aggregateWeatherForecastData = (forecastResponse) => {
|
|||
export {
|
||||
getPoint,
|
||||
getOpenMeteoForecast,
|
||||
getAggregatedOpenMeteoForecast,
|
||||
aggregateWeatherForecastData,
|
||||
getConditionText,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue