mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-27 03:39:55 +00:00
Use metric units internally in all weatherproviders (#2849)
So finally I think this refactorin is ready to be reviewed :-) DONE: - [x] Removed all conversion functions for wind and temperature from specific weatherproviders - [x] Use internally only metric units: celsius for temperature, meters per seconds for wind - [x] Convert temp and wind into the configured units when displaying data on the UI - [x] look how beaufort calculation uses metrics, added knots as new windunit - [x] add more e2e tests Checked providers: - [x] Darksky - [x] EnvCanada - [x] OpenWeatherMap - [x] SMHI provider - [x] UK Met Office - [x] UK Met Office DataHub - [x] WeatherBit - [x] WeatherFlow - [x] WeatherGov TODO in different tickets: - check weatherproviders for usage of weatherEndpoint (as seen in https://github.com/MichMich/MagicMirror-Documentation/issues/131) -> see #2926 - cleanup precipations -> #2953 Co-authored-by: veeck <michael@veeck.de>
This commit is contained in:
parent
64ed5a54cb
commit
2d3940a4ff
@ -28,6 +28,7 @@ Special thanks to: @rejas, @sdetweil
|
|||||||
- Updated da translation
|
- Updated da translation
|
||||||
- Rework weather module
|
- Rework weather module
|
||||||
- Use fetch instead of XMLHttpRequest in weatherprovider
|
- Use fetch instead of XMLHttpRequest in weatherprovider
|
||||||
|
- Reworked how weatherproviders handle units
|
||||||
- Use unix() method for parsing times, fix suntimes on the way
|
- Use unix() method for parsing times, fix suntimes on the way
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
@ -3,15 +3,7 @@
|
|||||||
<div class="normal medium">
|
<div class="normal medium">
|
||||||
<span class="wi wi-strong-wind dimmed"></span>
|
<span class="wi wi-strong-wind dimmed"></span>
|
||||||
<span>
|
<span>
|
||||||
{% if config.useBeaufort %}
|
{{ current.windSpeed | unit("wind") | round }}
|
||||||
{{ current.beaufortWindSpeed() | round }}
|
|
||||||
{% else %}
|
|
||||||
{% if config.useKmh %}
|
|
||||||
{{ current.kmhWindSpeed() | round }}
|
|
||||||
{% else %}
|
|
||||||
{{ current.windSpeed | round }}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if config.showWindDirection %}
|
{% if config.showWindDirection %}
|
||||||
<sup>
|
<sup>
|
||||||
{% if config.showWindDirectionAsArrow %}
|
{% if config.showWindDirectionAsArrow %}
|
||||||
|
@ -26,11 +26,6 @@ WeatherProvider.register("darksky", {
|
|||||||
lon: 0
|
lon: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
units: {
|
|
||||||
imperial: "us",
|
|
||||||
metric: "si"
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
@ -67,13 +62,12 @@ WeatherProvider.register("darksky", {
|
|||||||
|
|
||||||
// Create a URL from the config and base URL.
|
// Create a URL from the config and base URL.
|
||||||
getUrl() {
|
getUrl() {
|
||||||
const units = this.units[this.config.units] || "auto";
|
return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=si&lang=${this.config.lang}`;
|
||||||
return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=${units}&lang=${this.config.lang}`;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Implement WeatherDay generator.
|
// Implement WeatherDay generator.
|
||||||
generateWeatherDayFromCurrentWeather(currentWeatherData) {
|
generateWeatherDayFromCurrentWeather(currentWeatherData) {
|
||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const currentWeather = new WeatherObject();
|
||||||
|
|
||||||
currentWeather.date = moment();
|
currentWeather.date = moment();
|
||||||
currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity);
|
currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity);
|
||||||
@ -91,7 +85,7 @@ WeatherProvider.register("darksky", {
|
|||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
for (const forecast of forecasts) {
|
for (const forecast of forecasts) {
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const weather = new WeatherObject();
|
||||||
|
|
||||||
weather.date = moment.unix(forecast.time);
|
weather.date = moment.unix(forecast.time);
|
||||||
weather.minTemperature = forecast.temperatureMin;
|
weather.minTemperature = forecast.temperatureMin;
|
||||||
|
@ -11,13 +11,13 @@
|
|||||||
* https://dd.weather.gc.ca/citypage_weather/schema/
|
* https://dd.weather.gc.ca/citypage_weather/schema/
|
||||||
* https://eccc-msc.github.io/open-data/msc-datamart/readme_en/
|
* https://eccc-msc.github.io/open-data/msc-datamart/readme_en/
|
||||||
*
|
*
|
||||||
* This module supports Canadian locations only and requires 2 additional config parms:
|
* This module supports Canadian locations only and requires 2 additional config parameters:
|
||||||
*
|
*
|
||||||
* siteCode - the city/town unique identifier for which weather is to be displayed. Format is 's0000000'.
|
* siteCode - the city/town unique identifier for which weather is to be displayed. Format is 's0000000'.
|
||||||
*
|
*
|
||||||
* provCode - the 2-character province code for the selected city/town.
|
* provCode - the 2-character province code for the selected city/town.
|
||||||
*
|
*
|
||||||
* Example: for Toronto, Ontario, the following parms would be used
|
* Example: for Toronto, Ontario, the following parameters would be used
|
||||||
*
|
*
|
||||||
* siteCode: 's0000458',
|
* siteCode: 's0000458',
|
||||||
* provCode: 'ON'
|
* provCode: 'ON'
|
||||||
@ -64,10 +64,6 @@ WeatherProvider.register("envcanada", {
|
|||||||
start: function () {
|
start: function () {
|
||||||
Log.info(`Weather provider: ${this.providerName} started.`);
|
Log.info(`Weather provider: ${this.providerName} started.`);
|
||||||
this.setFetchedLocation(this.config.location);
|
this.setFetchedLocation(this.config.location);
|
||||||
|
|
||||||
// Ensure kmH are ignored since these are custom-handled by this Provider
|
|
||||||
|
|
||||||
this.config.useKmh = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -150,7 +146,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
//
|
//
|
||||||
|
|
||||||
generateWeatherObjectFromCurrentWeather(ECdoc) {
|
generateWeatherObjectFromCurrentWeather(ECdoc) {
|
||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
const currentWeather = new WeatherObject();
|
||||||
|
|
||||||
// There are instances where EC will update weather data and current temperature will not be
|
// There are instances where EC will update weather data and current temperature will not be
|
||||||
// provided. While this is a defect in the EC systems, we need to accommodate to avoid a current temp
|
// provided. While this is a defect in the EC systems, we need to accommodate to avoid a current temp
|
||||||
@ -161,13 +157,13 @@ WeatherProvider.register("envcanada", {
|
|||||||
// EC finds no current temp. In this scenario, MM will end up displaying a current temp of null;
|
// EC finds no current temp. In this scenario, MM will end up displaying a current temp of null;
|
||||||
|
|
||||||
if (ECdoc.querySelector("siteData currentConditions temperature").textContent) {
|
if (ECdoc.querySelector("siteData currentConditions temperature").textContent) {
|
||||||
currentWeather.temperature = this.convertTemp(ECdoc.querySelector("siteData currentConditions temperature").textContent);
|
currentWeather.temperature = ECdoc.querySelector("siteData currentConditions temperature").textContent;
|
||||||
this.cacheCurrentTemp = currentWeather.temperature;
|
this.cacheCurrentTemp = currentWeather.temperature;
|
||||||
} else {
|
} else {
|
||||||
currentWeather.temperature = this.cacheCurrentTemp;
|
currentWeather.temperature = this.cacheCurrentTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentWeather.windSpeed = this.convertWind(ECdoc.querySelector("siteData currentConditions wind speed").textContent);
|
currentWeather.windSpeed = currentWeather.convertWindToMs(ECdoc.querySelector("siteData currentConditions wind speed").textContent);
|
||||||
|
|
||||||
currentWeather.windDirection = ECdoc.querySelector("siteData currentConditions wind bearing").textContent;
|
currentWeather.windDirection = ECdoc.querySelector("siteData currentConditions wind bearing").textContent;
|
||||||
|
|
||||||
@ -190,11 +186,11 @@ WeatherProvider.register("envcanada", {
|
|||||||
currentWeather.feelsLikeTemp = currentWeather.temperature;
|
currentWeather.feelsLikeTemp = currentWeather.temperature;
|
||||||
|
|
||||||
if (ECdoc.querySelector("siteData currentConditions windChill")) {
|
if (ECdoc.querySelector("siteData currentConditions windChill")) {
|
||||||
currentWeather.feelsLikeTemp = this.convertTemp(ECdoc.querySelector("siteData currentConditions windChill").textContent);
|
currentWeather.feelsLikeTemp = ECdoc.querySelector("siteData currentConditions windChill").textContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ECdoc.querySelector("siteData currentConditions humidex")) {
|
if (ECdoc.querySelector("siteData currentConditions humidex")) {
|
||||||
currentWeather.feelsLikeTemp = this.convertTemp(ECdoc.querySelector("siteData currentConditions humidex").textContent);
|
currentWeather.feelsLikeTemp = ECdoc.querySelector("siteData currentConditions humidex").textContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +221,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
|
|
||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
const weather = new WeatherObject();
|
||||||
|
|
||||||
const foreBaseDates = ECdoc.querySelectorAll("siteData forecastGroup dateTime");
|
const foreBaseDates = ECdoc.querySelectorAll("siteData forecastGroup dateTime");
|
||||||
const baseDate = foreBaseDates[1].querySelector("timeStamp").textContent;
|
const baseDate = foreBaseDates[1].querySelector("timeStamp").textContent;
|
||||||
@ -326,7 +322,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
days.push(weather);
|
days.push(weather);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Now do the the rest of the forecast starting at nextDay. We will process each day using 2 EC
|
// Now do the rest of the forecast starting at nextDay. We will process each day using 2 EC
|
||||||
// forecast Elements. This will address the fact that the EC forecast always includes Today and
|
// forecast Elements. This will address the fact that the EC forecast always includes Today and
|
||||||
// Tonight for each day. This is why we iterate through the forecast by a a count of 2, with each
|
// Tonight for each day. This is why we iterate through the forecast by a a count of 2, with each
|
||||||
// iteration looking at the current Element and the next Element.
|
// iteration looking at the current Element and the next Element.
|
||||||
@ -335,7 +331,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
let lastDate = moment(baseDate, "YYYYMMDDhhmmss");
|
let lastDate = moment(baseDate, "YYYYMMDDhhmmss");
|
||||||
|
|
||||||
for (let stepDay = nextDay; stepDay < lastDay; stepDay += 2) {
|
for (let stepDay = nextDay; stepDay < lastDay; stepDay += 2) {
|
||||||
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
let weather = new WeatherObject();
|
||||||
|
|
||||||
// Add 1 to the date to reflect the current forecast day we are building
|
// Add 1 to the date to reflect the current forecast day we are building
|
||||||
|
|
||||||
@ -389,7 +385,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
const hourGroup = ECdoc.querySelectorAll("siteData hourlyForecastGroup hourlyForecast");
|
const hourGroup = ECdoc.querySelectorAll("siteData hourlyForecastGroup hourlyForecast");
|
||||||
|
|
||||||
for (let stepHour = 0; stepHour < 24; stepHour += 1) {
|
for (let stepHour = 0; stepHour < 24; stepHour += 1) {
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
const weather = new WeatherObject();
|
||||||
|
|
||||||
// Determine local time by applying UTC offset to the forecast timestamp
|
// Determine local time by applying UTC offset to the forecast timestamp
|
||||||
|
|
||||||
@ -399,7 +395,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
|
|
||||||
// Capture the temperature
|
// Capture the temperature
|
||||||
|
|
||||||
weather.temperature = this.convertTemp(hourGroup[stepHour].querySelector("temperature").textContent);
|
weather.temperature = hourGroup[stepHour].querySelector("temperature").textContent;
|
||||||
|
|
||||||
// Capture Likelihood of Precipitation (LOP) and unit-of-measure values
|
// Capture Likelihood of Precipitation (LOP) and unit-of-measure values
|
||||||
|
|
||||||
@ -450,7 +446,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
weather.minTemperature = this.todayTempCacheMin;
|
weather.minTemperature = this.todayTempCacheMin;
|
||||||
weather.maxTemperature = this.todayTempCacheMax;
|
weather.maxTemperature = this.todayTempCacheMax;
|
||||||
} else {
|
} else {
|
||||||
weather.minTemperature = this.convertTemp(currentTemp);
|
weather.minTemperature = currentTemp;
|
||||||
weather.maxTemperature = weather.minTemperature;
|
weather.maxTemperature = weather.minTemperature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -463,14 +459,14 @@ WeatherProvider.register("envcanada", {
|
|||||||
//
|
//
|
||||||
|
|
||||||
if (todayClass === "low") {
|
if (todayClass === "low") {
|
||||||
weather.minTemperature = this.convertTemp(todayTemp);
|
weather.minTemperature = todayTemp;
|
||||||
if (today === 0 && fullDay === true) {
|
if (today === 0 && fullDay === true) {
|
||||||
this.todayTempCacheMin = weather.minTemperature;
|
this.todayTempCacheMin = weather.minTemperature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (todayClass === "high") {
|
if (todayClass === "high") {
|
||||||
weather.maxTemperature = this.convertTemp(todayTemp);
|
weather.maxTemperature = todayTemp;
|
||||||
if (today === 0 && fullDay === true) {
|
if (today === 0 && fullDay === true) {
|
||||||
this.todayTempCacheMax = weather.maxTemperature;
|
this.todayTempCacheMax = weather.maxTemperature;
|
||||||
}
|
}
|
||||||
@ -482,11 +478,11 @@ WeatherProvider.register("envcanada", {
|
|||||||
|
|
||||||
if (fullDay === true) {
|
if (fullDay === true) {
|
||||||
if (nextClass === "low") {
|
if (nextClass === "low") {
|
||||||
weather.minTemperature = this.convertTemp(nextTemp);
|
weather.minTemperature = nextTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextClass === "high") {
|
if (nextClass === "high") {
|
||||||
weather.maxTemperature = this.convertTemp(nextTemp);
|
weather.maxTemperature = nextTemp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -536,31 +532,6 @@ WeatherProvider.register("envcanada", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//
|
|
||||||
// Unit conversions
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Convert C to F temps
|
|
||||||
//
|
|
||||||
convertTemp(temp) {
|
|
||||||
if (this.config.tempUnits === "imperial") {
|
|
||||||
return 1.8 * temp + 32;
|
|
||||||
} else {
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
//
|
|
||||||
// Convert km/h to mph
|
|
||||||
//
|
|
||||||
convertWind(kilo) {
|
|
||||||
if (this.config.windUnits === "imperial") {
|
|
||||||
return kilo / 1.609344;
|
|
||||||
} else {
|
|
||||||
return kilo;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Convert the icons to a more usable name.
|
// Convert the icons to a more usable name.
|
||||||
//
|
//
|
||||||
|
@ -30,14 +30,14 @@ WeatherProvider.register("openweathermap", {
|
|||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
let currentWeather;
|
||||||
if (this.config.weatherEndpoint === "/onecall") {
|
if (this.config.weatherEndpoint === "/onecall") {
|
||||||
const weatherData = this.generateWeatherObjectsFromOnecall(data);
|
currentWeather = this.generateWeatherObjectsFromOnecall(data).current;
|
||||||
this.setCurrentWeather(weatherData.current);
|
|
||||||
this.setFetchedLocation(`${data.timezone}`);
|
this.setFetchedLocation(`${data.timezone}`);
|
||||||
} else {
|
} else {
|
||||||
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
|
currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
|
||||||
this.setCurrentWeather(currentWeather);
|
|
||||||
}
|
}
|
||||||
|
this.setCurrentWeather(currentWeather);
|
||||||
})
|
})
|
||||||
.catch(function (request) {
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
@ -49,15 +49,17 @@ WeatherProvider.register("openweathermap", {
|
|||||||
fetchWeatherForecast() {
|
fetchWeatherForecast() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
let forecast;
|
||||||
|
let location;
|
||||||
if (this.config.weatherEndpoint === "/onecall") {
|
if (this.config.weatherEndpoint === "/onecall") {
|
||||||
const weatherData = this.generateWeatherObjectsFromOnecall(data);
|
forecast = this.generateWeatherObjectsFromOnecall(data).days;
|
||||||
this.setWeatherForecast(weatherData.days);
|
location = `${data.timezone}`;
|
||||||
this.setFetchedLocation(`${data.timezone}`);
|
|
||||||
} else {
|
} else {
|
||||||
const forecast = this.generateWeatherObjectsFromForecast(data.list);
|
forecast = this.generateWeatherObjectsFromForecast(data.list);
|
||||||
this.setWeatherForecast(forecast);
|
location = `${data.city.name}, ${data.city.country}`;
|
||||||
this.setFetchedLocation(`${data.city.name}, ${data.city.country}`);
|
|
||||||
}
|
}
|
||||||
|
this.setWeatherForecast(forecast);
|
||||||
|
this.setFetchedLocation(location);
|
||||||
})
|
})
|
||||||
.catch(function (request) {
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
@ -123,8 +125,9 @@ WeatherProvider.register("openweathermap", {
|
|||||||
* Generate a WeatherObject based on currentWeatherInformation
|
* Generate a WeatherObject based on currentWeatherInformation
|
||||||
*/
|
*/
|
||||||
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const currentWeather = new WeatherObject();
|
||||||
|
|
||||||
|
currentWeather.date = moment.unix(currentWeatherData.dt);
|
||||||
currentWeather.humidity = currentWeatherData.main.humidity;
|
currentWeather.humidity = currentWeatherData.main.humidity;
|
||||||
currentWeather.temperature = currentWeatherData.main.temp;
|
currentWeather.temperature = currentWeatherData.main.temp;
|
||||||
currentWeather.feelsLikeTemp = currentWeatherData.main.feels_like;
|
currentWeather.feelsLikeTemp = currentWeatherData.main.feels_like;
|
||||||
@ -147,7 +150,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
return this.fetchForecastDaily(forecasts);
|
return this.fetchForecastDaily(forecasts);
|
||||||
}
|
}
|
||||||
// if weatherEndpoint does not match forecast or forecast/daily, what should be returned?
|
// if weatherEndpoint does not match forecast or forecast/daily, what should be returned?
|
||||||
return [new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh)];
|
return [new WeatherObject()];
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -158,7 +161,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
return this.fetchOnecall(data);
|
return this.fetchOnecall(data);
|
||||||
}
|
}
|
||||||
// if weatherEndpoint does not match onecall, what should be returned?
|
// if weatherEndpoint does not match onecall, what should be returned?
|
||||||
return { current: new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh), hours: [], days: [] };
|
return { current: new WeatherObject(), hours: [], days: [] };
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -174,7 +177,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
let snow = 0;
|
let snow = 0;
|
||||||
// variable for date
|
// variable for date
|
||||||
let date = "";
|
let date = "";
|
||||||
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
let weather = new WeatherObject();
|
||||||
|
|
||||||
for (const forecast of forecasts) {
|
for (const forecast of forecasts) {
|
||||||
if (date !== moment.unix(forecast.dt).format("YYYY-MM-DD")) {
|
if (date !== moment.unix(forecast.dt).format("YYYY-MM-DD")) {
|
||||||
@ -187,7 +190,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
// push weather information to days array
|
// push weather information to days array
|
||||||
days.push(weather);
|
days.push(weather);
|
||||||
// create new weather-object
|
// create new weather-object
|
||||||
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
weather = new WeatherObject();
|
||||||
|
|
||||||
minTemp = [];
|
minTemp = [];
|
||||||
maxTemp = [];
|
maxTemp = [];
|
||||||
@ -250,7 +253,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
for (const forecast of forecasts) {
|
for (const forecast of forecasts) {
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const weather = new WeatherObject();
|
||||||
|
|
||||||
weather.date = moment.unix(forecast.dt);
|
weather.date = moment.unix(forecast.dt);
|
||||||
weather.minTemperature = forecast.temp.min;
|
weather.minTemperature = forecast.temp.min;
|
||||||
@ -296,7 +299,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
let precip = false;
|
let precip = false;
|
||||||
|
|
||||||
// get current weather, if requested
|
// get current weather, if requested
|
||||||
const current = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const current = new WeatherObject();
|
||||||
if (data.hasOwnProperty("current")) {
|
if (data.hasOwnProperty("current")) {
|
||||||
current.date = moment.unix(data.current.dt).utcOffset(data.timezone_offset / 60);
|
current.date = moment.unix(data.current.dt).utcOffset(data.timezone_offset / 60);
|
||||||
current.windSpeed = data.current.wind_speed;
|
current.windSpeed = data.current.wind_speed;
|
||||||
@ -328,7 +331,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
current.feelsLikeTemp = data.current.feels_like;
|
current.feelsLikeTemp = data.current.feels_like;
|
||||||
}
|
}
|
||||||
|
|
||||||
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
let weather = new WeatherObject();
|
||||||
|
|
||||||
// get hourly weather, if requested
|
// get hourly weather, if requested
|
||||||
const hours = [];
|
const hours = [];
|
||||||
@ -363,7 +366,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hours.push(weather);
|
hours.push(weather);
|
||||||
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
weather = new WeatherObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +405,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
days.push(weather);
|
days.push(weather);
|
||||||
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
weather = new WeatherObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,7 +474,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
params += "&units=" + this.config.units;
|
params += "&units=metric"; // WeatherProviders should use metric internally and use the units only for when displaying data
|
||||||
params += "&lang=" + this.config.lang;
|
params += "&lang=" + this.config.lang;
|
||||||
params += "&APPID=" + this.config.apiKey;
|
params += "&APPID=" + this.config.apiKey;
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ WeatherProvider.register("smhi", {
|
|||||||
setConfig(config) {
|
setConfig(config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
if (!config.precipitationValue || ["pmin", "pmean", "pmedian", "pmax"].indexOf(config.precipitationValue) === -1) {
|
if (!config.precipitationValue || ["pmin", "pmean", "pmedian", "pmax"].indexOf(config.precipitationValue) === -1) {
|
||||||
console.log("invalid or not set: " + config.precipitationValue);
|
Log.log("invalid or not set: " + config.precipitationValue);
|
||||||
config.precipitationValue = this.defaults.precipitationValue;
|
config.precipitationValue = this.defaults.precipitationValue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -134,8 +134,7 @@ WeatherProvider.register("smhi", {
|
|||||||
* @returns {WeatherObject} The converted weatherdata at the specified location
|
* @returns {WeatherObject} The converted weatherdata at the specified location
|
||||||
*/
|
*/
|
||||||
convertWeatherDataToObject(weatherData, coordinates) {
|
convertWeatherDataToObject(weatherData, coordinates) {
|
||||||
// Weather data is only for Sweden and nobody in Sweden would use imperial
|
let currentWeather = new WeatherObject();
|
||||||
let currentWeather = new WeatherObject("metric", "metric", "metric");
|
|
||||||
|
|
||||||
currentWeather.date = moment(weatherData.validTime);
|
currentWeather.date = moment(weatherData.validTime);
|
||||||
currentWeather.updateSunTime(coordinates.lat, coordinates.lon);
|
currentWeather.updateSunTime(coordinates.lat, coordinates.lon);
|
||||||
@ -191,7 +190,7 @@ WeatherProvider.register("smhi", {
|
|||||||
for (const weatherObject of allWeatherObjects) {
|
for (const weatherObject of allWeatherObjects) {
|
||||||
//If its the first object or if a day/hour change we need to reset the summary object
|
//If its the first object or if a day/hour change we need to reset the summary object
|
||||||
if (!currentWeather || !currentWeather.date.isSame(weatherObject.date, groupBy)) {
|
if (!currentWeather || !currentWeather.date.isSame(weatherObject.date, groupBy)) {
|
||||||
currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
currentWeather = new WeatherObject();
|
||||||
dayWeatherTypes = [];
|
dayWeatherTypes = [];
|
||||||
currentWeather.temperature = weatherObject.temperature;
|
currentWeather.temperature = weatherObject.temperature;
|
||||||
currentWeather.date = weatherObject.date;
|
currentWeather.date = weatherObject.date;
|
||||||
|
@ -21,11 +21,6 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
apiKey: ""
|
apiKey: ""
|
||||||
},
|
},
|
||||||
|
|
||||||
units: {
|
|
||||||
imperial: "us",
|
|
||||||
metric: "si"
|
|
||||||
},
|
|
||||||
|
|
||||||
// Overwrite the fetchCurrentWeather method.
|
// Overwrite the fetchCurrentWeather method.
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl("3hourly"))
|
this.fetchData(this.getUrl("3hourly"))
|
||||||
@ -80,7 +75,7 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
* Generate a WeatherObject based on currentWeatherInformation
|
* Generate a WeatherObject based on currentWeatherInformation
|
||||||
*/
|
*/
|
||||||
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const currentWeather = new WeatherObject();
|
||||||
const location = currentWeatherData.SiteRep.DV.Location;
|
const location = currentWeatherData.SiteRep.DV.Location;
|
||||||
|
|
||||||
// data times are always UTC
|
// data times are always UTC
|
||||||
@ -103,11 +98,11 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
if (timeInMins >= p && timeInMins - 180 < p) {
|
if (timeInMins >= p && timeInMins - 180 < p) {
|
||||||
// finally got the one we want, so populate weather object
|
// finally got the one we want, so populate weather object
|
||||||
currentWeather.humidity = rep.H;
|
currentWeather.humidity = rep.H;
|
||||||
currentWeather.temperature = this.convertTemp(rep.T);
|
currentWeather.temperature = rep.T;
|
||||||
currentWeather.feelsLikeTemp = this.convertTemp(rep.F);
|
currentWeather.feelsLikeTemp = rep.F;
|
||||||
currentWeather.precipitation = parseInt(rep.Pp);
|
currentWeather.precipitation = parseInt(rep.Pp);
|
||||||
currentWeather.windSpeed = this.convertWindSpeed(rep.S);
|
currentWeather.windSpeed = currentWeather.convertWindToMetric(rep.S);
|
||||||
currentWeather.windDirection = this.convertWindDirection(rep.D);
|
currentWeather.windDirection = currentWeather.valueWindDirection(rep.D);
|
||||||
currentWeather.weatherType = this.convertWeatherType(rep.W);
|
currentWeather.weatherType = this.convertWeatherType(rep.W);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,7 +125,7 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
// loop round the (5) periods getting the data
|
// loop round the (5) periods getting the data
|
||||||
// for each period array, Day is [0], Night is [1]
|
// for each period array, Day is [0], Night is [1]
|
||||||
for (const period of forecasts.SiteRep.DV.Location.Period) {
|
for (const period of forecasts.SiteRep.DV.Location.Period) {
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const weather = new WeatherObject();
|
||||||
|
|
||||||
// data times are always UTC
|
// data times are always UTC
|
||||||
const dateStr = period.value;
|
const dateStr = period.value;
|
||||||
@ -140,8 +135,8 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
|
if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
|
||||||
// populate the weather object
|
// populate the weather object
|
||||||
weather.date = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD");
|
weather.date = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD");
|
||||||
weather.minTemperature = this.convertTemp(period.Rep[1].Nm);
|
weather.minTemperature = period.Rep[1].Nm;
|
||||||
weather.maxTemperature = this.convertTemp(period.Rep[0].Dm);
|
weather.maxTemperature = period.Rep[0].Dm;
|
||||||
weather.weatherType = this.convertWeatherType(period.Rep[0].W);
|
weather.weatherType = this.convertWeatherType(period.Rep[0].W);
|
||||||
weather.precipitation = parseInt(period.Rep[0].PPd);
|
weather.precipitation = parseInt(period.Rep[0].PPd);
|
||||||
|
|
||||||
@ -192,46 +187,6 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
|
return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert temp (from degrees C) if required
|
|
||||||
*/
|
|
||||||
convertTemp(tempInC) {
|
|
||||||
return this.tempUnits === "imperial" ? (tempInC * 9) / 5 + 32 : tempInC;
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert wind speed (from mph to m/s or km/h) if required
|
|
||||||
*/
|
|
||||||
convertWindSpeed(windInMph) {
|
|
||||||
return this.windUnits === "metric" ? (this.useKmh ? windInMph * 1.60934 : windInMph / 2.23694) : windInMph;
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert the wind direction cardinal to value
|
|
||||||
*/
|
|
||||||
convertWindDirection(windDirection) {
|
|
||||||
const windCardinals = {
|
|
||||||
N: 0,
|
|
||||||
NNE: 22,
|
|
||||||
NE: 45,
|
|
||||||
ENE: 67,
|
|
||||||
E: 90,
|
|
||||||
ESE: 112,
|
|
||||||
SE: 135,
|
|
||||||
SSE: 157,
|
|
||||||
S: 180,
|
|
||||||
SSW: 202,
|
|
||||||
SW: 225,
|
|
||||||
WSW: 247,
|
|
||||||
W: 270,
|
|
||||||
WNW: 292,
|
|
||||||
NW: 315,
|
|
||||||
NNW: 337
|
|
||||||
};
|
|
||||||
|
|
||||||
return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an url with api parameters based on the config.
|
* Generates an url with api parameters based on the config.
|
||||||
*
|
*
|
||||||
|
@ -20,11 +20,9 @@
|
|||||||
* weatherProvider: "ukmetofficedatahub",
|
* weatherProvider: "ukmetofficedatahub",
|
||||||
* apiBase: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/",
|
* apiBase: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/",
|
||||||
* apiKey: "[YOUR API KEY]",
|
* apiKey: "[YOUR API KEY]",
|
||||||
* apiSecret: "[YOUR API SECRET]]",
|
* apiSecret: "[YOUR API SECRET]",
|
||||||
* lat: [LATITUDE (DECIMAL)],
|
* lat: [LATITUDE (DECIMAL)],
|
||||||
* lon: [LONGITUDE (DECIMAL)],
|
* lon: [LONGITUDE (DECIMAL)]
|
||||||
* windUnits: "mps" | "kph" | "mph" (default)
|
|
||||||
* tempUnits: "imperial" | "metric" (default)
|
|
||||||
*
|
*
|
||||||
* At time of writing, free accounts are limited to 360 requests a day per service (hourly, 3hourly, daily); take this in mind when
|
* At time of writing, free accounts are limited to 360 requests a day per service (hourly, 3hourly, daily); take this in mind when
|
||||||
* setting your update intervals. For reference, 360 requests per day is once every 4 minutes.
|
* setting your update intervals. For reference, 360 requests per day is once every 4 minutes.
|
||||||
@ -51,8 +49,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
|||||||
apiKey: "",
|
apiKey: "",
|
||||||
apiSecret: "",
|
apiSecret: "",
|
||||||
lat: 0,
|
lat: 0,
|
||||||
lon: 0,
|
lon: 0
|
||||||
windUnits: "mph"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
|
// Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
|
||||||
@ -115,7 +112,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
|||||||
|
|
||||||
// Create a WeatherObject using current weather data (data for the current hour)
|
// Create a WeatherObject using current weather data (data for the current hour)
|
||||||
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const currentWeather = new WeatherObject();
|
||||||
|
|
||||||
// Extract the actual forecasts
|
// Extract the actual forecasts
|
||||||
let forecastDataHours = currentWeatherData.features[0].properties.timeSeries;
|
let forecastDataHours = currentWeatherData.features[0].properties.timeSeries;
|
||||||
@ -128,17 +125,17 @@ WeatherProvider.register("ukmetofficedatahub", {
|
|||||||
let forecastTime = moment.utc(forecastDataHours[hour].time);
|
let forecastTime = moment.utc(forecastDataHours[hour].time);
|
||||||
if (nowUtc.isSameOrAfter(forecastTime) && nowUtc.isBefore(moment(forecastTime.add(1, "h")))) {
|
if (nowUtc.isSameOrAfter(forecastTime) && nowUtc.isBefore(moment(forecastTime.add(1, "h")))) {
|
||||||
currentWeather.date = forecastTime;
|
currentWeather.date = forecastTime;
|
||||||
currentWeather.windSpeed = this.convertWindSpeed(forecastDataHours[hour].windSpeed10m);
|
currentWeather.windSpeed = forecastDataHours[hour].windSpeed10m;
|
||||||
currentWeather.windDirection = forecastDataHours[hour].windDirectionFrom10m;
|
currentWeather.windDirection = forecastDataHours[hour].windDirectionFrom10m;
|
||||||
currentWeather.temperature = this.convertTemp(forecastDataHours[hour].screenTemperature);
|
currentWeather.temperature = forecastDataHours[hour].screenTemperature;
|
||||||
currentWeather.minTemperature = this.convertTemp(forecastDataHours[hour].minScreenAirTemp);
|
currentWeather.minTemperature = forecastDataHours[hour].minScreenAirTemp;
|
||||||
currentWeather.maxTemperature = this.convertTemp(forecastDataHours[hour].maxScreenAirTemp);
|
currentWeather.maxTemperature = forecastDataHours[hour].maxScreenAirTemp;
|
||||||
currentWeather.weatherType = this.convertWeatherType(forecastDataHours[hour].significantWeatherCode);
|
currentWeather.weatherType = this.convertWeatherType(forecastDataHours[hour].significantWeatherCode);
|
||||||
currentWeather.humidity = forecastDataHours[hour].screenRelativeHumidity;
|
currentWeather.humidity = forecastDataHours[hour].screenRelativeHumidity;
|
||||||
currentWeather.rain = forecastDataHours[hour].totalPrecipAmount;
|
currentWeather.rain = forecastDataHours[hour].totalPrecipAmount;
|
||||||
currentWeather.snow = forecastDataHours[hour].totalSnowAmount;
|
currentWeather.snow = forecastDataHours[hour].totalSnowAmount;
|
||||||
currentWeather.precipitation = forecastDataHours[hour].probOfPrecipitation;
|
currentWeather.precipitation = forecastDataHours[hour].probOfPrecipitation;
|
||||||
currentWeather.feelsLikeTemp = this.convertTemp(forecastDataHours[hour].feelsLikeTemperature);
|
currentWeather.feelsLikeTemp = forecastDataHours[hour].feelsLikeTemperature;
|
||||||
|
|
||||||
// Pass on full details, so they can be used in custom templates
|
// Pass on full details, so they can be used in custom templates
|
||||||
// Note the units of the supplied data when using this (see top of file)
|
// Note the units of the supplied data when using this (see top of file)
|
||||||
@ -194,7 +191,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
|||||||
|
|
||||||
// Go through each day in the forecasts
|
// Go through each day in the forecasts
|
||||||
for (let day in forecastDataDays) {
|
for (let day in forecastDataDays) {
|
||||||
const forecastWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const forecastWeather = new WeatherObject();
|
||||||
|
|
||||||
// Get date of forecast
|
// Get date of forecast
|
||||||
let forecastDate = moment.utc(forecastDataDays[day].time);
|
let forecastDate = moment.utc(forecastDataDays[day].time);
|
||||||
@ -202,11 +199,11 @@ WeatherProvider.register("ukmetofficedatahub", {
|
|||||||
// Check if forecast is for today or in the future (i.e., ignore yesterday's forecast)
|
// Check if forecast is for today or in the future (i.e., ignore yesterday's forecast)
|
||||||
if (forecastDate.isSameOrAfter(today)) {
|
if (forecastDate.isSameOrAfter(today)) {
|
||||||
forecastWeather.date = forecastDate;
|
forecastWeather.date = forecastDate;
|
||||||
forecastWeather.minTemperature = this.convertTemp(forecastDataDays[day].nightMinScreenTemperature);
|
forecastWeather.minTemperature = forecastDataDays[day].nightMinScreenTemperature;
|
||||||
forecastWeather.maxTemperature = this.convertTemp(forecastDataDays[day].dayMaxScreenTemperature);
|
forecastWeather.maxTemperature = forecastDataDays[day].dayMaxScreenTemperature;
|
||||||
|
|
||||||
// Using daytime forecast values
|
// Using daytime forecast values
|
||||||
forecastWeather.windSpeed = this.convertWindSpeed(forecastDataDays[day].midday10MWindSpeed);
|
forecastWeather.windSpeed = forecastDataDays[day].midday10MWindSpeed;
|
||||||
forecastWeather.windDirection = forecastDataDays[day].midday10MWindDirection;
|
forecastWeather.windDirection = forecastDataDays[day].midday10MWindDirection;
|
||||||
forecastWeather.weatherType = this.convertWeatherType(forecastDataDays[day].daySignificantWeatherCode);
|
forecastWeather.weatherType = this.convertWeatherType(forecastDataDays[day].daySignificantWeatherCode);
|
||||||
forecastWeather.precipitation = forecastDataDays[day].dayProbabilityOfPrecipitation;
|
forecastWeather.precipitation = forecastDataDays[day].dayProbabilityOfPrecipitation;
|
||||||
@ -214,7 +211,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
|||||||
forecastWeather.humidity = forecastDataDays[day].middayRelativeHumidity;
|
forecastWeather.humidity = forecastDataDays[day].middayRelativeHumidity;
|
||||||
forecastWeather.rain = forecastDataDays[day].dayProbabilityOfRain;
|
forecastWeather.rain = forecastDataDays[day].dayProbabilityOfRain;
|
||||||
forecastWeather.snow = forecastDataDays[day].dayProbabilityOfSnow;
|
forecastWeather.snow = forecastDataDays[day].dayProbabilityOfSnow;
|
||||||
forecastWeather.feelsLikeTemp = this.convertTemp(forecastDataDays[day].dayMaxFeelsLikeTemp);
|
forecastWeather.feelsLikeTemp = forecastDataDays[day].dayMaxFeelsLikeTemp;
|
||||||
|
|
||||||
// Pass on full details, so they can be used in custom templates
|
// Pass on full details, so they can be used in custom templates
|
||||||
// Note the units of the supplied data when using this (see top of file)
|
// Note the units of the supplied data when using this (see top of file)
|
||||||
@ -232,27 +229,6 @@ WeatherProvider.register("ukmetofficedatahub", {
|
|||||||
this.fetchedLocationName = name;
|
this.fetchedLocationName = name;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Convert temperatures to Fahrenheit (from degrees C), if required
|
|
||||||
convertTemp(tempInC) {
|
|
||||||
return this.config.tempUnits === "imperial" ? (tempInC * 9) / 5 + 32 : tempInC;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Convert wind speed from metres per second
|
|
||||||
// To keep the supplied metres per second units, use "mps"
|
|
||||||
// To use kilometres per hour, use "kph"
|
|
||||||
// Else assumed imperial and the value is returned in miles per hour (a Met Office user is likely to be UK-based)
|
|
||||||
convertWindSpeed(windInMpS) {
|
|
||||||
if (this.config.windUnits === "mps") {
|
|
||||||
return windInMpS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.config.windUnits === "kph" || this.config.windUnits === "metric" || this.config.useKmh) {
|
|
||||||
return windInMpS * 3.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
return windInMpS * 2.23694;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Match the Met Office "significant weather code" to a weathericons.css icon
|
// Match the Met Office "significant weather code" to a weathericons.css icon
|
||||||
// Use: https://metoffice.apiconnect.ibmcloud.com/metoffice/production/node/264
|
// Use: https://metoffice.apiconnect.ibmcloud.com/metoffice/production/node/264
|
||||||
// and: https://erikflowers.github.io/weather-icons/
|
// and: https://erikflowers.github.io/weather-icons/
|
||||||
|
@ -23,11 +23,6 @@ WeatherProvider.register("weatherbit", {
|
|||||||
lon: 0
|
lon: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
units: {
|
|
||||||
imperial: "I",
|
|
||||||
metric: "M"
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchedLocation: function () {
|
fetchedLocation: function () {
|
||||||
return this.fetchedLocationName || "";
|
return this.fetchedLocationName || "";
|
||||||
},
|
},
|
||||||
@ -95,8 +90,7 @@ WeatherProvider.register("weatherbit", {
|
|||||||
|
|
||||||
// Create a URL from the config and base URL.
|
// Create a URL from the config and base URL.
|
||||||
getUrl() {
|
getUrl() {
|
||||||
const units = this.units[this.config.units] || "auto";
|
return `${this.config.apiBase}${this.config.weatherEndpoint}?lat=${this.config.lat}&lon=${this.config.lon}&units=M&key=${this.config.apiKey}`;
|
||||||
return `${this.config.apiBase}${this.config.weatherEndpoint}?lat=${this.config.lat}&lon=${this.config.lon}&units=${units}&key=${this.config.apiKey}`;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Implement WeatherDay generator.
|
// Implement WeatherDay generator.
|
||||||
@ -106,7 +100,7 @@ WeatherProvider.register("weatherbit", {
|
|||||||
let tzOffset = d.getTimezoneOffset();
|
let tzOffset = d.getTimezoneOffset();
|
||||||
tzOffset = tzOffset * -1;
|
tzOffset = tzOffset * -1;
|
||||||
|
|
||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
const currentWeather = new WeatherObject();
|
||||||
|
|
||||||
currentWeather.date = moment.unix(currentWeatherData.data[0].ts);
|
currentWeather.date = moment.unix(currentWeatherData.data[0].ts);
|
||||||
currentWeather.humidity = parseFloat(currentWeatherData.data[0].rh);
|
currentWeather.humidity = parseFloat(currentWeatherData.data[0].rh);
|
||||||
@ -126,7 +120,7 @@ WeatherProvider.register("weatherbit", {
|
|||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
for (const forecast of forecasts) {
|
for (const forecast of forecasts) {
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
const weather = new WeatherObject();
|
||||||
|
|
||||||
weather.date = moment(forecast.datetime, "YYYY-MM-DD");
|
weather.date = moment(forecast.datetime, "YYYY-MM-DD");
|
||||||
weather.minTemperature = forecast.min_temp;
|
weather.minTemperature = forecast.min_temp;
|
||||||
|
@ -23,32 +23,15 @@ WeatherProvider.register("weatherflow", {
|
|||||||
stationid: ""
|
stationid: ""
|
||||||
},
|
},
|
||||||
|
|
||||||
units: {
|
|
||||||
imperial: {
|
|
||||||
temp: "f",
|
|
||||||
wind: "mph",
|
|
||||||
pressure: "hpa",
|
|
||||||
precip: "in",
|
|
||||||
distance: "mi"
|
|
||||||
},
|
|
||||||
metric: {
|
|
||||||
temp: "c",
|
|
||||||
wind: "kph",
|
|
||||||
pressure: "mb",
|
|
||||||
precip: "mm",
|
|
||||||
distance: "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const currentWeather = new WeatherObject();
|
||||||
currentWeather.date = moment();
|
currentWeather.date = moment();
|
||||||
|
|
||||||
currentWeather.humidity = data.current_conditions.relative_humidity;
|
currentWeather.humidity = data.current_conditions.relative_humidity;
|
||||||
currentWeather.temperature = data.current_conditions.air_temperature;
|
currentWeather.temperature = data.current_conditions.air_temperature;
|
||||||
currentWeather.windSpeed = data.current_conditions.wind_avg;
|
currentWeather.windSpeed = currentWeather.convertWindToMs(data.current_conditions.wind_avg);
|
||||||
currentWeather.windDirection = data.current_conditions.wind_direction;
|
currentWeather.windDirection = data.current_conditions.wind_direction;
|
||||||
currentWeather.weatherType = data.forecast.daily[0].icon;
|
currentWeather.weatherType = data.forecast.daily[0].icon;
|
||||||
currentWeather.sunrise = moment.unix(data.forecast.daily[0].sunrise);
|
currentWeather.sunrise = moment.unix(data.forecast.daily[0].sunrise);
|
||||||
@ -67,7 +50,7 @@ WeatherProvider.register("weatherflow", {
|
|||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
for (const forecast of data.forecast.daily) {
|
for (const forecast of data.forecast.daily) {
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
const weather = new WeatherObject();
|
||||||
|
|
||||||
weather.date = moment.unix(forecast.day_start_local);
|
weather.date = moment.unix(forecast.day_start_local);
|
||||||
weather.minTemperature = forecast.air_temp_low;
|
weather.minTemperature = forecast.air_temp_low;
|
||||||
@ -88,22 +71,6 @@ WeatherProvider.register("weatherflow", {
|
|||||||
|
|
||||||
// Create a URL from the config and base URL.
|
// Create a URL from the config and base URL.
|
||||||
getUrl() {
|
getUrl() {
|
||||||
return (
|
return `${this.config.apiBase}better_forecast?station_id=${this.config.stationid}&units_temp=c&units_wind=kph&units_pressure=mb&units_precip=mm&units_distance=km&token=${this.config.token}`;
|
||||||
this.config.apiBase +
|
|
||||||
"better_forecast?station_id=" +
|
|
||||||
this.config.stationid +
|
|
||||||
"&units_temp=" +
|
|
||||||
this.units[this.config.units].temp +
|
|
||||||
"&units_wind=" +
|
|
||||||
this.units[this.config.units].wind +
|
|
||||||
"&units_pressure=" +
|
|
||||||
this.units[this.config.units].pressure +
|
|
||||||
"&units_precip=" +
|
|
||||||
this.units[this.config.units].precip +
|
|
||||||
"&units_distance=" +
|
|
||||||
this.units[this.config.units].distance +
|
|
||||||
"&token=" +
|
|
||||||
this.config.token
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -131,8 +131,8 @@ WeatherProvider.register("weathergov", {
|
|||||||
}
|
}
|
||||||
this.fetchedLocationName = data.properties.relativeLocation.properties.city + ", " + data.properties.relativeLocation.properties.state;
|
this.fetchedLocationName = data.properties.relativeLocation.properties.city + ", " + data.properties.relativeLocation.properties.state;
|
||||||
Log.log("Forecast location is " + this.fetchedLocationName);
|
Log.log("Forecast location is " + this.fetchedLocationName);
|
||||||
this.forecastURL = data.properties.forecast;
|
this.forecastURL = data.properties.forecast + "?units=si";
|
||||||
this.forecastHourlyURL = data.properties.forecastHourly;
|
this.forecastHourlyURL = data.properties.forecastHourly + "?units=si";
|
||||||
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
|
||||||
@ -171,7 +171,7 @@ WeatherProvider.register("weathergov", {
|
|||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
// variable for date
|
// variable for date
|
||||||
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
let weather = new WeatherObject();
|
||||||
for (const forecast of forecasts) {
|
for (const forecast of forecasts) {
|
||||||
weather.date = moment(forecast.startTime.slice(0, 19));
|
weather.date = moment(forecast.startTime.slice(0, 19));
|
||||||
if (forecast.windSpeed.search(" ") < 0) {
|
if (forecast.windSpeed.search(" ") < 0) {
|
||||||
@ -187,7 +187,7 @@ WeatherProvider.register("weathergov", {
|
|||||||
|
|
||||||
days.push(weather);
|
days.push(weather);
|
||||||
|
|
||||||
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
weather = new WeatherObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
// push weather information to days array
|
// push weather information to days array
|
||||||
@ -201,24 +201,24 @@ WeatherProvider.register("weathergov", {
|
|||||||
* ... object needs data in units based on config!
|
* ... 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, this.config.useKmh);
|
const currentWeather = new WeatherObject();
|
||||||
|
|
||||||
currentWeather.date = moment(currentWeatherData.timestamp);
|
currentWeather.date = moment(currentWeatherData.timestamp);
|
||||||
currentWeather.temperature = this.convertTemp(currentWeatherData.temperature.value);
|
currentWeather.temperature = currentWeatherData.temperature.value;
|
||||||
currentWeather.windSpeed = this.convertSpeed(currentWeatherData.windSpeed.value);
|
currentWeather.windSpeed = currentWeather.convertWindToMs(currentWeatherData.windSpeed.value);
|
||||||
currentWeather.windDirection = currentWeatherData.windDirection.value;
|
currentWeather.windDirection = currentWeatherData.windDirection.value;
|
||||||
currentWeather.minTemperature = this.convertTemp(currentWeatherData.minTemperatureLast24Hours.value);
|
currentWeather.minTemperature = currentWeatherData.minTemperatureLast24Hours.value;
|
||||||
currentWeather.maxTemperature = this.convertTemp(currentWeatherData.maxTemperatureLast24Hours.value);
|
currentWeather.maxTemperature = currentWeatherData.maxTemperatureLast24Hours.value;
|
||||||
currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value);
|
currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value);
|
||||||
currentWeather.rain = null;
|
currentWeather.rain = null;
|
||||||
currentWeather.snow = null;
|
currentWeather.snow = null;
|
||||||
currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value);
|
currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value);
|
||||||
if (currentWeatherData.heatIndex.value !== null) {
|
if (currentWeatherData.heatIndex.value !== null) {
|
||||||
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value);
|
currentWeather.feelsLikeTemp = currentWeatherData.heatIndex.value;
|
||||||
} else if (currentWeatherData.windChill.value !== null) {
|
} else if (currentWeatherData.windChill.value !== null) {
|
||||||
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.windChill.value);
|
currentWeather.feelsLikeTemp = currentWeatherData.windChill.value;
|
||||||
} else {
|
} else {
|
||||||
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.temperature.value);
|
currentWeather.feelsLikeTemp = currentWeatherData.temperature.value;
|
||||||
}
|
}
|
||||||
// determine the sunrise/sunset times - not supplied in weather.gov data
|
// determine the sunrise/sunset times - not supplied in weather.gov data
|
||||||
currentWeather.updateSunTime(this.config.lat, this.config.lon);
|
currentWeather.updateSunTime(this.config.lat, this.config.lon);
|
||||||
@ -247,7 +247,7 @@ WeatherProvider.register("weathergov", {
|
|||||||
let maxTemp = [];
|
let maxTemp = [];
|
||||||
// variable for date
|
// variable for date
|
||||||
let date = "";
|
let date = "";
|
||||||
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
let weather = new WeatherObject();
|
||||||
weather.precipitation = 0;
|
weather.precipitation = 0;
|
||||||
|
|
||||||
for (const forecast of forecasts) {
|
for (const forecast of forecasts) {
|
||||||
@ -259,7 +259,7 @@ WeatherProvider.register("weathergov", {
|
|||||||
// push weather information to days array
|
// push weather information to days array
|
||||||
days.push(weather);
|
days.push(weather);
|
||||||
// create new weather-object
|
// create new weather-object
|
||||||
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
|
weather = new WeatherObject();
|
||||||
|
|
||||||
minTemp = [];
|
minTemp = [];
|
||||||
maxTemp = [];
|
maxTemp = [];
|
||||||
@ -298,26 +298,6 @@ WeatherProvider.register("weathergov", {
|
|||||||
/*
|
/*
|
||||||
* Unit conversions
|
* Unit conversions
|
||||||
*/
|
*/
|
||||||
// conversion to fahrenheit
|
|
||||||
convertTemp(temp) {
|
|
||||||
if (this.config.tempUnits === "imperial") {
|
|
||||||
return (9 / 5) * temp + 32;
|
|
||||||
} else {
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// conversion to mph or kmh
|
|
||||||
convertSpeed(metSec) {
|
|
||||||
if (this.config.windUnits === "imperial") {
|
|
||||||
return metSec * 2.23694;
|
|
||||||
} else {
|
|
||||||
if (this.config.useKmh) {
|
|
||||||
return metSec * 3.6;
|
|
||||||
} else {
|
|
||||||
return metSec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// conversion to inches
|
// conversion to inches
|
||||||
convertLength(meters) {
|
convertLength(meters) {
|
||||||
if (this.config.units === "imperial") {
|
if (this.config.units === "imperial") {
|
||||||
@ -395,31 +375,5 @@ WeatherProvider.register("weathergov", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Convert the direction into Degrees
|
|
||||||
*/
|
|
||||||
convertWindDirection(windDirection) {
|
|
||||||
const windCardinals = {
|
|
||||||
N: 0,
|
|
||||||
NNE: 22,
|
|
||||||
NE: 45,
|
|
||||||
ENE: 67,
|
|
||||||
E: 90,
|
|
||||||
ESE: 112,
|
|
||||||
SE: 135,
|
|
||||||
SSE: 157,
|
|
||||||
S: 180,
|
|
||||||
SSW: 202,
|
|
||||||
SW: 225,
|
|
||||||
WSW: 247,
|
|
||||||
W: 270,
|
|
||||||
WNW: 292,
|
|
||||||
NW: 315,
|
|
||||||
NNW: 337
|
|
||||||
};
|
|
||||||
|
|
||||||
return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -13,7 +13,6 @@ Module.register("weather", {
|
|||||||
roundTemp: false,
|
roundTemp: false,
|
||||||
type: "current", // current, forecast, daily (equivalent to forecast), hourly (only with OpenWeatherMap /onecall endpoint)
|
type: "current", // current, forecast, daily (equivalent to forecast), hourly (only with OpenWeatherMap /onecall endpoint)
|
||||||
units: config.units,
|
units: config.units,
|
||||||
useKmh: false,
|
|
||||||
tempUnits: config.units,
|
tempUnits: config.units,
|
||||||
windUnits: config.units,
|
windUnits: config.units,
|
||||||
updateInterval: 10 * 60 * 1000, // every 10 minutes
|
updateInterval: 10 * 60 * 1000, // every 10 minutes
|
||||||
@ -23,7 +22,6 @@ Module.register("weather", {
|
|||||||
showPeriodUpper: false,
|
showPeriodUpper: false,
|
||||||
showWindDirection: true,
|
showWindDirection: true,
|
||||||
showWindDirectionAsArrow: false,
|
showWindDirectionAsArrow: false,
|
||||||
useBeaufort: true,
|
|
||||||
lang: config.language,
|
lang: config.language,
|
||||||
showHumidity: false,
|
showHumidity: false,
|
||||||
showSun: true,
|
showSun: true,
|
||||||
@ -77,6 +75,14 @@ Module.register("weather", {
|
|||||||
start: function () {
|
start: function () {
|
||||||
moment.locale(this.config.lang);
|
moment.locale(this.config.lang);
|
||||||
|
|
||||||
|
if (this.config.useKmh) {
|
||||||
|
Log.warn("Your are using the deprecated config values 'useKmh'. Please switch to windUnits!");
|
||||||
|
this.windUnits = "kmh";
|
||||||
|
} else if (this.config.useBeaufort) {
|
||||||
|
Log.warn("Your are using the deprecated config values 'useBeaufort'. Please switch to windUnits!");
|
||||||
|
this.windUnits = "beaufort";
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the weather provider.
|
// Initialize the weather provider.
|
||||||
this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this);
|
this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this);
|
||||||
|
|
||||||
@ -195,6 +201,59 @@ Module.register("weather", {
|
|||||||
return roundValue === "-0" ? 0 : roundValue;
|
return roundValue === "-0" ? 0 : roundValue;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert temp (from degrees C) into imperial or metric unit depending on
|
||||||
|
* your config
|
||||||
|
*
|
||||||
|
* @param {number} tempInC the temperature you want to convert in celsius
|
||||||
|
* @returns {number} the temperature converted to what is defined in the config
|
||||||
|
*/
|
||||||
|
convertTemp(tempInC) {
|
||||||
|
return this.config.tempUnits === "imperial" ? this.roundValue(tempInC * 1.8 + 32) : tempInC;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Convert wind speed (from meters per second) into whatever is defined in
|
||||||
|
* your config. Can be 'beaufort', 'kmh', 'knots, 'imperial' (mph) or
|
||||||
|
* 'metric' (mps)
|
||||||
|
*
|
||||||
|
* @param {number} windInMS the windspeed you want to convert
|
||||||
|
* @returns {number} the windspeed converted to what is defined in the config
|
||||||
|
*/
|
||||||
|
convertWind(windInMS) {
|
||||||
|
switch (this.config.windUnits) {
|
||||||
|
case "beaufort":
|
||||||
|
return this.beaufortWindSpeed(windInMS);
|
||||||
|
case "kmh":
|
||||||
|
return (windInMS * 3600) / 1000;
|
||||||
|
case "knots":
|
||||||
|
return windInMS * 1.943844;
|
||||||
|
case "imperial":
|
||||||
|
return windInMS * 2.2369362920544;
|
||||||
|
case "metric":
|
||||||
|
default:
|
||||||
|
return windInMS;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert wind (from m/s) to beaufort scale
|
||||||
|
*
|
||||||
|
* @param {number} speedInMS the windspeed you want to convert
|
||||||
|
* @returns {number} the speed in beaufort
|
||||||
|
*/
|
||||||
|
beaufortWindSpeed(speedInMS) {
|
||||||
|
const windInKmh = (speedInMS * 3600) / 1000;
|
||||||
|
const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
|
||||||
|
for (const [index, speed] of speeds.entries()) {
|
||||||
|
if (speed > windInKmh) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 12;
|
||||||
|
},
|
||||||
|
|
||||||
addFilters() {
|
addFilters() {
|
||||||
this.nunjucksEnvironment().addFilter(
|
this.nunjucksEnvironment().addFilter(
|
||||||
"formatTime",
|
"formatTime",
|
||||||
@ -221,9 +280,7 @@ Module.register("weather", {
|
|||||||
"unit",
|
"unit",
|
||||||
function (value, type) {
|
function (value, type) {
|
||||||
if (type === "temperature") {
|
if (type === "temperature") {
|
||||||
if (this.config.tempUnits === "metric" || this.config.tempUnits === "imperial") {
|
value = this.convertTemp(value) + "°";
|
||||||
value += "°";
|
|
||||||
}
|
|
||||||
if (this.config.degreeLabel) {
|
if (this.config.degreeLabel) {
|
||||||
if (this.config.tempUnits === "metric") {
|
if (this.config.tempUnits === "metric") {
|
||||||
value += "C";
|
value += "C";
|
||||||
@ -245,8 +302,9 @@ Module.register("weather", {
|
|||||||
}
|
}
|
||||||
} else if (type === "humidity") {
|
} else if (type === "humidity") {
|
||||||
value += "%";
|
value += "%";
|
||||||
|
} else if (type === "wind") {
|
||||||
|
value = this.convertWind(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
|
@ -14,17 +14,8 @@
|
|||||||
class WeatherObject {
|
class WeatherObject {
|
||||||
/**
|
/**
|
||||||
* Constructor for a WeatherObject
|
* Constructor for a WeatherObject
|
||||||
*
|
|
||||||
* @param {string} units what units to use, "imperial" or "metric"
|
|
||||||
* @param {string} tempUnits what tempunits to use
|
|
||||||
* @param {string} windUnits what windunits to use
|
|
||||||
* @param {boolean} useKmh use kmh if true, mps if false
|
|
||||||
*/
|
*/
|
||||||
constructor(units, tempUnits, windUnits, useKmh) {
|
constructor() {
|
||||||
this.units = units;
|
|
||||||
this.tempUnits = tempUnits;
|
|
||||||
this.windUnits = windUnits;
|
|
||||||
this.useKmh = useKmh;
|
|
||||||
this.date = null;
|
this.date = null;
|
||||||
this.windSpeed = null;
|
this.windSpeed = null;
|
||||||
this.windDirection = null;
|
this.windDirection = null;
|
||||||
@ -78,19 +69,38 @@ class WeatherObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
beaufortWindSpeed() {
|
/*
|
||||||
const windInKmh = this.windUnits === "imperial" ? this.windSpeed * 1.609344 : this.useKmh ? this.windSpeed : (this.windSpeed * 60 * 60) / 1000;
|
* Convert the wind direction cardinal to value
|
||||||
const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
|
*/
|
||||||
for (const [index, speed] of speeds.entries()) {
|
valueWindDirection(windDirection) {
|
||||||
if (speed > windInKmh) {
|
const windCardinals = {
|
||||||
return index;
|
N: 0,
|
||||||
}
|
NNE: 22,
|
||||||
}
|
NE: 45,
|
||||||
return 12;
|
ENE: 67,
|
||||||
|
E: 90,
|
||||||
|
ESE: 112,
|
||||||
|
SE: 135,
|
||||||
|
SSE: 157,
|
||||||
|
S: 180,
|
||||||
|
SSW: 202,
|
||||||
|
SW: 225,
|
||||||
|
WSW: 247,
|
||||||
|
W: 270,
|
||||||
|
WNW: 292,
|
||||||
|
NW: 315,
|
||||||
|
NNW: 337
|
||||||
|
};
|
||||||
|
|
||||||
|
return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
kmhWindSpeed() {
|
convertWindToMetric(mph) {
|
||||||
return this.windUnits === "imperial" ? this.windSpeed * 1.609344 : (this.windSpeed * 60 * 60) / 1000;
|
return mph / 2.2369362920544;
|
||||||
|
}
|
||||||
|
|
||||||
|
convertWindToMs(kmh) {
|
||||||
|
return kmh * 0.27777777777778;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextSunAction() {
|
nextSunAction() {
|
||||||
@ -101,8 +111,8 @@ class WeatherObject {
|
|||||||
if (this.feelsLikeTemp) {
|
if (this.feelsLikeTemp) {
|
||||||
return this.feelsLikeTemp;
|
return this.feelsLikeTemp;
|
||||||
}
|
}
|
||||||
const windInMph = this.windUnits === "imperial" ? this.windSpeed : this.windSpeed * 2.23694;
|
const windInMph = this.windSpeed * 2.2369362920544;
|
||||||
const tempInF = this.tempUnits === "imperial" ? this.temperature : (this.temperature * 9) / 5 + 32;
|
const tempInF = (this.temperature * 9) / 5 + 32;
|
||||||
let feelsLike = tempInF;
|
let feelsLike = tempInF;
|
||||||
|
|
||||||
if (windInMph > 3 && tempInF < 50) {
|
if (windInMph > 3 && tempInF < 50) {
|
||||||
@ -120,7 +130,7 @@ class WeatherObject {
|
|||||||
1.99 * Math.pow(10, -6) * tempInF * tempInF * this.humidity * this.humidity;
|
1.99 * Math.pow(10, -6) * tempInF * tempInF * this.humidity * this.humidity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.tempUnits === "imperial" ? feelsLike : ((feelsLike - 32) * 5) / 9;
|
return ((feelsLike - 32) * 5) / 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +11,7 @@ let config = {
|
|||||||
config: {
|
config: {
|
||||||
location: "Munich",
|
location: "Munich",
|
||||||
mockData: '"#####WEATHERDATA#####"',
|
mockData: '"#####WEATHERDATA#####"',
|
||||||
useBeaufort: false,
|
windUnits: "beaufort",
|
||||||
showWindDirectionAsArrow: true,
|
showWindDirectionAsArrow: true,
|
||||||
showSun: false,
|
showSun: false,
|
||||||
showHumidity: true,
|
showHumidity: true,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
const moment = require("moment");
|
|
||||||
const helpers = require("../helpers/global-setup");
|
const helpers = require("../helpers/global-setup");
|
||||||
const weatherFunc = require("../helpers/weather-functions");
|
const weatherFunc = require("../helpers/weather-functions");
|
||||||
|
|
||||||
@ -14,39 +13,15 @@ describe("Weather module", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should render wind speed and wind direction", async () => {
|
it("should render wind speed and wind direction", async () => {
|
||||||
await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6 WSW"); // now "12"
|
await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "12 WSW");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render temperature with icon", async () => {
|
it("should render temperature with icon", async () => {
|
||||||
await weatherFunc.getText(".weather .large.light span.bright", "1.5°"); // now "1°C"
|
await weatherFunc.getText(".weather .large.light span.bright", "1.5°");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render feels like temperature", async () => {
|
it("should render feels like temperature", async () => {
|
||||||
await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°"); // now "Feels like -6°C"
|
await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°");
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Default configuration with sunrise", () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
const sunrise = moment().startOf("day").unix();
|
|
||||||
const sunset = moment().startOf("day").unix();
|
|
||||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render sunrise", async () => {
|
|
||||||
await weatherFunc.getText(".weather .normal.medium span:nth-child(4)", "12:00 am");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Default configuration with sunset", () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
const sunrise = moment().startOf("day").unix();
|
|
||||||
const sunset = moment().endOf("day").unix();
|
|
||||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render sunset", async () => {
|
|
||||||
await weatherFunc.getText(".weather .normal.medium span:nth-child(4)", "11:59 pm");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -66,65 +41,44 @@ describe("Weather module", () => {
|
|||||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_options.js", {});
|
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_options.js", {});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render useBeaufort = false", async () => {
|
it("should render windUnits in beaufort", async () => {
|
||||||
await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "12");
|
await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render showWindDirectionAsArrow = true", async () => {
|
it("should render windDirection with an arrow", async () => {
|
||||||
const elem = await helpers.waitForElement(".weather .normal.medium sup i.fa-long-arrow-alt-up");
|
const elem = await helpers.waitForElement(".weather .normal.medium sup i.fa-long-arrow-alt-up");
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.outerHTML).toContain("transform:rotate(250deg);");
|
expect(elem.outerHTML).toContain("transform:rotate(250deg);");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render showHumidity = true", async () => {
|
it("should render humidity", async () => {
|
||||||
await weatherFunc.getText(".weather .normal.medium span:nth-child(3)", "93.7");
|
await weatherFunc.getText(".weather .normal.medium span:nth-child(3)", "93.7");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render degreeLabel = true for temp", async () => {
|
it("should render degreeLabel for temp", async () => {
|
||||||
await weatherFunc.getText(".weather .large.light span.bright", "1°C");
|
await weatherFunc.getText(".weather .large.light span.bright", "1°C");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render degreeLabel = true for feels like", async () => {
|
it("should render degreeLabel for feels like", async () => {
|
||||||
await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C");
|
await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Current weather units", () => {
|
describe("Current weather with imperial units", () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_units.js", {
|
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_units.js", {});
|
||||||
main: {
|
|
||||||
temp: (1.49 * 9) / 5 + 32,
|
|
||||||
temp_min: (1 * 9) / 5 + 32,
|
|
||||||
temp_max: (2 * 9) / 5 + 32
|
|
||||||
},
|
|
||||||
wind: {
|
|
||||||
speed: 11.8 * 2.23694
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render imperial units for wind", async () => {
|
it("should render wind in imperial units", async () => {
|
||||||
await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6 WSW");
|
await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "26 WSW");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render imperial units for temp", async () => {
|
it("should render temperatures in fahrenheit", async () => {
|
||||||
await weatherFunc.getText(".weather .large.light span.bright", "34,7°");
|
await weatherFunc.getText(".weather .large.light span.bright", "34,7°");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render imperial units for feels like", async () => {
|
it("should render 'feels like' in fahrenheit", async () => {
|
||||||
await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°");
|
await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 21,9°");
|
||||||
});
|
|
||||||
|
|
||||||
it("should render custom decimalSymbol = ',' for humidity", async () => {
|
|
||||||
await weatherFunc.getText(".weather .normal.medium span:nth-child(3)", "93,7");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render custom decimalSymbol = ',' for temp", async () => {
|
|
||||||
await weatherFunc.getText(".weather .large.light span.bright", "34,7°");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render custom decimalSymbol = ',' for feels like", async () => {
|
|
||||||
await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -86,7 +86,7 @@ describe("Weather module: Weather Forecast", () => {
|
|||||||
await weatherFunc.startApp("tests/configs/modules/weather/forecastweather_units.js", {});
|
await weatherFunc.startApp("tests/configs/modules/weather/forecastweather_units.js", {});
|
||||||
});
|
});
|
||||||
|
|
||||||
const temperatures = ["24_4°", "21_0°", "22_9°", "23_4°", "20_6°"];
|
const temperatures = ["75_9°", "69_8°", "73_2°", "74_1°", "69_1°"];
|
||||||
for (const [index, temp] of temperatures.entries()) {
|
for (const [index, temp] of temperatures.entries()) {
|
||||||
it("should render custom decimalSymbol = '_' for temp " + temp, async () => {
|
it("should render custom decimalSymbol = '_' for temp " + temp, async () => {
|
||||||
await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp);
|
await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp);
|
||||||
|
29
tests/electron/helpers/weather-setup.js
Normal file
29
tests/electron/helpers/weather-setup.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const helpers = require("./global-setup");
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
const { generateWeather, generateWeatherForecast } = require("../../mocks/weather_test");
|
||||||
|
|
||||||
|
exports.getText = async (element, result) => {
|
||||||
|
const elem = await helpers.getElement(element);
|
||||||
|
await expect(elem).not.toBe(null);
|
||||||
|
const text = await elem.textContent();
|
||||||
|
await expect(
|
||||||
|
text
|
||||||
|
.trim()
|
||||||
|
.replace(/(\r\n|\n|\r)/gm, "")
|
||||||
|
.replace(/[ ]+/g, " ")
|
||||||
|
).toBe(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.startApp = async (configFile, systemDate) => {
|
||||||
|
let mockWeather;
|
||||||
|
if (configFile.includes("forecast")) {
|
||||||
|
mockWeather = generateWeatherForecast();
|
||||||
|
} else {
|
||||||
|
mockWeather = generateWeather();
|
||||||
|
}
|
||||||
|
let content = fs.readFileSync(path.resolve(__dirname + "../../../../" + configFile)).toString();
|
||||||
|
content = content.replace("#####WEATHERDATA#####", mockWeather);
|
||||||
|
fs.writeFileSync(path.resolve(__dirname + "../../../../config/config.js"), content);
|
||||||
|
await helpers.startApplication("", systemDate);
|
||||||
|
};
|
28
tests/electron/modules/weather_spec.js
Normal file
28
tests/electron/modules/weather_spec.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const helpers = require("../helpers/global-setup");
|
||||||
|
const weatherHelper = require("../helpers/weather-setup");
|
||||||
|
|
||||||
|
describe("Weather module", () => {
|
||||||
|
afterEach(async () => {
|
||||||
|
await helpers.stopApplication();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Current weather with sunrise", () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await weatherHelper.startApp("tests/configs/modules/weather/currentweather_default.js", "13 Jan 2019 00:30:00 GMT");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render sunrise", async () => {
|
||||||
|
await weatherHelper.getText(".weather .normal.medium span:nth-child(4)", "7:00 am");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Current weather with sunset", () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await weatherHelper.startApp("tests/configs/modules/weather/currentweather_default.js", "13 Jan 2019 12:30:00 GMT");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render sunset", async () => {
|
||||||
|
await weatherHelper.getText(".weather .normal.medium span:nth-child(4)", "3:45 pm");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -10,7 +10,7 @@ describe("WeatherObject", () => {
|
|||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
originalTimeZone = moment.tz.guess();
|
originalTimeZone = moment.tz.guess();
|
||||||
moment.tz.setDefault("Africa/Dar_es_Salaam");
|
moment.tz.setDefault("Africa/Dar_es_Salaam");
|
||||||
weatherobject = new WeatherObject("metric", "metric", "metric", true);
|
weatherobject = new WeatherObject();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return true for daytime at noon", () => {
|
it("should return true for daytime at noon", () => {
|
||||||
@ -25,6 +25,14 @@ describe("WeatherObject", () => {
|
|||||||
expect(weatherobject.isDayTime()).toBe(false);
|
expect(weatherobject.isDayTime()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should convert windspeed correctly from mph to mps", () => {
|
||||||
|
expect(Math.round(weatherobject.convertWindToMetric(93.951324266285))).toBe(42);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should convert wind direction correctly from cardinal to value", () => {
|
||||||
|
expect(weatherobject.valueWindDirection("SSE")).toBe(157);
|
||||||
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
moment.tz.setDefault(originalTimeZone);
|
moment.tz.setDefault(originalTimeZone);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user