Merge pull request #1495 from fewieden/feature/weather-module-improvements

weather module feels like temperature
This commit is contained in:
Michael Teeuw 2018-12-30 15:40:22 +01:00 committed by GitHub
commit 986337da0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 46 deletions

View File

@ -48,7 +48,6 @@ The following properties can be configured:
| `lang` | The language of the days. <br><br> **Possible values:** `en`, `nl`, `ru`, etc ... <br> **Default value:** uses value of _config.language_ | `lang` | The language of the days. <br><br> **Possible values:** `en`, `nl`, `ru`, etc ... <br> **Default value:** uses value of _config.language_
| `decimalSymbol` | The decimal symbol to use.<br><br> **Possible values:** `.`, `,` or any other symbol.<br> **Default value:** `.` | `decimalSymbol` | The decimal symbol to use.<br><br> **Possible values:** `.`, `,` or any other symbol.<br> **Default value:** `.`
| `initialLoadDelay` | The initial delay before loading. If you have multiple modules that use the same API key, you might want to delay one of the requests. (Milliseconds) <br><br> **Possible values:** `1000` - `5000` <br> **Default value:** `0` | `initialLoadDelay` | The initial delay before loading. If you have multiple modules that use the same API key, you might want to delay one of the requests. (Milliseconds) <br><br> **Possible values:** `1000` - `5000` <br> **Default value:** `0`
| `retryDelay` | The delay before retrying after a request failure. (Milliseconds) <br><br> **Possible values:** `1000` - `60000` <br> **Default value:** `2500`
| `appendLocationNameToHeader` | If set to `true`, the returned location name will be appended to the header of the module, if the header is enabled. This is mainly intresting when using calender based weather. <br><br> **Default value:** `true` | `appendLocationNameToHeader` | If set to `true`, the returned location name will be appended to the header of the module, if the header is enabled. This is mainly intresting when using calender based weather. <br><br> **Default value:** `true`
| `calendarClass` | The class for the calender module to base the event based weather information on. <br><br> **Default value:** `'calendar'` | `calendarClass` | The class for the calender module to base the event based weather information on. <br><br> **Default value:** `'calendar'`
@ -63,6 +62,7 @@ The following properties can be configured:
| `showHumidity` | Show the current humidity <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false` | `showHumidity` | Show the current humidity <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
| `showIndoorTemperature` | If you have another module that emits the `INDOOR_TEMPERATURE` notification, the indoor temperature will be displayed <br> **Default value:** `false` | `showIndoorTemperature` | If you have another module that emits the `INDOOR_TEMPERATURE` notification, the indoor temperature will be displayed <br> **Default value:** `false`
| `showIndoorHumidity` | If you have another module that emits the `INDOOR_HUMIDITY` notification, the indoor humidity will be displayed <br> **Default value:** `false` | `showIndoorHumidity` | If you have another module that emits the `INDOOR_HUMIDITY` notification, the indoor humidity will be displayed <br> **Default value:** `false`
| `showFeelsLike` | Shows the Feels like temperature weather. <br><br> **Possible values:**`true` or `false`<br>**Default value:** `true`
#### Weather forecast options #### Weather forecast options

View File

@ -51,6 +51,13 @@
</span> </span>
{% endif %} {% endif %}
</div> </div>
{% if config.showFeelsLike and not config.onlyTemp %}
<div class="normal medium">
<span class="dimmed">
{{ "FEELS" | translate }} {{ current.feelsLike() | roundValue | unit("temperature") }}
</span>
</div>
{% endif %}
{% else %} {% else %}
<div class="dimmed light small"> <div class="dimmed light small">
{{"LOADING" | translate}} {{"LOADING" | translate}}

View File

@ -16,10 +16,10 @@ WeatherProvider.register("darksky", {
units: { units: {
imperial: 'us', imperial: 'us',
metric: 'ca' metric: 'si'
}, },
fetchCurrentWeather: function() { fetchCurrentWeather() {
this.fetchData(this.getUrl()) this.fetchData(this.getUrl())
.then(data => { .then(data => {
if(!data || !data.currently || typeof data.currently.temperature === "undefined") { if(!data || !data.currently || typeof data.currently.temperature === "undefined") {
@ -27,14 +27,14 @@ WeatherProvider.register("darksky", {
return; return;
} }
var currentWeather = this.generateWeatherDayFromCurrentWeather(data); const currentWeather = this.generateWeatherDayFromCurrentWeather(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);
}); });
}, },
fetchWeatherForecast: function() { fetchWeatherForecast() {
this.fetchData(this.getUrl()) this.fetchData(this.getUrl())
.then(data => { .then(data => {
if(!data || !data.daily || !data.daily.data.length) { if(!data || !data.daily || !data.daily.data.length) {
@ -42,7 +42,7 @@ WeatherProvider.register("darksky", {
return; return;
} }
var forecast = this.generateWeatherObjectsFromForecast(data.daily.data); const forecast = this.generateWeatherObjectsFromForecast(data.daily.data);
this.setWeatherForecast(forecast); this.setWeatherForecast(forecast);
}).catch(function(request) { }).catch(function(request) {
Log.error("Could not load data ... ", request); Log.error("Could not load data ... ", request);
@ -50,14 +50,14 @@ WeatherProvider.register("darksky", {
}, },
// Create a URL from the config and base URL. // Create a URL from the config and base URL.
getUrl: function() { getUrl() {
var units = this.units[this.config.units] || 'auto'; 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=${units}&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: function(currentWeatherData) { generateWeatherDayFromCurrentWeather(currentWeatherData) {
var currentWeather = new WeatherObject(); const currentWeather = new WeatherObject(this.config.units);
currentWeather.date = moment(); currentWeather.date = moment();
currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity); currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity);
@ -71,11 +71,11 @@ WeatherProvider.register("darksky", {
return currentWeather; return currentWeather;
}, },
generateWeatherObjectsFromForecast: function(forecasts) { generateWeatherObjectsFromForecast(forecasts) {
var days = []; const days = [];
for (var forecast of forecasts) { for (const forecast of forecasts) {
var weather = new WeatherObject(); const weather = new WeatherObject(this.config.units);
weather.date = moment(forecast.time, "X"); weather.date = moment(forecast.time, "X");
weather.minTemperature = forecast.temperatureMin; weather.minTemperature = forecast.temperatureMin;
@ -83,15 +83,15 @@ WeatherProvider.register("darksky", {
weather.weatherType = this.convertWeatherType(forecast.icon); weather.weatherType = this.convertWeatherType(forecast.icon);
weather.rain = forecast.precipAccumulation; weather.rain = forecast.precipAccumulation;
days.push(weather) days.push(weather);
} }
return days return days;
}, },
// Map icons from Dark Sky to our icons. // Map icons from Dark Sky to our icons.
convertWeatherType: function(weatherType) { convertWeatherType(weatherType) {
var weatherTypes = { const weatherTypes = {
"clear-day": "day-sunny", "clear-day": "day-sunny",
"clear-night": "night-clear", "clear-night": "night-clear",
"rain": "rain", "rain": "rain",
@ -103,6 +103,7 @@ WeatherProvider.register("darksky", {
"partly-cloudy-day": "day-cloudy", "partly-cloudy-day": "day-cloudy",
"partly-cloudy-night": "night-cloudy" "partly-cloudy-night": "night-cloudy"
}; };
return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null; return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
} }
}); });

View File

@ -17,7 +17,7 @@ WeatherProvider.register("openweathermap", {
providerName: "OpenWeatherMap", providerName: "OpenWeatherMap",
// Overwrite the fetchCurrentWeather method. // Overwrite the fetchCurrentWeather method.
fetchCurrentWeather: function() { fetchCurrentWeather() {
this.fetchData(this.getUrl()) this.fetchData(this.getUrl())
.then(data => { .then(data => {
if (!data || !data.main || typeof data.main.temp === "undefined") { if (!data || !data.main || typeof data.main.temp === "undefined") {
@ -28,7 +28,7 @@ WeatherProvider.register("openweathermap", {
this.setFetchedLocation(`${data.name}, ${data.sys.country}`); this.setFetchedLocation(`${data.name}, ${data.sys.country}`);
var currentWeather = this.generateWeatherObjectFromCurrentWeather(data); const currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
this.setCurrentWeather(currentWeather); this.setCurrentWeather(currentWeather);
}) })
.catch(function(request) { .catch(function(request) {
@ -37,7 +37,7 @@ WeatherProvider.register("openweathermap", {
}, },
// Overwrite the fetchCurrentWeather method. // Overwrite the fetchCurrentWeather method.
fetchWeatherForecast: function() { fetchWeatherForecast() {
this.fetchData(this.getUrl()) this.fetchData(this.getUrl())
.then(data => { .then(data => {
if (!data || !data.list || !data.list.length) { if (!data || !data.list || !data.list.length) {
@ -48,7 +48,7 @@ WeatherProvider.register("openweathermap", {
this.setFetchedLocation(`${data.city.name}, ${data.city.country}`); this.setFetchedLocation(`${data.city.name}, ${data.city.country}`);
var forecast = this.generateWeatherObjectsFromForecast(data.list); const forecast = this.generateWeatherObjectsFromForecast(data.list);
this.setWeatherForecast(forecast); this.setWeatherForecast(forecast);
}) })
.catch(function(request) { .catch(function(request) {
@ -62,15 +62,15 @@ WeatherProvider.register("openweathermap", {
/* /*
* Gets the complete url for the request * Gets the complete url for the request
*/ */
getUrl: function() { getUrl() {
return this.config.apiBase + this.config.apiVersion + this.config.weatherEndpoint + this.getParams(); return this.config.apiBase + this.config.apiVersion + this.config.weatherEndpoint + this.getParams();
}, },
/* /*
* Generate a WeatherObject based on currentWeatherInformation * Generate a WeatherObject based on currentWeatherInformation
*/ */
generateWeatherObjectFromCurrentWeather: function(currentWeatherData) { generateWeatherObjectFromCurrentWeather(currentWeatherData) {
var currentWeather = new WeatherObject(); const currentWeather = new WeatherObject(this.config.units);
currentWeather.humidity = currentWeatherData.main.humidity; currentWeather.humidity = currentWeatherData.main.humidity;
currentWeather.temperature = currentWeatherData.main.temp; currentWeather.temperature = currentWeatherData.main.temp;
@ -86,11 +86,11 @@ WeatherProvider.register("openweathermap", {
/* /*
* Generate WeatherObjects based on forecast information * Generate WeatherObjects based on forecast information
*/ */
generateWeatherObjectsFromForecast: function(forecasts) { generateWeatherObjectsFromForecast(forecasts) {
var days = []; const days = [];
for (var forecast of forecasts) { for (const forecast of forecasts) {
var weather = new WeatherObject(); const weather = new WeatherObject(this.config.units);
weather.date = moment(forecast.dt, "X"); weather.date = moment(forecast.dt, "X");
weather.minTemperature = forecast.temp.min; weather.minTemperature = forecast.temp.min;
@ -107,8 +107,8 @@ WeatherProvider.register("openweathermap", {
/* /*
* Convert the OpenWeatherMap icons to a more usable name. * Convert the OpenWeatherMap icons to a more usable name.
*/ */
convertWeatherType: function(weatherType) { convertWeatherType(weatherType) {
var weatherTypes = { const weatherTypes = {
"01d": "day-sunny", "01d": "day-sunny",
"02d": "day-cloudy", "02d": "day-cloudy",
"03d": "cloudy", "03d": "cloudy",
@ -137,8 +137,8 @@ WeatherProvider.register("openweathermap", {
* *
* return String - URL params. * return String - URL params.
*/ */
getParams: function() { getParams() {
var params = "?"; let params = "?";
if(this.config.locationID) { if(this.config.locationID) {
params += "id=" + this.config.locationID; params += "id=" + this.config.locationID;
} else if(this.config.location) { } else if(this.config.location) {

View File

@ -46,7 +46,8 @@ Module.register("weather",{
onlyTemp: false, onlyTemp: false,
showRainAmount: true, showRainAmount: true,
colored: false colored: false,
showFeelsLike: true
}, },
// Module properties. // Module properties.

View File

@ -13,7 +13,8 @@
// As soon as we start implementing the forecast, mode properties will be added. // As soon as we start implementing the forecast, mode properties will be added.
class WeatherObject { class WeatherObject {
constructor() { constructor(units) {
this.units = units;
this.date = null; this.date = null;
this.windSpeed = null; this.windSpeed = null;
this.windDirection = null; this.windDirection = null;
@ -26,7 +27,7 @@ class WeatherObject {
this.humidity = null; this.humidity = null;
} }
cardinalWindDirection () { cardinalWindDirection() {
if (this.windDirection > 11.25 && this.windDirection <= 33.75){ if (this.windDirection > 11.25 && this.windDirection <= 33.75){
return "NNE"; return "NNE";
} else if (this.windDirection > 33.75 && this.windDirection <= 56.25) { } else if (this.windDirection > 33.75 && this.windDirection <= 56.25) {
@ -62,20 +63,37 @@ class WeatherObject {
} }
} }
beaufortWindSpeed () { beaufortWindSpeed() {
var kmh = this.windSpeed * 60 * 60 / 1000; const windInKmh = this.units === "imperial" ? this.windSpeed * 1.609344 : this.windSpeed * 60 * 60 / 1000;
var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000]; const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
for (var beaufort in speeds) { for (const [index, speed] of speeds.entries()) {
var speed = speeds[beaufort]; if (speed > windInKmh) {
if (speed > kmh) { return index;
return beaufort;
} }
} }
return 12; return 12;
} }
nextSunAction () { nextSunAction() {
var now = new Date(); return moment().isBetween(this.sunrise, this.sunset) ? "sunset" : "sunrise";
return (this.sunrise < now && this.sunset > now) ? "sunset" : "sunrise"; }
feelsLike() {
const windInMph = this.units === "imperial" ? this.windSpeed : this.windSpeed * 2.23694;
const tempInF = this.units === "imperial" ? this.temperature : this.temperature * 9 / 5 + 32;
let feelsLike = tempInF;
if (windInMph > 3 && tempInF < 50) {
feelsLike = Math.round(35.74 + 0.6215 * tempInF - 35.75 * Math.pow(windInMph, 0.16) + 0.4275 * tempInF * Math.pow(windInMph, 0.16));
} else if (tempInF > 80 && this.humidity > 40) {
feelsLike = -42.379 + 2.04901523 * tempInF + 10.14333127 * this.humidity
- 0.22475541 * tempInF * this.humidity - 6.83783 * Math.pow(10, -3) * tempInF * tempInF
- 5.481717 * Math.pow(10, -2) * this.humidity * this.humidity
+ 1.22874 * Math.pow(10, -3) * tempInF * tempInF * this.humidity
+ 8.5282 * Math.pow(10, -4) * tempInF * this.humidity * this.humidity
- 1.99 * Math.pow(10, -6) * tempInF * tempInF * this.humidity * this.humidity;
}
return this.units === "imperial" ? feelsLike : (feelsLike - 32) * 5 / 9;
} }
} }