add additional URLs per API

This commit is contained in:
easyas314
2020-06-13 11:58:06 -04:00
parent df3aa22c59
commit 9d2d170c2d

View File

@@ -3,13 +3,14 @@
/* Magic Mirror /* Magic Mirror
* Module: Weather * Module: Weather
* Provider: weather.gov * Provider: weather.gov
* https://weather-gov.github.io/api/general-faqs
* *
* By Vince Peri * Original by Vince Peri
* MIT Licensed. * MIT Licensed.
* *
* This class is a provider for weather.gov. * This class is a provider for weather.gov.
* Note that this is only for US locations (lat and lon) and does not require an API key * Note that this is only for US locations (lat and lon) and does not require an API key
* Since it is free, there are some items missing - like sunrise, sunset, humidity, etc. * Since it is free, there are some items missing - like sunrise, sunset
*/ */
WeatherProvider.register("weathergov", { WeatherProvider.register("weathergov", {
@@ -18,10 +19,10 @@ WeatherProvider.register("weathergov", {
// But for debugging (and future alerts) it would be nice to have the real name. // But for debugging (and future alerts) it would be nice to have the real name.
providerName: "Weather.gov", providerName: "Weather.gov",
// need setConfig URLs status // Flag all needed URLs availability
configURLs: false, configURLs: false,
//multiple urls involved //This API has multiple urls involved
forecastURL: "tbd", forecastURL: "tbd",
forecastHourlyURL: "tbd", forecastHourlyURL: "tbd",
forecastGridDataURL: "tbd", forecastGridDataURL: "tbd",
@@ -31,9 +32,7 @@ WeatherProvider.register("weathergov", {
// Called to set the config, this config is the same as the weather module's config. // Called to set the config, this config is the same as the weather module's config.
setConfig: function (config) { setConfig: function (config) {
this.config = config; this.config = config;
Log.info(`Weather provider: ${this.providerName} config set.`, this.config); (this.config.apiBase = "https://api.weather.gov"), this.fetchWxGovURLs(this.config);
// URLs needed from weather.gov
this.fetchWxGovURLs(this.config);
}, },
// Called when the weather provider is about to start. // Called when the weather provider is about to start.
@@ -41,26 +40,28 @@ WeatherProvider.register("weathergov", {
Log.info(`Weather provider: ${this.providerName} started.`); Log.info(`Weather provider: ${this.providerName} started.`);
}, },
// This returns the name of the fetched location or an empty string.
fetchedLocation: function () {
return this.fetchedLocationName || "";
},
// Overwrite the fetchCurrentWeather method. // Overwrite the fetchCurrentWeather method.
fetchCurrentWeather() { fetchCurrentWeather() {
if (!this.configURLs) { if (!this.configURLs) {
Log.info("fetch wx waiting on config URLs"); Log.info("fetch wx waiting on config URLs");
return; return;
} }
// this.fetchData(this.getUrl()) this.fetchData(this.stationObsURL)
this.fetchData(this.forecastURL)
.then((data) => { .then((data) => {
if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) { if (!data || !data.properties) {
// Did not receive usable new data. // Did not receive usable new data.
// Maybe this needs a better check?
return; return;
} }
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties);
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties.periods[0]);
this.setCurrentWeather(currentWeather); this.setCurrentWeather(currentWeather);
}) })
.catch(function (request) { .catch(function (request) {
Log.error("Could not load data ... ", request); Log.error("Could not load station obs data ... ", request);
}) })
.finally(() => this.updateAvailable()); .finally(() => this.updateAvailable());
}, },
@@ -71,20 +72,17 @@ WeatherProvider.register("weathergov", {
Log.info("fetch wx waiting on config URLs"); Log.info("fetch wx waiting on config URLs");
return; return;
} }
//this.fetchData(this.getUrl()) this.fetchData(this.forecastURL)
this.fetchData(this.forecastHourlyURL)
.then((data) => { .then((data) => {
if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) { if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) {
// Did not receive usable new data. // Did not receive usable new data.
// Maybe this needs a better check?
return; return;
} }
const forecast = this.generateWeatherObjectsFromForecast(data.properties.periods); const forecast = this.generateWeatherObjectsFromForecast(data.properties.periods);
this.setWeatherForecast(forecast); this.setWeatherForecast(forecast);
}) })
.catch(function (request) { .catch(function (request) {
Log.error("Could not load data ... ", request); Log.error("Could not load forecast hourly data ... ", request);
}) })
.finally(() => this.updateAvailable()); .finally(() => this.updateAvailable());
}, },
@@ -95,21 +93,20 @@ WeatherProvider.register("weathergov", {
* Get specific URLs * Get specific URLs
*/ */
fetchWxGovURLs(config) { fetchWxGovURLs(config) {
// wxCtl.initialLoadDelay here ?
this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`) this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`)
.then((data) => { .then((data) => {
if (!data || !data.properties) { if (!data || !data.properties) {
// points URL did not respond with usable data. // points URL did not respond with usable data.
return; return;
} }
this.fetchedLocationName = data.properties.relativeLocation.properties.city + ", " + data.properties.relativeLocation.properties.state;
Log.log("Forecast location is " + this.fetchedLocationName);
this.forecastURL = data.properties.forecast; this.forecastURL = data.properties.forecast;
Log.log(this.forecastURL);
this.forecastHourlyURL = data.properties.forecastHourly; this.forecastHourlyURL = data.properties.forecastHourly;
this.forecastGridDataURL = data.properties.forecastGridData; this.forecastGridDataURL = data.properties.forecastGridData;
this.observationStationsURL = data.properties.observationStations; this.observationStationsURL = data.properties.observationStations;
// with this URL, we chain another promise for the station obs URL // with this URL, we chain another promise for the station obs URL
return this.fetchData(data.properties.observationStations); return this.fetchData(data.properties.observationStations);
//const wxStations = await this.fetchData(wxPoints.properties.observationStationsURL);
}) })
.then((obsData) => { .then((obsData) => {
if (!obsData || !obsData.features) { if (!obsData || !obsData.features) {
@@ -117,34 +114,44 @@ WeatherProvider.register("weathergov", {
return; return;
} }
this.stationObsURL = obsData.features[0].id + "/observations/latest"; this.stationObsURL = obsData.features[0].id + "/observations/latest";
Log.log(this.stationObsURL);
}) })
.catch((err) => { .catch((err) => {
Log.error(err); Log.error(err);
}) })
.finally(() => { .finally(() => {
// excellent, let's fetch some actual wx data
this.configURLs = true; this.configURLs = true;
this.fetchCurrentWeather(); this.fetchCurrentWeather();
}); });
}, },
/*
* Gets the complete url for the request
*/
getUrl() {
return this.config.apiBase + this.config.lat + "," + this.config.lon + this.config.weatherEndpoint;
},
/* /*
* Generate a WeatherObject based on currentWeatherInformation * Generate a WeatherObject based on currentWeatherInformation
* Weather.gov API uses specific units; API does not include choice of units
* ... object needs data in units based on config!
*/ */
generateWeatherObjectFromCurrentWeather(currentWeatherData) { generateWeatherObjectFromCurrentWeather(currentWeatherData) {
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
currentWeather.temperature = currentWeatherData.temperature; currentWeather.date = moment(currentWeatherData.timestamp);
currentWeather.windSpeed = currentWeatherData.windSpeed.split(" ", 1); currentWeather.temperature = this.convertTemp(currentWeatherData.temperature.value);
currentWeather.windDirection = this.convertWindDirection(currentWeatherData.windDirection); currentWeather.windSpeed = this.covertSpeed(currentWeatherData.windSpeed.value);
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.shortForecast, currentWeatherData.isDaytime); currentWeather.windDirection = currentWeatherData.windDirection.value;
currentWeather.minTemperature = this.convertTemp(currentWeatherData.minTemperatureLast24Hours.value);
currentWeather.maxTemperature = this.convertTemp(currentWeatherData.maxTemperatureLast24Hours.value);
currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value);
currentWeather.rain = null;
currentWeather.snow = null;
currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value);
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value);
let isDaytime = true;
if (currentWeatherData.icon.includes("day")) {
isDaytime = true;
} else {
isDaytime = false;
}
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.textDescription, isDaytime);
// determine the sunrise/sunset times - not supplied in weather.gov data // determine the sunrise/sunset times - not supplied in weather.gov data
let times = this.calcAstroData(this.config.lat, this.config.lon); let times = this.calcAstroData(this.config.lat, this.config.lon);
@@ -220,6 +227,34 @@ WeatherProvider.register("weathergov", {
return days.slice(1); return days.slice(1);
}, },
/*
* Unit conversions
*/
// conversion to fahrenheit
convertTemp(temp) {
if (this.config.tempUnits === "imperial") {
return (9 / 5) * temp + 32;
} else {
return temp;
}
},
// conversion to mph
covertSpeed(metSec) {
if (this.config.windUnits === "imperial") {
return metSec * 2.23694;
} else {
return metSec;
}
},
// conversion to inches
convertLength(meters) {
if (this.config.units === "imperial") {
return meters * 39.3701;
} else {
return meters;
}
},
/* /*
* Calculate the astronomical data * Calculate the astronomical data
*/ */