mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-09-14 08:07:01 +00:00
integrated onecall usage into existing types
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
{% if current %}
|
||||
{% if current or weatherData %}
|
||||
{% if weatherData %}
|
||||
{% set current = weatherData.current %}
|
||||
{% endif %}
|
||||
{% if not config.onlyTemp %}
|
||||
<div class="normal medium">
|
||||
<span class="wi wi-strong-wind dimmed"></span>
|
||||
|
@@ -1,4 +1,7 @@
|
||||
{% if forecast %}
|
||||
{% if forecast or weatherData %}
|
||||
{% if weatherData %}
|
||||
{% set forecast = weatherData.days %}
|
||||
{% endif %}
|
||||
{% set numSteps = forecast | calcNumSteps %}
|
||||
{% set currentStep = 0 %}
|
||||
<table class="{{ config.tableClass }}">
|
||||
|
@@ -1,8 +1,11 @@
|
||||
{% if wData %}
|
||||
{% set numSteps = wData.hours | calcNumEntries %}
|
||||
{% if hourly or weatherData %}
|
||||
{% if weatherData %}
|
||||
{% set hourly = weatherData.hours %}
|
||||
{% endif %}
|
||||
{% set numSteps = hourly | calcNumEntries %}
|
||||
{% set currentStep = 0 %}
|
||||
<table class="{{ config.tableClass }}">
|
||||
{% set hours = wData.hours.slice(0, numSteps) %}
|
||||
{% set hours = hourly.slice(0, numSteps) %}
|
||||
{% for hour in hours %}
|
||||
<tr {% if config.colored %}class="colored"{% endif %} {% if config.fade %}style="opacity: {{ currentStep | opacity(numSteps) }};"{% endif %}>
|
||||
<td class="day">{{ hour.date | formatTime }}</td>
|
||||
@@ -25,5 +28,5 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Uncomment the line below to see the contents of the `wData` object. -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{wData | dump}}</div> -->
|
||||
<!-- Uncomment the line below to see the contents of the `hourly` object. -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{weatherData | dump}}</div> -->
|
@@ -68,8 +68,8 @@ WeatherProvider.register("openweathermap", {
|
||||
|
||||
this.setFetchedLocation(`(${data.lat},${data.lon})`);
|
||||
|
||||
const wData = this.generateWeatherObjectsFromOnecall(data);
|
||||
this.setWeatherData(wData);
|
||||
const weatherData = this.generateWeatherObjectsFromOnecall(data);
|
||||
this.setWeatherData(weatherData);
|
||||
})
|
||||
.catch(function (request) {
|
||||
Log.error("Could not load data ... ", request);
|
||||
@@ -124,8 +124,8 @@ WeatherProvider.register("openweathermap", {
|
||||
return this.fetchOnecall(data);
|
||||
}
|
||||
// if weatherEndpoint does not match onecall, what should be returned?
|
||||
const wData = {current: new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits), hours: [], days: []};
|
||||
return wData;
|
||||
const weatherData = {current: new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits), hours: [], days: []};
|
||||
return weatherData;
|
||||
},
|
||||
|
||||
/*
|
||||
@@ -415,11 +415,11 @@ WeatherProvider.register("openweathermap", {
|
||||
if (this.config.weatherEndpoint === "/onecall") {
|
||||
params += "lat=" + this.config.lat;
|
||||
params += "&lon=" + this.config.lon;
|
||||
if (this.config.type === "wDataCurrent") {
|
||||
if (this.config.type === "current") {
|
||||
params += "&exclude=minutely,hourly,daily";
|
||||
} else if (this.config.type === "wDataHourly") {
|
||||
} else if (this.config.type === "hourly") {
|
||||
params += "&exclude=current,minutely,daily";
|
||||
} else if (this.config.type === "wDataDaily") {
|
||||
} else if (this.config.type === "daily" || this.config.type === "forecast") {
|
||||
params += "&exclude=current,minutely,hourly";
|
||||
} else {
|
||||
params += "&exclude=minutely";
|
||||
|
@@ -3,76 +3,155 @@
|
||||
/* Magic Mirror
|
||||
* Module: Weather
|
||||
* Provider: weather.gov
|
||||
* https://weather-gov.github.io/api/general-faqs
|
||||
*
|
||||
* By Vince Peri
|
||||
* Original by Vince Peri
|
||||
* MIT Licensed.
|
||||
*
|
||||
* 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
|
||||
* 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", {
|
||||
// Set the name of the provider.
|
||||
// This isn't strictly necessary, since it will fallback to the provider identifier
|
||||
// But for debugging (and future alerts) it would be nice to have the real name.
|
||||
providerName: "Weather.gov",
|
||||
|
||||
// Flag all needed URLs availability
|
||||
configURLs: false,
|
||||
|
||||
//This API has multiple urls involved
|
||||
forecastURL: "tbd",
|
||||
forecastHourlyURL: "tbd",
|
||||
forecastGridDataURL: "tbd",
|
||||
observationStationsURL: "tbd",
|
||||
stationObsURL: "tbd",
|
||||
|
||||
// Called to set the config, this config is the same as the weather module's config.
|
||||
setConfig: function (config) {
|
||||
this.config = config;
|
||||
(this.config.apiBase = "https://api.weather.gov"), this.fetchWxGovURLs(this.config);
|
||||
},
|
||||
|
||||
// Called when the weather provider is about to start.
|
||||
start: function () {
|
||||
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.
|
||||
fetchCurrentWeather() {
|
||||
this.fetchData(this.getUrl())
|
||||
if (!this.configURLs) {
|
||||
Log.info("fetch wx waiting on config URLs");
|
||||
return;
|
||||
}
|
||||
this.fetchData(this.stationObsURL)
|
||||
.then((data) => {
|
||||
if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) {
|
||||
if (!data || !data.properties) {
|
||||
// Did not receive usable new data.
|
||||
// Maybe this needs a better check?
|
||||
return;
|
||||
}
|
||||
|
||||
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties.periods[0]);
|
||||
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties);
|
||||
this.setCurrentWeather(currentWeather);
|
||||
})
|
||||
.catch(function (request) {
|
||||
Log.error("Could not load data ... ", request);
|
||||
Log.error("Could not load station obs data ... ", request);
|
||||
})
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
// Overwrite the fetchCurrentWeather method.
|
||||
// Overwrite the fetchWeatherForecast method.
|
||||
fetchWeatherForecast() {
|
||||
this.fetchData(this.getUrl())
|
||||
if (!this.configURLs) {
|
||||
Log.info("fetch wx waiting on config URLs");
|
||||
return;
|
||||
}
|
||||
this.fetchData(this.forecastURL)
|
||||
.then((data) => {
|
||||
if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) {
|
||||
// Did not receive usable new data.
|
||||
// Maybe this needs a better check?
|
||||
return;
|
||||
}
|
||||
|
||||
const forecast = this.generateWeatherObjectsFromForecast(data.properties.periods);
|
||||
this.setWeatherForecast(forecast);
|
||||
})
|
||||
.catch(function (request) {
|
||||
Log.error("Could not load data ... ", request);
|
||||
Log.error("Could not load forecast hourly data ... ", request);
|
||||
})
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
/** Weather.gov Specific Methods - These are not part of the default provider methods */
|
||||
|
||||
/*
|
||||
* Gets the complete url for the request
|
||||
* Get specific URLs
|
||||
*/
|
||||
getUrl() {
|
||||
return this.config.apiBase + this.config.lat + "," + this.config.lon + this.config.weatherEndpoint;
|
||||
fetchWxGovURLs(config) {
|
||||
this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`)
|
||||
.then((data) => {
|
||||
if (!data || !data.properties) {
|
||||
// points URL did not respond with usable data.
|
||||
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.forecastHourlyURL = data.properties.forecastHourly;
|
||||
this.forecastGridDataURL = data.properties.forecastGridData;
|
||||
this.observationStationsURL = data.properties.observationStations;
|
||||
// with this URL, we chain another promise for the station obs URL
|
||||
return this.fetchData(data.properties.observationStations);
|
||||
})
|
||||
.then((obsData) => {
|
||||
if (!obsData || !obsData.features) {
|
||||
// obs station URL did not respond with usable data.
|
||||
return;
|
||||
}
|
||||
this.stationObsURL = obsData.features[0].id + "/observations/latest";
|
||||
})
|
||||
.catch((err) => {
|
||||
Log.error(err);
|
||||
})
|
||||
.finally(() => {
|
||||
// excellent, let's fetch some actual wx data
|
||||
this.configURLs = true;
|
||||
this.fetchCurrentWeather();
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||
|
||||
currentWeather.temperature = currentWeatherData.temperature;
|
||||
currentWeather.windSpeed = currentWeatherData.windSpeed.split(" ", 1);
|
||||
currentWeather.windDirection = this.convertWindDirection(currentWeatherData.windDirection);
|
||||
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.shortForecast, currentWeatherData.isDaytime);
|
||||
currentWeather.date = moment(currentWeatherData.timestamp);
|
||||
currentWeather.temperature = this.convertTemp(currentWeatherData.temperature.value);
|
||||
currentWeather.windSpeed = this.covertSpeed(currentWeatherData.windSpeed.value);
|
||||
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
|
||||
let times = this.calcAstroData(this.config.lat, this.config.lon);
|
||||
@@ -124,7 +203,7 @@ WeatherProvider.register("weathergov", {
|
||||
// specify date
|
||||
weather.date = moment(forecast.startTime);
|
||||
|
||||
// If the first value of today is later than 17:00, we have an icon at least!
|
||||
// use the forecast isDayTime attribute to help build the weatherType label
|
||||
weather.weatherType = this.convertWeatherType(forecast.shortForecast, forecast.isDaytime);
|
||||
}
|
||||
|
||||
@@ -148,6 +227,34 @@ WeatherProvider.register("weathergov", {
|
||||
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
|
||||
*/
|
||||
|
@@ -1,83 +0,0 @@
|
||||
{% if wData %}
|
||||
{% set current = wData.current %}
|
||||
{% if not config.onlyTemp %}
|
||||
<div class="normal medium">
|
||||
<span class="wi wi-strong-wind dimmed"></span>
|
||||
<span>
|
||||
{% if config.useBeaufort %}
|
||||
{{ current.beaufortWindSpeed() | round }}
|
||||
{% else %}
|
||||
{{ current.windSpeed | round }}
|
||||
{% endif %}
|
||||
{% if config.showWindDirection %}
|
||||
<sup>
|
||||
{% if config.showWindDirectionAsArrow %}
|
||||
<i class="fa fa-long-arrow-up" style="transform:rotate({{ current.windDirection }}deg);"></i>
|
||||
{% else %}
|
||||
{{ current.cardinalWindDirection() | translate }}
|
||||
{% endif %}
|
||||
|
||||
</sup>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if config.showHumidity and current.humidity %}
|
||||
<span>{{ current.humidity | decimalSymbol }}</span><sup> <i class="wi wi-humidity humidityIcon"></i></sup>
|
||||
{% endif %}
|
||||
{% if config.showSun %}
|
||||
<span class="wi dimmed wi-{{ current.nextSunAction() }}"></span>
|
||||
<span>
|
||||
{% if current.nextSunAction() === "sunset" %}
|
||||
{{ current.sunset | formatTime }}
|
||||
{% else %}
|
||||
{{ current.sunrise | formatTime }}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="large light">
|
||||
<span class="wi weathericon wi-{{current.weatherType}}"></span>
|
||||
<span class="bright">
|
||||
{{ current.temperature | roundValue | unit("temperature") | decimalSymbol }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="normal light indoor">
|
||||
{% if config.showIndoorTemperature and indoor.temperature %}
|
||||
<div>
|
||||
<span class="fa fa-home"></span>
|
||||
<span class="bright">
|
||||
{{ indoor.temperature | roundValue | unit("temperature") | decimalSymbol }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if config.showIndoorHumidity and indoor.humidity %}
|
||||
<div>
|
||||
<span class="fa fa-tint"></span>
|
||||
<span class="bright">
|
||||
{{ indoor.humidity | roundValue | unit("humidity") | decimalSymbol }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if (config.showFeelsLike or config.showPrecipitationAmount) and not config.onlyTemp %}
|
||||
<div class="normal medium">
|
||||
{% if config.showFeelsLike %}
|
||||
<span class="dimmed">
|
||||
{{ "FEELS" | translate }} {{ current.feelsLike() | roundValue | unit("temperature") | decimalSymbol }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if config.showPrecipitationAmount %}
|
||||
<span class="dimmed">
|
||||
{{ "PRECIP" | translate }} {{ current.precipitation | unit("precip") }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="dimmed light small">
|
||||
{{ "LOADING" | translate | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Uncomment the line below to see the contents of the `wData` object. -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{wData | dump}}</div> -->
|
@@ -1,32 +0,0 @@
|
||||
{% if wData %}
|
||||
{% set numSteps = wData.days | calcNumEntries %}
|
||||
{% set currentStep = 0 %}
|
||||
<table class="{{ config.tableClass }}">
|
||||
{% set days = wData.days.slice(0, numSteps) %}
|
||||
{% for day in days %}
|
||||
<tr {% if config.colored %}class="colored"{% endif %} {% if config.fade %}style="opacity: {{ currentStep | opacity(numSteps) }};"{% endif %}>
|
||||
<td class="day">{{ day.date.format('ddd') }}</td>
|
||||
<td class="bright weather-icon"><span class="wi weathericon wi-{{ day.weatherType }}"></span></td>
|
||||
<td class="align-right bright max-temp">
|
||||
{{ day.maxTemperature | roundValue | unit("temperature") }}
|
||||
</td>
|
||||
<td class="align-right min-temp">
|
||||
{{ day.minTemperature | roundValue | unit("temperature") }}
|
||||
</td>
|
||||
{% if config.showPrecipitationAmount %}
|
||||
<td class="align-right bright precipitation">
|
||||
{{ day.precipitation | unit("precip") }}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% set currentStep = currentStep + 1 %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="dimmed light small">
|
||||
{{ "LOADING" | translate | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Uncomment the line below to see the contents of the `wData` object. -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{wData | dump}}</div> -->
|
@@ -11,7 +11,7 @@ Module.register("weather", {
|
||||
defaults: {
|
||||
weatherProvider: "openweathermap",
|
||||
roundTemp: false,
|
||||
type: "current", //current, forecast, wDataCurrent, wDataHourly, wDataDaily
|
||||
type: "current",
|
||||
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
@@ -127,6 +127,9 @@ Module.register("weather", {
|
||||
|
||||
// Select the template depending on the display type.
|
||||
getTemplate: function () {
|
||||
if (this.config.type === "daily") {
|
||||
return `forecast.njk`;
|
||||
}
|
||||
return `${this.config.type.toLowerCase()}.njk`;
|
||||
},
|
||||
|
||||
@@ -136,7 +139,7 @@ Module.register("weather", {
|
||||
config: this.config,
|
||||
current: this.weatherProvider.currentWeather(),
|
||||
forecast: this.weatherProvider.weatherForecast(),
|
||||
wData: this.weatherProvider.weatherData(),
|
||||
weatherData: this.weatherProvider.weatherData(),
|
||||
indoor: {
|
||||
humidity: this.indoorHumidity,
|
||||
temperature: this.indoorTemperature
|
||||
@@ -158,12 +161,12 @@ Module.register("weather", {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.config.type === "forecast") {
|
||||
this.weatherProvider.fetchWeatherForecast();
|
||||
} else if (this.config.type === "current") {
|
||||
this.weatherProvider.fetchCurrentWeather();
|
||||
} else {
|
||||
if (this.config.weatherEndpoint === "/onecall") {
|
||||
this.weatherProvider.fetchWeatherData();
|
||||
} else if (this.config.type === "forecast") {
|
||||
this.weatherProvider.fetchWeatherForecast();
|
||||
} else {
|
||||
this.weatherProvider.fetchCurrentWeather();
|
||||
}
|
||||
}, nextLoad);
|
||||
},
|
||||
|
Reference in New Issue
Block a user