Release 2.22.0 (#2983)

## [2.22.0] - 2023-01-01

Thanks to: @angeldeejay, @buxxi, @dariom, @dWoolridge,
@KristjanESPERANTO, @MagMar94, @naveensrinivasan, @retroflex, @SkySails
and @Tom.

Special thanks to @khassel, @rejas and @sdetweil for taking over most
(if not all) of the work on this release as project collaborators. This
version would not be there without their effort. Thank you!

### Added

- Added test for remoteFile option in compliments module
- Added hourlyWeather functionality to Weather.gov weather provider
- Removed weatherEndpoint definition from weathergov.js (not used)
- Added css class names "today" and "tomorrow" for default calendar
- Added Collaboration.md
- Added new github action for dependency review (#2862)
- Added a WeatherProvider for Open-Meteo
- Added Yr as a weather provider
- Added config options "ignoreXOriginHeader" and
"ignoreContentSecurityPolicy"

### Removed

- Removed usage of internal fetch function of node until it is more
stable

### Updated

- Cleaned up test directory (#2937) and jest config (#2959)
- Wait for all modules to start before declaring the system ready
(#2487)
- Updated e2e tests (moved `done()` in helper functions) and use es6
syntax in all tests
- Updated da translation
- Rework weather module
- Make sure smhi provider api only gets a maximum of 6 digits
coordinates (#2955)
  - Use fetch instead of XMLHttpRequest in weatherprovider (#2935)
  - Reworked how weatherproviders handle units (#2849)
  - Use unix() method for parsing times, fix suntimes on the way (#2950)
  - Refactor conversion functions into utils class (#2958)
- The `cors`-method in `server.js` now supports sending and recieving
HTTP headers
- Replace `…` by `…`
- Cleanup compliments module
- Updated dependencies including electron to v22 (#2903)

### Fixed

- Correctly show apparent temperature in SMHI weather provider
- Ensure updatenotification module isn't shown when local is _ahead_ of
remote
- Handle node_helper errors during startup (#2944)
- Possibility to change FontAwesome class in calendar, so icons like
`fab fa-facebook-square` works.
- Fix cors problems with newsfeed articles (as far as possible), allow
disabling cors per feed with option `useCorsProxy: false` (#2840)
- Tests not waiting for the application to start and stop before
starting the next test
- Fix electron tests failing sometimes in github workflow
- Fixed gap in clock module when displayed on the left side with
displayType=digital
- Fixed playwright issue by upgrading to v1.29.1 (#2969)

Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: veeck <michael@veeck.de>
Co-authored-by: dWoolridge <dwoolridge@charter.net>
Co-authored-by: Johan <jojjepersson@yahoo.se>
Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com>
Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com>
Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com>
Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com>
Co-authored-by: buxxi <buxxi@omfilm.net>
Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com>
This commit is contained in:
Michael Teeuw
2023-01-01 18:09:08 +01:00
committed by GitHub
parent 9e0293047f
commit 0300ce05d5
151 changed files with 5890 additions and 4949 deletions

View File

@@ -1,4 +1,4 @@
/* global WeatherProvider, WeatherObject */
/* global WeatherProvider, WeatherObject, WeatherUtils */
/* MagicMirror²
* Module: Weather
@@ -22,7 +22,6 @@ WeatherProvider.register("weathergov", {
// Set the default config properties that is specific to this provider
defaults: {
apiBase: "https://api.weather.gov/points/",
weatherEndpoint: "/forecast",
lat: 0,
lon: 0
},
@@ -57,7 +56,7 @@ WeatherProvider.register("weathergov", {
// Overwrite the fetchCurrentWeather method.
fetchCurrentWeather() {
if (!this.configURLs) {
Log.info("fetch wx waiting on config URLs");
Log.info("fetchCurrentWeather: fetch wx waiting on config URLs");
return;
}
this.fetchData(this.stationObsURL)
@@ -78,7 +77,7 @@ WeatherProvider.register("weathergov", {
// Overwrite the fetchWeatherForecast method.
fetchWeatherForecast() {
if (!this.configURLs) {
Log.info("fetch wx waiting on config URLs");
Log.info("fetchWeatherForecast: fetch wx waiting on config URLs");
return;
}
this.fetchData(this.forecastURL)
@@ -96,6 +95,28 @@ WeatherProvider.register("weathergov", {
.finally(() => this.updateAvailable());
},
// Overwrite the fetchWeatherHourly method.
fetchWeatherHourly() {
if (!this.configURLs) {
Log.info("fetchWeatherHourly: fetch wx waiting on config URLs");
return;
}
this.fetchData(this.forecastHourlyURL)
.then((data) => {
if (!data) {
// Did not receive usable new data.
// Maybe this needs a better check?
return;
}
const hourly = this.generateWeatherObjectsFromHourly(data.properties.periods);
this.setWeatherHourly(hourly);
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable());
},
/** Weather.gov Specific Methods - These are not part of the default provider methods */
/*
@@ -110,8 +131,8 @@ WeatherProvider.register("weathergov", {
}
this.fetchedLocationName = data.properties.relativeLocation.properties.city + ", " + data.properties.relativeLocation.properties.state;
Log.log("Forecast location is " + this.fetchedLocationName);
this.forecastURL = data.properties.forecast;
this.forecastHourlyURL = data.properties.forecastHourly;
this.forecastURL = data.properties.forecast + "?units=si";
this.forecastHourlyURL = data.properties.forecastHourly + "?units=si";
this.forecastGridDataURL = data.properties.forecastGridData;
this.observationStationsURL = data.properties.observationStations;
// with this URL, we chain another promise for the station obs URL
@@ -130,14 +151,49 @@ WeatherProvider.register("weathergov", {
.finally(() => {
// excellent, let's fetch some actual wx data
this.configURLs = true;
// handle 'forecast' config, fall back to 'current'
if (config.type === "forecast") {
this.fetchWeatherForecast();
} else if (config.type === "hourly") {
this.fetchWeatherHourly();
} else {
this.fetchCurrentWeather();
}
});
},
/*
* Generate a WeatherObject based on hourlyWeatherInformation
* Weather.gov API uses specific units; API does not include choice of units
* ... object needs data in units based on config!
*/
generateWeatherObjectsFromHourly(forecasts) {
const days = [];
// variable for date
let weather = new WeatherObject();
for (const forecast of forecasts) {
weather.date = moment(forecast.startTime.slice(0, 19));
if (forecast.windSpeed.search(" ") < 0) {
weather.windSpeed = forecast.windSpeed;
} else {
weather.windSpeed = forecast.windSpeed.slice(0, forecast.windSpeed.search(" "));
}
weather.windDirection = this.convertWindDirection(forecast.windDirection);
weather.temperature = forecast.temperature;
weather.tempUnits = forecast.temperatureUnit;
// use the forecast isDayTime attribute to help build the weatherType label
weather.weatherType = this.convertWeatherType(forecast.shortForecast, forecast.isDaytime);
days.push(weather);
weather = new WeatherObject();
}
// push weather information to days array
days.push(weather);
return days;
},
/*
* Generate a WeatherObject based on currentWeatherInformation
@@ -145,24 +201,24 @@ WeatherProvider.register("weathergov", {
* ... object needs data in units based on config!
*/
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.temperature = this.convertTemp(currentWeatherData.temperature.value);
currentWeather.windSpeed = this.convertSpeed(currentWeatherData.windSpeed.value);
currentWeather.temperature = currentWeatherData.temperature.value;
currentWeather.windSpeed = WeatherUtils.convertWindToMs(currentWeatherData.windSpeed.value);
currentWeather.windDirection = currentWeatherData.windDirection.value;
currentWeather.minTemperature = this.convertTemp(currentWeatherData.minTemperatureLast24Hours.value);
currentWeather.maxTemperature = this.convertTemp(currentWeatherData.maxTemperatureLast24Hours.value);
currentWeather.minTemperature = currentWeatherData.minTemperatureLast24Hours.value;
currentWeather.maxTemperature = currentWeatherData.maxTemperatureLast24Hours.value;
currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value);
currentWeather.rain = null;
currentWeather.snow = null;
currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value);
if (currentWeatherData.heatIndex.value !== null) {
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value);
currentWeather.feelsLikeTemp = currentWeatherData.heatIndex.value;
} else if (currentWeatherData.windChill.value !== null) {
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.windChill.value);
currentWeather.feelsLikeTemp = currentWeatherData.windChill.value;
} else {
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.temperature.value);
currentWeather.feelsLikeTemp = currentWeatherData.temperature.value;
}
// determine the sunrise/sunset times - not supplied in weather.gov data
currentWeather.updateSunTime(this.config.lat, this.config.lon);
@@ -191,7 +247,7 @@ WeatherProvider.register("weathergov", {
let maxTemp = [];
// variable for 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;
for (const forecast of forecasts) {
@@ -203,7 +259,7 @@ WeatherProvider.register("weathergov", {
// push weather information to days array
days.push(weather);
// create new weather-object
weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
weather = new WeatherObject();
minTemp = [];
maxTemp = [];
@@ -242,26 +298,6 @@ WeatherProvider.register("weathergov", {
/*
* 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
convertLength(meters) {
if (this.config.units === "imperial") {
@@ -339,31 +375,5 @@ WeatherProvider.register("weathergov", {
}
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;
}
});