Merge branch 'develop' into logger

This commit is contained in:
Karsten Hassel 2021-09-09 21:18:28 +02:00
commit 91d72e48ad
9 changed files with 55 additions and 188 deletions

View File

@ -439,6 +439,7 @@ Special thanks to @sdetweil for all his great contributions!
- Update `ical.js` to solve various calendar issues. - Update `ical.js` to solve various calendar issues.
- Update weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676) - Update weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
- Only update clock once per minute when seconds aren't shown - Only update clock once per minute when seconds aren't shown
- Update weatherprovider documentation.
### Fixed ### Fixed

View File

@ -1,148 +1,3 @@
# MagicMirror² Weather Module Weather Provider Development Documentation # Weather Module Weather Provider Development Documentation
This document describes the way to develop your own MagicMirror² weather module weather provider. For how to develop your own weather provider, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/development/weather-provider.html).
Table of Contents:
- The weather provider file: yourprovider.js
- [Weather provider methods to implement](#weather-provider-methods-to-implement)
- [Weather Provider instance methods](#weather-provider-instance-methods)
- [WeatherObject](#weatherobject)
---
## The weather provider file: yourprovider.js
This is the script in which the weather provider will be defined. In its most simple form, the weather provider must implement the following:
```javascript
WeatherProvider.register("yourprovider", {
providerName: "YourProvider",
fetchCurrentWeather() {},
fetchWeatherForecast() {}
});
```
### Weather provider methods to implement
#### `fetchCurrentWeather()`
This method is called when the weather module tries to fetch the current weather of your provider. The implementation of this method is required for current weather support.
The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise.
After the response is processed, the current weather information (as a [WeatherObject](#weatherobject)) needs to be set with `this.setCurrentWeather(currentWeather);`.
It will then automatically refresh the module DOM with the new data.
#### `fetchWeatherForecast()`
This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required for forecast support.
The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise.
After the response is processed, the weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setWeatherForecast(forecast);`.
It will then automatically refresh the module DOM with the new data.
#### `fetchWeatherHourly()`
This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required for hourly support.
The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise.
After the response is processed, the hourly weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setWeatherHourly(forecast);`.
It will then automatically refresh the module DOM with the new data.
### Weather Provider instance methods
#### `init()`
Called when a weather provider is initialized.
#### `setConfig(config)`
Called to set the config, this config is the same as the weather module's config.
#### `start()`
Called when the weather provider is about to start.
#### `currentWeather()`
This returns a WeatherDay object for the current weather.
#### `weatherForecast()`
This returns an array of WeatherDay objects for the weather forecast.
#### `weatherHourly()`
This returns an array of WeatherDay objects for the hourly weather forecast.
#### `fetchedLocation()`
This returns the name of the fetched location or an empty string.
#### `setCurrentWeather(currentWeatherObject)`
Set the currentWeather and notify the delegate that new information is available.
#### `setWeatherForecast(weatherForecastArray)`
Set the weatherForecastArray and notify the delegate that new information is available.
#### `setWeatherHourly(weatherHourlyArray)`
Set the weatherHourlyArray and notify the delegate that new information is available.
#### `setFetchedLocation(name)`
Set the fetched location name.
#### `updateAvailable()`
Notify the delegate that new weather is available.
#### `fetchData(url, method, data)`
A convenience function to make requests. It returns a promise.
### WeatherObject
| Property | Type | Value/Unit |
| -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| units | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
| tempUnits | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
| windUnits | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
| date | `object` | [Moment.js](https://momentjs.com/) object of the time/date. |
| windSpeed | `number` | Metric: `meter/second` <br> Imperial: `miles/hour` |
| windDirection | `number` | Direction of the wind in degrees. |
| sunrise | `object` | [Moment.js](https://momentjs.com/) object of sunrise. |
| sunset | `object` | [Moment.js](https://momentjs.com/) object of sunset. |
| temperature | `number` | Current temperature |
| minTemperature | `number` | Lowest temperature of the day. |
| maxTemperature | `number` | Highest temperature of the day. |
| weatherType | `string` | Icon name of the weather type. <br> Possible values: [WeatherIcons](https://www.npmjs.com/package/weathericons) |
| humidity | `number` | Percentage of humidity |
| rain | `number` | Metric: `millimeters` <br> Imperial: `inches` |
| snow | `number` | Metric: `millimeters` <br> Imperial: `inches` |
| precipitation | `number` | Metric: `millimeters` <br> Imperial: `inches` <br> UK Met Office provider: `percent` |
#### Current weather
For the current weather object the following properties are required:
- humidity
- sunrise
- sunset
- temperature
- units
- weatherType
- windDirection
- windSpeed
#### Weather forecast
For the forecast weather object the following properties are required:
- date
- maxTemperature
- minTemperature
- rain
- units
- weatherType

View File

@ -8,7 +8,8 @@
* MIT Licensed * MIT Licensed
* *
* This class is a provider for Dark Sky. * This class is a provider for Dark Sky.
* Note that the Dark Sky API does not provide rainfall. Instead it provides snowfall and precipitation probability * Note that the Dark Sky API does not provide rainfall. Instead it provides
* snowfall and precipitation probability
*/ */
WeatherProvider.register("darksky", { WeatherProvider.register("darksky", {
// Set the name of the provider. // Set the name of the provider.
@ -98,7 +99,8 @@ WeatherProvider.register("darksky", {
weather.snow = 0; weather.snow = 0;
// The API will return centimeters if units is 'si' and will return inches for 'us' // The API will return centimeters if units is 'si' and will return inches for 'us'
// Note that the Dark Sky API does not provide rainfall. Instead it provides snowfall and precipitation probability // Note that the Dark Sky API does not provide rainfall.
// Instead it provides snowfall and precipitation probability
if (forecast.hasOwnProperty("precipAccumulation")) { if (forecast.hasOwnProperty("precipAccumulation")) {
if (this.config.units === "imperial" && !isNaN(forecast.precipAccumulation)) { if (this.config.units === "imperial" && !isNaN(forecast.precipAccumulation)) {
weather.snow = forecast.precipAccumulation; weather.snow = forecast.precipAccumulation;

View File

@ -18,10 +18,10 @@ WeatherProvider.register("openweathermap", {
defaults: { defaults: {
apiVersion: "2.5", apiVersion: "2.5",
apiBase: "https://api.openweathermap.org/data/", apiBase: "https://api.openweathermap.org/data/",
weatherEndpoint: "", weatherEndpoint: "", // can be "onecall", "forecast" or "weather" (for current)
locationID: false, locationID: false,
location: false, location: false,
lat: 0, lat: 0, // the onecall endpoint needs lat / lon values, it doesn'T support the locationId
lon: 0, lon: 0,
apiKey: "" apiKey: ""
}, },

View File

@ -7,9 +7,8 @@
* By BuXXi https://github.com/buxxi * By BuXXi https://github.com/buxxi
* MIT Licensed * MIT Licensed
* *
* This class is a provider for SMHI (Sweden only). * This class is a provider for SMHI (Sweden only). Metric system is the only
* Note that SMHI doesn't provide sunrise and sundown, use SunCalc to calculate it. * supported unit.
* Metric system is the only supported unit.
*/ */
WeatherProvider.register("smhi", { WeatherProvider.register("smhi", {
providerName: "SMHI", providerName: "SMHI",
@ -193,7 +192,8 @@ WeatherProvider.register("smhi", {
}, },
/** /**
* Resolve coordinates from the response data (probably preferably to use this if it's not matching the config values exactly) * Resolve coordinates from the response data (probably preferably to use
* this if it's not matching the config values exactly)
* *
* @param {object} data Response data from the weather service * @param {object} data Response data from the weather service
* @returns {{lon, lat}} the lat/long coordinates of the data * @returns {{lon, lat}} the lat/long coordinates of the data
@ -237,12 +237,12 @@ WeatherProvider.register("smhi", {
}, },
/** /**
* Map the icon value from SHMI to an icon that MagicMirror understands. * Map the icon value from SMHI to an icon that MagicMirror understands.
* Uses different icons depending if its daytime or nighttime. * Uses different icons depending if its daytime or nighttime.
* SHMI's description of what the numeric value means is the comment after the case. * SMHI's description of what the numeric value means is the comment after the case.
* *
* @param {number} input The smhi icon value * @param {number} input The SMHI icon value
* @param {boolean} isDayTime True if the icon should be for daytime, false for nightime * @param {boolean} isDayTime True if the icon should be for daytime, false for nighttime
* @returns {string} The icon name for the MagicMirror * @returns {string} The icon name for the MagicMirror
*/ */
convertWeatherType(input, isDayTime) { convertWeatherType(input, isDayTime) {
@ -250,57 +250,57 @@ WeatherProvider.register("smhi", {
case 1: case 1:
return isDayTime ? "day-sunny" : "night-clear"; // Clear sky return isDayTime ? "day-sunny" : "night-clear"; // Clear sky
case 2: case 2:
return isDayTime ? "day-sunny-overcast" : "night-partly-cloudy"; //Nearly clear sky return isDayTime ? "day-sunny-overcast" : "night-partly-cloudy"; // Nearly clear sky
case 3: case 3:
return isDayTime ? "day-cloudy" : "night-cloudy"; //Variable cloudiness return isDayTime ? "day-cloudy" : "night-cloudy"; // Variable cloudiness
case 4: case 4:
return isDayTime ? "day-cloudy" : "night-cloudy"; //Halfclear sky return isDayTime ? "day-cloudy" : "night-cloudy"; // Halfclear sky
case 5: case 5:
return "cloudy"; //Cloudy sky return "cloudy"; // Cloudy sky
case 6: case 6:
return "cloudy"; //Overcast return "cloudy"; // Overcast
case 7: case 7:
return "fog"; //Fog return "fog"; // Fog
case 8: case 8:
return "showers"; //Light rain showers return "showers"; // Light rain showers
case 9: case 9:
return "showers"; //Moderate rain showers return "showers"; // Moderate rain showers
case 10: case 10:
return "showers"; //Heavy rain showers return "showers"; // Heavy rain showers
case 11: case 11:
return "thunderstorm"; //Thunderstorm return "thunderstorm"; // Thunderstorm
case 12: case 12:
return "sleet"; //Light sleet showers return "sleet"; // Light sleet showers
case 13: case 13:
return "sleet"; //Moderate sleet showers return "sleet"; // Moderate sleet showers
case 14: case 14:
return "sleet"; //Heavy sleet showers return "sleet"; // Heavy sleet showers
case 15: case 15:
return "snow"; //Light snow showers return "snow"; // Light snow showers
case 16: case 16:
return "snow"; //Moderate snow showers return "snow"; // Moderate snow showers
case 17: case 17:
return "snow"; //Heavy snow showers return "snow"; // Heavy snow showers
case 18: case 18:
return "rain"; //Light rain return "rain"; // Light rain
case 19: case 19:
return "rain"; //Moderate rain return "rain"; // Moderate rain
case 20: case 20:
return "rain"; //Heavy rain return "rain"; // Heavy rain
case 21: case 21:
return "thunderstorm"; //Thunder return "thunderstorm"; // Thunder
case 22: case 22:
return "sleet"; // Light sleet return "sleet"; // Light sleet
case 23: case 23:
return "sleet"; //Moderate sleet return "sleet"; // Moderate sleet
case 24: case 24:
return "sleet"; // Heavy sleet return "sleet"; // Heavy sleet
case 25: case 25:
return "snow"; // Light snowfall return "snow"; // Light snowfall
case 26: case 26:
return "snow"; //Moderate snowfall return "snow"; // Moderate snowfall
case 27: case 27:
return "snow"; //Heavy snowfall return "snow"; // Heavy snowfall
default: default:
return ""; return "";
} }

View File

@ -13,9 +13,8 @@
* Hourly data for next 2 days ("hourly") - https://www.metoffice.gov.uk/binaries/content/assets/metofficegovuk/pdf/data/global-spot-data-hourly.pdf * Hourly data for next 2 days ("hourly") - https://www.metoffice.gov.uk/binaries/content/assets/metofficegovuk/pdf/data/global-spot-data-hourly.pdf
* 3-hourly data for the next 7 days ("3hourly") - https://www.metoffice.gov.uk/binaries/content/assets/metofficegovuk/pdf/data/global-spot-data-3-hourly.pdf * 3-hourly data for the next 7 days ("3hourly") - https://www.metoffice.gov.uk/binaries/content/assets/metofficegovuk/pdf/data/global-spot-data-3-hourly.pdf
* Daily data for the next 7 days ("daily") - https://www.metoffice.gov.uk/binaries/content/assets/metofficegovuk/pdf/data/global-spot-data-daily.pdf * Daily data for the next 7 days ("daily") - https://www.metoffice.gov.uk/binaries/content/assets/metofficegovuk/pdf/data/global-spot-data-daily.pdf
*/ *
* NOTES
/* NOTES
* This provider requires longitude/latitude coordinates, rather than a location ID (as with the previous Met Office provider) * This provider requires longitude/latitude coordinates, rather than a location ID (as with the previous Met Office provider)
* Provide the following in your config.js file: * Provide the following in your config.js file:
* weatherProvider: "ukmetofficedatahub", * weatherProvider: "ukmetofficedatahub",

View File

@ -7,7 +7,8 @@
* By Andrew Pometti * By Andrew Pometti
* MIT Licensed * MIT Licensed
* *
* This class is a provider for Weatherbit, based on Nicholas Hubbard's class for Dark Sky & Vince Peri's class for Weather.gov. * This class is a provider for Weatherbit, based on Nicholas Hubbard's class
* for Dark Sky & Vince Peri's class for Weather.gov.
*/ */
WeatherProvider.register("weatherbit", { WeatherProvider.register("weatherbit", {
// Set the name of the provider. // Set the name of the provider.

View File

@ -133,7 +133,9 @@ class WeatherObject {
} }
/** /**
* Update the sunrise / sunset time depending on the location * Update the sunrise / sunset time depending on the location. This can be
* used if your provider doesnt provide that data by itself. Then SunCalc
* is used here to calculate them according to the location.
* *
* @param {number} lat latitude * @param {number} lat latitude
* @param {number} lon longitude * @param {number} lon longitude

View File

@ -1,12 +1,15 @@
const WeatherObject = require("../../../modules/default/weather/weatherobject.js"); const WeatherObject = require("../../../modules/default/weather/weatherobject.js");
global.moment = require("moment"); global.moment = require("moment-timezone");
global.SunCalc = require("suncalc"); global.SunCalc = require("suncalc");
describe("WeatherObject", function () { describe("WeatherObject", function () {
let originalTimeZone;
let weatherobject; let weatherobject;
beforeAll(function () { beforeAll(function () {
originalTimeZone = moment.tz.guess();
moment.tz.setDefault("Africa/Dar_es_Salaam");
weatherobject = new WeatherObject("metric", "metric", "metric", true); weatherobject = new WeatherObject("metric", "metric", "metric", true);
}); });
@ -21,4 +24,8 @@ describe("WeatherObject", function () {
weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327); weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327);
expect(weatherobject.isDayTime()).toBe(false); expect(weatherobject.isDayTime()).toBe(false);
}); });
afterAll(function () {
moment.tz.setDefault(originalTimeZone);
});
}); });