mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-29 12:39:45 +00:00
added OpenWeatherMap One Call API function to default Weather module, added wDataHourly type
This commit is contained in:
parent
fdd389d6b7
commit
4a162543f6
@ -35,7 +35,7 @@ WeatherProvider.register("openweathermap", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
// Overwrite the fetchCurrentWeather method.
|
||||
// Overwrite the fetchWeatherForecast method.
|
||||
fetchWeatherForecast() {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
@ -56,6 +56,27 @@ WeatherProvider.register("openweathermap", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
// Overwrite the fetchWeatherData method.
|
||||
fetchWeatherData() {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
if (!data || !data.list || !data.list.length) {
|
||||
// Did not receive usable new data.
|
||||
// Maybe this needs a better check?
|
||||
return;
|
||||
}
|
||||
|
||||
this.setFetchedLocation(`(${data.lat},${data.lon})`);
|
||||
|
||||
const wData = this.generateWeatherObjectsFromOnecall(data);
|
||||
this.setWeatherData(wData);
|
||||
})
|
||||
.catch(function (request) {
|
||||
Log.error("Could not load data ... ", request);
|
||||
})
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
/** OpenWeatherMap Specific Methods - These are not part of the default provider methods */
|
||||
/*
|
||||
* Gets the complete url for the request
|
||||
@ -95,6 +116,153 @@ WeatherProvider.register("openweathermap", {
|
||||
return days;
|
||||
},
|
||||
|
||||
/*
|
||||
* Generate WeatherObjects based on One Call forecast information
|
||||
*/
|
||||
generateWeatherObjectsFromOnecall(data) {
|
||||
if (this.config.weatherEndpoint === "/onecall") {
|
||||
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;
|
||||
},
|
||||
|
||||
/*
|
||||
* fetch One Call forecast information (available for free subscription).
|
||||
* factors in timezone offsets.
|
||||
* minutely forecasts are excluded for the moment, see getParams().
|
||||
*/
|
||||
fetchOnecall(data) {
|
||||
let precip = false;
|
||||
// get current weather
|
||||
const current = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||
if (!isNaN(data.current)) {
|
||||
current.date = moment(data.current.dt, "X").utcOffset(data.timezone_offset/60);
|
||||
current.windSpeed = data.current.wind_speed;
|
||||
current.windDirection = data.current.wind_deg;
|
||||
current.sunrise = moment(data.current.sunrise, "X").utcOffset(data.timezone_offset/60);
|
||||
current.sunset = moment(data.current.sunset, "X").utcOffset(data.timezone_offset/60);
|
||||
current.temperature = data.current.temp;
|
||||
current.weatherType = this.convertWeatherType(data.current.weather[0].icon);
|
||||
current.humidity = data.current.humidity;
|
||||
if (!isNaN(data.current.rain)) {
|
||||
current.rain = data.current.rain.1h;
|
||||
precip = true;
|
||||
}
|
||||
if (!isNaN(data.current.snow)) {
|
||||
current.snow = data.current.snow.1h;
|
||||
precip = true;
|
||||
}
|
||||
if (precip) {
|
||||
current.precipitation = current.rain+current.snow;
|
||||
}
|
||||
current.feelsLikeTemp = data.current.feels_like;
|
||||
}
|
||||
|
||||
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||
|
||||
// let onecallDailyFormat = "MMM DD"
|
||||
// let onecallHourlyFormat = "HH"
|
||||
// let onecallMinutelyFormat = "HH:mm"
|
||||
// if (this.config.timeFormat === 12) {
|
||||
// if (this.config.showPeriod === true) {
|
||||
// if (this.config.showPeriodUpper === true) {
|
||||
// onecallHourlyFormat = "hhA"
|
||||
// onecallMinutelyFormat = "hh:mmA"
|
||||
// } else {
|
||||
// onecallHourlyFormat = "hha"
|
||||
// onecallMinutelyFormat = "hh:mma"
|
||||
// }
|
||||
// } else {
|
||||
// onecallHourlyFormat = "hh"
|
||||
// onecallMinutelyFormat = "hh:mm"
|
||||
// }
|
||||
// }
|
||||
|
||||
// get hourly weather
|
||||
const hours = [];
|
||||
if (!isNaN(data.hourly)) {
|
||||
for (const hour of data.hourly) {
|
||||
weather.date = moment(hour.dt, "X").utcOffset(data.timezone_offset/60);
|
||||
// weather.date = moment(hour.dt, "X").utcOffset(data.timezone_offset/60).format(onecallDailyFormat+","+onecallHourlyFormat);
|
||||
weather.temperature = hour.temp;
|
||||
weather.feelsLikeTemp = hour.feels_like;
|
||||
weather.humidity = hour.humidity;
|
||||
weather.windSpeed = hour.wind_speed;
|
||||
weather.windDirection = hour.wind_deg;
|
||||
weather.weatherType = this.convertWeatherType(hour.weather[0].icon);
|
||||
precip = false;
|
||||
if (!isNaN(hour.rain)) {
|
||||
if (this.config.units === "imperial") {
|
||||
weather.rain = hour.rain.1h / 25.4;
|
||||
} else {
|
||||
weather.rain = hour.rain.1h;
|
||||
}
|
||||
precip = true;
|
||||
}
|
||||
if (!isNaN(hour.snow)) {
|
||||
if (this.config.units === "imperial") {
|
||||
weather.snow = hour.snow.1h / 25.4;
|
||||
} else {
|
||||
weather.snow = hour.snow.1h;
|
||||
}
|
||||
precip = true;
|
||||
}
|
||||
if (precip) {
|
||||
weather.precipitation = weather.rain+weather.snow;
|
||||
}
|
||||
|
||||
hours.push(weather);
|
||||
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||
}
|
||||
}
|
||||
|
||||
// get daily weather
|
||||
const days = [];
|
||||
if (!isNaN(data.daily)) {
|
||||
for (const day of data.daily) {
|
||||
weather.date = moment(day.dt, "X").utcOffset(data.timezone_offset/60);
|
||||
weather.sunrise = moment(day.sunrise, "X").utcOffset(data.timezone_offset/60);
|
||||
weather.sunset = moment(day.sunset, "X").utcOffset(data.timezone_offset/60);
|
||||
// weather.date = moment(day.dt, "X").utcOffset(data.timezone_offset/60).format(onecallDailyFormat);
|
||||
// weather.sunrise = moment(day.sunrise, "X").utcOffset(data.timezone_offset/60).format(onecallMinutelyFormat);
|
||||
// weather.sunset = moment(day.sunset, "X").utcOffset(data.timezone_offset/60).format(onecallMinutelyFormat);
|
||||
weather.minTemperature = day.temp.min;
|
||||
weather.maxTemperature = day.temp.max;
|
||||
weather.humidity = day.humidity;
|
||||
weather.windSpeed = day.wind_speed;
|
||||
weather.windDirection = day.wind_deg;
|
||||
weather.weatherType = this.convertWeatherType(day.weather[0].icon);
|
||||
precip = false;
|
||||
if (!isNaN(day.rain)) {
|
||||
if (this.config.units === "imperial") {
|
||||
weather.rain = day.rain / 25.4;
|
||||
} else {
|
||||
weather.rain = day.rain;
|
||||
}
|
||||
precip = true;
|
||||
}
|
||||
if (!isNaN(day.snow)) {
|
||||
if (this.config.units === "imperial") {
|
||||
weather.snow = day.snow / 25.4;
|
||||
} else {
|
||||
weather.snow = day.snow;
|
||||
}
|
||||
precip = true;
|
||||
}
|
||||
if (precip) {
|
||||
weather.precipitation = weather.rain+weather.snow;
|
||||
}
|
||||
|
||||
days.push(weather);
|
||||
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||
}
|
||||
}
|
||||
|
||||
return {current: current, hours: hours, days: days};
|
||||
},
|
||||
|
||||
/*
|
||||
* fetch forecast information for 3-hourly forecast (available for free subscription).
|
||||
*/
|
||||
@ -256,7 +424,19 @@ WeatherProvider.register("openweathermap", {
|
||||
*/
|
||||
getParams() {
|
||||
let params = "?";
|
||||
if (this.config.locationID) {
|
||||
if (this.config.weatherEndpoint === "/onecall") {
|
||||
params += "lat=" + this.config.lat;
|
||||
params += "&lon=" + this.config.lon;
|
||||
if (this.config.type === "wDataCurrent") {
|
||||
params += "&exclude=minutely,hourly,daily";
|
||||
} else if (this.config.type === "wDataHourly") {
|
||||
params += "&exclude=current,minutely,daily";
|
||||
} else if (this.config.type === "wDataDaily") {
|
||||
params += "&exclude=current,minutely,hourly";
|
||||
} else {
|
||||
params += "&exclude=minutely";
|
||||
}
|
||||
} else if (this.config.locationID) {
|
||||
params += "id=" + this.config.locationID;
|
||||
} else if (this.config.location) {
|
||||
params += "q=" + this.config.location;
|
||||
|
29
modules/default/weather/wdataHourly.njk
Normal file
29
modules/default/weather/wdataHourly.njk
Normal file
@ -0,0 +1,29 @@
|
||||
{% if wData %}
|
||||
{% set numSteps = wData.hours | calcNumEntries %}
|
||||
{% set currentStep = 0 %}
|
||||
<table class="{{ config.tableClass }}">
|
||||
{% set hours = wData.hours.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="time">{{ hour.date | formatTimeMoment }}</td>
|
||||
<td class="bright weather-icon"><span class="wi weathericon wi-{{ hour.weatherType }}"></span></td>
|
||||
<td class="align-right bright max-temp">
|
||||
{{ hour.temperature | roundValue | unit("temperature") }}
|
||||
</td>
|
||||
{% if config.showPrecipitationAmount %}
|
||||
<td class="align-right bright precipitation">
|
||||
{{ hour.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
|
||||
type: "current", //current, forecast, wDataCurrent, wDataHourly, wDataDaily
|
||||
|
||||
location: false,
|
||||
locationID: false,
|
||||
@ -37,6 +37,7 @@ Module.register("weather", {
|
||||
showIndoorTemperature: false,
|
||||
showIndoorHumidity: false,
|
||||
maxNumberOfDays: 5,
|
||||
maxEntries: 5,
|
||||
fade: true,
|
||||
fadePoint: 0.25, // Start on 1/4th of the list.
|
||||
|
||||
@ -132,6 +133,7 @@ Module.register("weather", {
|
||||
config: this.config,
|
||||
current: this.weatherProvider.currentWeather(),
|
||||
forecast: this.weatherProvider.weatherForecast(),
|
||||
wData: this.weatherProvider.weatherData(),
|
||||
indoor: {
|
||||
humidity: this.indoorHumidity,
|
||||
temperature: this.indoorTemperature
|
||||
@ -153,7 +155,11 @@ Module.register("weather", {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.config.type === "forecast") {
|
||||
if (this.config.type === "wDataCurrent"
|
||||
|| this.config.type === "wDataHourly"
|
||||
|| this.config.type === "wDataDaily") {
|
||||
this.weatherProvider.fetchWeatherData();
|
||||
} else if (this.config.type === "forecast") {
|
||||
this.weatherProvider.fetchWeatherForecast();
|
||||
} else {
|
||||
this.weatherProvider.fetchCurrentWeather();
|
||||
@ -187,6 +193,25 @@ Module.register("weather", {
|
||||
return date.format("HH:mm");
|
||||
}.bind(this)
|
||||
);
|
||||
this.nunjucksEnvironment().addFilter(
|
||||
"formatTimeMoment",
|
||||
function (date) {
|
||||
|
||||
if (this.config.timeFormat !== 24) {
|
||||
if (this.config.showPeriod) {
|
||||
if (this.config.showPeriodUpper) {
|
||||
return date.format("h:mm A");
|
||||
} else {
|
||||
return date.format("h:mm a");
|
||||
}
|
||||
} else {
|
||||
return date.format("h:mm");
|
||||
}
|
||||
}
|
||||
|
||||
return date.format("HH:mm");
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
this.nunjucksEnvironment().addFilter(
|
||||
"unit",
|
||||
@ -243,6 +268,13 @@ Module.register("weather", {
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
this.nunjucksEnvironment().addFilter(
|
||||
"calcNumEntries",
|
||||
function (dataArray) {
|
||||
return Math.min(dataArray.length, this.config.maxNumberOfEntries);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
this.nunjucksEnvironment().addFilter(
|
||||
"opacity",
|
||||
function (currentStep, numSteps) {
|
||||
|
@ -16,6 +16,7 @@ var WeatherProvider = Class.extend({
|
||||
// Try to not access them directly.
|
||||
currentWeatherObject: null,
|
||||
weatherForecastArray: null,
|
||||
weatherDataObject: null,
|
||||
fetchedLocationName: null,
|
||||
|
||||
// The following properties will be set automatically.
|
||||
@ -56,6 +57,12 @@ var WeatherProvider = Class.extend({
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherForecast method.`);
|
||||
},
|
||||
|
||||
// This method should start the API request to fetch the weather forecast.
|
||||
// This method should definitely be overwritten in the provider.
|
||||
fetchWeatherData: function () {
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherData method.`);
|
||||
},
|
||||
|
||||
// This returns a WeatherDay object for the current weather.
|
||||
currentWeather: function () {
|
||||
return this.currentWeatherObject;
|
||||
@ -66,6 +73,11 @@ var WeatherProvider = Class.extend({
|
||||
return this.weatherForecastArray;
|
||||
},
|
||||
|
||||
// This returns an object containing WeatherDay object(s) depending on the type of call.
|
||||
weatherData: function () {
|
||||
return this.weatherDataObject;
|
||||
},
|
||||
|
||||
// This returns the name of the fetched location or an empty string.
|
||||
fetchedLocation: function () {
|
||||
return this.fetchedLocationName || "";
|
||||
@ -83,6 +95,12 @@ var WeatherProvider = Class.extend({
|
||||
this.weatherForecastArray = weatherForecastArray;
|
||||
},
|
||||
|
||||
// Set the weatherDataObject and notify the delegate that new information is available.
|
||||
setWeatherData: function (weatherDataObject) {
|
||||
// We should check here if we are passing a WeatherDay
|
||||
this.weatherDataObject = weatherDataObject;
|
||||
},
|
||||
|
||||
// Set the fetched location name.
|
||||
setFetchedLocation: function (name) {
|
||||
this.fetchedLocationName = name;
|
||||
|
Loading…
x
Reference in New Issue
Block a user