mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-08-21 04:45:17 +00:00
Replace prettier by stylistic to lint JavaScript (#3303)
In the latest versions of ESLint, more and more formatting rules were removed or declared deprecated. These rules have been integrated into the new Stylistic package (https://eslint.style/guide/why) and expanded. Stylistic acts as a better formatter for JavaScript as Prettier. With this PR there are many changes that make the code more uniform, but it may be difficult to review due to the large amount. Even if I have no worries about the changes, perhaps this would be something for the release after next. Let me know what you think.
This commit is contained in:
committed by
GitHub
parent
4e7b68a69d
commit
0b70274a1a
@@ -49,7 +49,7 @@ WeatherProvider.register("envcanada", {
|
||||
// Set config values (equates to weather module config values). Also set values pertaining to caching of
|
||||
// Today's temperature forecast (for use in the Forecast functions below)
|
||||
//
|
||||
setConfig: function (config) {
|
||||
setConfig (config) {
|
||||
this.config = config;
|
||||
|
||||
this.todayTempCacheMin = 0;
|
||||
@@ -61,7 +61,7 @@ WeatherProvider.register("envcanada", {
|
||||
//
|
||||
// Called when the weather provider is started
|
||||
//
|
||||
start: function () {
|
||||
start () {
|
||||
Log.info(`Weather provider: ${this.providerName} started.`);
|
||||
this.setFetchedLocation(this.config.location);
|
||||
},
|
||||
@@ -69,7 +69,7 @@ WeatherProvider.register("envcanada", {
|
||||
//
|
||||
// Override the fetchCurrentWeather method to query EC and construct a Current weather object
|
||||
//
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getUrl(), "xml")
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
@@ -89,7 +89,7 @@ WeatherProvider.register("envcanada", {
|
||||
//
|
||||
// Override the fetchWeatherForecast method to query EC and construct Forecast weather objects
|
||||
//
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getUrl(), "xml")
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
@@ -109,7 +109,7 @@ WeatherProvider.register("envcanada", {
|
||||
//
|
||||
// Override the fetchWeatherHourly method to query EC and construct Forecast weather objects
|
||||
//
|
||||
fetchWeatherHourly() {
|
||||
fetchWeatherHourly () {
|
||||
this.fetchData(this.getUrl(), "xml")
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
@@ -137,7 +137,7 @@ WeatherProvider.register("envcanada", {
|
||||
// URL defaults to the English version simply because there is no language dependency in the data
|
||||
// being accessed. This is only pertinent when using the EC data elements that contain a textual forecast.
|
||||
//
|
||||
getUrl() {
|
||||
getUrl () {
|
||||
return `https://dd.weather.gc.ca/citypage_weather/xml/${this.config.provCode}/${this.config.siteCode}_e.xml`;
|
||||
},
|
||||
|
||||
@@ -145,7 +145,7 @@ WeatherProvider.register("envcanada", {
|
||||
// Generate a WeatherObject based on current EC weather conditions
|
||||
//
|
||||
|
||||
generateWeatherObjectFromCurrentWeather(ECdoc) {
|
||||
generateWeatherObjectFromCurrentWeather (ECdoc) {
|
||||
const currentWeather = new WeatherObject();
|
||||
|
||||
// There are instances where EC will update weather data and current temperature will not be
|
||||
@@ -216,7 +216,7 @@ WeatherProvider.register("envcanada", {
|
||||
// Generate an array of WeatherObjects based on EC weather forecast
|
||||
//
|
||||
|
||||
generateWeatherObjectsFromForecast(ECdoc) {
|
||||
generateWeatherObjectsFromForecast (ECdoc) {
|
||||
// Declare an array to hold each day's forecast object
|
||||
|
||||
const days = [];
|
||||
@@ -360,7 +360,7 @@ WeatherProvider.register("envcanada", {
|
||||
// Generate an array of WeatherObjects based on EC hourly weather forecast
|
||||
//
|
||||
|
||||
generateWeatherObjectsFromHourly(ECdoc) {
|
||||
generateWeatherObjectsFromHourly (ECdoc) {
|
||||
// Declare an array to hold each hour's forecast object
|
||||
|
||||
const hours = [];
|
||||
@@ -416,7 +416,7 @@ WeatherProvider.register("envcanada", {
|
||||
// the next Forecast element should be considered - i.e. look at Today *and* Tonight vs.Tonight-only
|
||||
//
|
||||
|
||||
setMinMaxTemps(weather, foreGroup, today, fullDay, currentTemp) {
|
||||
setMinMaxTemps (weather, foreGroup, today, fullDay, currentTemp) {
|
||||
const todayTemp = foreGroup[today].querySelector("temperatures temperature").textContent;
|
||||
|
||||
const todayClass = foreGroup[today].querySelector("temperatures temperature").getAttribute("class");
|
||||
@@ -498,7 +498,7 @@ WeatherProvider.register("envcanada", {
|
||||
// the nightime forecast after a certain point in that specific scenario.
|
||||
//
|
||||
|
||||
setPrecipitation(weather, foreGroup, today) {
|
||||
setPrecipitation (weather, foreGroup, today) {
|
||||
if (foreGroup[today].querySelector("precipitation accumulation")) {
|
||||
weather.precipitationAmount = foreGroup[today].querySelector("precipitation accumulation amount").textContent * 1.0;
|
||||
weather.precipitationUnits = foreGroup[today].querySelector("precipitation accumulation amount").getAttribute("units");
|
||||
@@ -514,7 +514,7 @@ WeatherProvider.register("envcanada", {
|
||||
//
|
||||
// Convert the icons to a more usable name.
|
||||
//
|
||||
convertWeatherType(weatherType) {
|
||||
convertWeatherType (weatherType) {
|
||||
const weatherTypes = {
|
||||
"00": "day-sunny",
|
||||
"01": "day-sunny",
|
||||
|
@@ -140,11 +140,11 @@ WeatherProvider.register("openmeteo", {
|
||||
"et0_fao_evapotranspiration"
|
||||
],
|
||||
|
||||
fetchedLocation: function () {
|
||||
fetchedLocation () {
|
||||
return this.fetchedLocationName || "";
|
||||
},
|
||||
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => this.parseWeatherApiResponse(data))
|
||||
.then((parsedData) => {
|
||||
@@ -162,7 +162,7 @@ WeatherProvider.register("openmeteo", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => this.parseWeatherApiResponse(data))
|
||||
.then((parsedData) => {
|
||||
@@ -180,7 +180,7 @@ WeatherProvider.register("openmeteo", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
fetchWeatherHourly() {
|
||||
fetchWeatherHourly () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => this.parseWeatherApiResponse(data))
|
||||
.then((parsedData) => {
|
||||
@@ -202,7 +202,7 @@ WeatherProvider.register("openmeteo", {
|
||||
* Overrides method for setting config to check if endpoint is correct for hourly
|
||||
* @param {object} config The configuration object
|
||||
*/
|
||||
setConfig(config) {
|
||||
setConfig (config) {
|
||||
this.config = {
|
||||
lang: config.lang ?? "en",
|
||||
...this.defaults,
|
||||
@@ -226,7 +226,7 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Generate valid query params to perform the request
|
||||
getQueryParameters() {
|
||||
getQueryParameters () {
|
||||
let params = {
|
||||
latitude: this.config.lat,
|
||||
longitude: this.config.lon,
|
||||
@@ -278,25 +278,23 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Create a URL from the config and base URL.
|
||||
getUrl() {
|
||||
getUrl () {
|
||||
return `${this.config.apiBase}/forecast?${this.getQueryParameters()}`;
|
||||
},
|
||||
|
||||
// Transpose hourly and daily data matrices
|
||||
transposeDataMatrix(data) {
|
||||
return data.time.map((_, index) =>
|
||||
Object.keys(data).reduce((row, key) => {
|
||||
return {
|
||||
...row,
|
||||
// Parse time values as momentjs instances
|
||||
[key]: ["time", "sunrise", "sunset"].includes(key) ? moment.unix(data[key][index]) : data[key][index]
|
||||
};
|
||||
}, {})
|
||||
);
|
||||
transposeDataMatrix (data) {
|
||||
return data.time.map((_, index) => Object.keys(data).reduce((row, key) => {
|
||||
return {
|
||||
...row,
|
||||
// Parse time values as momentjs instances
|
||||
[key]: ["time", "sunrise", "sunset"].includes(key) ? moment.unix(data[key][index]) : data[key][index]
|
||||
};
|
||||
}, {}));
|
||||
},
|
||||
|
||||
// Sanitize and validate API response
|
||||
parseWeatherApiResponse(data) {
|
||||
parseWeatherApiResponse (data) {
|
||||
const validByType = {
|
||||
current: data.current_weather && data.current_weather.time,
|
||||
hourly: data.hourly && data.hourly.time && Array.isArray(data.hourly.time) && data.hourly.time.length > 0,
|
||||
@@ -334,7 +332,7 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Reverse geocoding from latitude and longitude provided
|
||||
fetchLocation() {
|
||||
fetchLocation () {
|
||||
this.fetchData(`${GEOCODE_BASE}?latitude=${this.config.lat}&longitude=${this.config.lon}&localityLanguage=${this.config.lang}`)
|
||||
.then((data) => {
|
||||
if (!data || !data.city) {
|
||||
@@ -349,7 +347,8 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Implement WeatherDay generator.
|
||||
generateWeatherDayFromCurrentWeather(weather) {
|
||||
generateWeatherDayFromCurrentWeather (weather) {
|
||||
|
||||
/**
|
||||
* Since some units comes from API response "splitted" into daily, hourly and current_weather
|
||||
* every time you request it, you have to ensure to get the data from the right place every time.
|
||||
@@ -394,7 +393,7 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Implement WeatherForecast generator.
|
||||
generateWeatherObjectsFromForecast(weathers) {
|
||||
generateWeatherObjectsFromForecast (weathers) {
|
||||
const days = [];
|
||||
|
||||
weathers.daily.forEach((weather) => {
|
||||
@@ -422,7 +421,7 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Implement WeatherHourly generator.
|
||||
generateWeatherObjectsFromHourly(weathers) {
|
||||
generateWeatherObjectsFromHourly (weathers) {
|
||||
const hours = [];
|
||||
const now = moment();
|
||||
|
||||
@@ -457,7 +456,7 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Map icons from Dark Sky to our icons.
|
||||
convertWeatherType(weathercode, isDayTime) {
|
||||
convertWeatherType (weathercode, isDayTime) {
|
||||
const weatherConditions = {
|
||||
0: "clear",
|
||||
1: "mainly-clear",
|
||||
@@ -542,7 +541,7 @@ WeatherProvider.register("openmeteo", {
|
||||
},
|
||||
|
||||
// Define required scripts.
|
||||
getScripts: function () {
|
||||
getScripts () {
|
||||
return ["moment.js"];
|
||||
}
|
||||
});
|
||||
|
@@ -27,7 +27,7 @@ WeatherProvider.register("openweathermap", {
|
||||
},
|
||||
|
||||
// Overwrite the fetchCurrentWeather method.
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
let currentWeather;
|
||||
@@ -46,7 +46,7 @@ WeatherProvider.register("openweathermap", {
|
||||
},
|
||||
|
||||
// Overwrite the fetchWeatherForecast method.
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
let forecast;
|
||||
@@ -68,7 +68,7 @@ WeatherProvider.register("openweathermap", {
|
||||
},
|
||||
|
||||
// Overwrite the fetchWeatherHourly method.
|
||||
fetchWeatherHourly() {
|
||||
fetchWeatherHourly () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
@@ -92,7 +92,7 @@ WeatherProvider.register("openweathermap", {
|
||||
* Overrides method for setting config to check if endpoint is correct for hourly
|
||||
* @param {object} config The configuration object
|
||||
*/
|
||||
setConfig(config) {
|
||||
setConfig (config) {
|
||||
this.config = config;
|
||||
if (!this.config.weatherEndpoint) {
|
||||
switch (this.config.type) {
|
||||
@@ -116,14 +116,14 @@ WeatherProvider.register("openweathermap", {
|
||||
/*
|
||||
* Gets the complete url for the request
|
||||
*/
|
||||
getUrl() {
|
||||
getUrl () {
|
||||
return this.config.apiBase + this.config.apiVersion + this.config.weatherEndpoint + this.getParams();
|
||||
},
|
||||
|
||||
/*
|
||||
* Generate a WeatherObject based on currentWeatherInformation
|
||||
*/
|
||||
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
||||
generateWeatherObjectFromCurrentWeather (currentWeatherData) {
|
||||
const currentWeather = new WeatherObject();
|
||||
|
||||
currentWeather.date = moment.unix(currentWeatherData.dt);
|
||||
@@ -142,7 +142,7 @@ WeatherProvider.register("openweathermap", {
|
||||
/*
|
||||
* Generate WeatherObjects based on forecast information
|
||||
*/
|
||||
generateWeatherObjectsFromForecast(forecasts) {
|
||||
generateWeatherObjectsFromForecast (forecasts) {
|
||||
if (this.config.weatherEndpoint === "/forecast") {
|
||||
return this.generateForecastHourly(forecasts);
|
||||
} else if (this.config.weatherEndpoint === "/forecast/daily") {
|
||||
@@ -155,7 +155,7 @@ WeatherProvider.register("openweathermap", {
|
||||
/*
|
||||
* Generate WeatherObjects based on One Call forecast information
|
||||
*/
|
||||
generateWeatherObjectsFromOnecall(data) {
|
||||
generateWeatherObjectsFromOnecall (data) {
|
||||
if (this.config.weatherEndpoint === "/onecall") {
|
||||
return this.fetchOnecall(data);
|
||||
}
|
||||
@@ -167,7 +167,7 @@ WeatherProvider.register("openweathermap", {
|
||||
* Generate forecast information for 3-hourly forecast (available for free
|
||||
* subscription).
|
||||
*/
|
||||
generateForecastHourly(forecasts) {
|
||||
generateForecastHourly (forecasts) {
|
||||
// initial variable declaration
|
||||
const days = [];
|
||||
// variables for temperature range and rain
|
||||
@@ -241,7 +241,7 @@ WeatherProvider.register("openweathermap", {
|
||||
* Generate forecast information for daily forecast (available for paid
|
||||
* subscription or old apiKey).
|
||||
*/
|
||||
generateForecastDaily(forecasts) {
|
||||
generateForecastDaily (forecasts) {
|
||||
// initial variable declaration
|
||||
const days = [];
|
||||
|
||||
@@ -281,7 +281,7 @@ WeatherProvider.register("openweathermap", {
|
||||
* Factors in timezone offsets.
|
||||
* Minutely forecasts are excluded for the moment, see getParams().
|
||||
*/
|
||||
fetchOnecall(data) {
|
||||
fetchOnecall (data) {
|
||||
let precip = false;
|
||||
|
||||
// get current weather, if requested
|
||||
@@ -382,7 +382,7 @@ WeatherProvider.register("openweathermap", {
|
||||
/*
|
||||
* Convert the OpenWeatherMap icons to a more usable name.
|
||||
*/
|
||||
convertWeatherType(weatherType) {
|
||||
convertWeatherType (weatherType) {
|
||||
const weatherTypes = {
|
||||
"01d": "day-sunny",
|
||||
"02d": "day-cloudy",
|
||||
@@ -412,7 +412,7 @@ WeatherProvider.register("openweathermap", {
|
||||
*
|
||||
* return String - URL params.
|
||||
*/
|
||||
getParams() {
|
||||
getParams () {
|
||||
let params = "?";
|
||||
if (this.config.weatherEndpoint === "/onecall") {
|
||||
params += `lat=${this.config.lat}`;
|
||||
|
@@ -21,7 +21,7 @@ const OverrideWrapper = Class.extend({
|
||||
notificationWeatherObject: null,
|
||||
currentOverrideWeatherObject: null,
|
||||
|
||||
init(baseProvider) {
|
||||
init (baseProvider) {
|
||||
this.baseProvider = baseProvider;
|
||||
|
||||
// Binding the scope of current weather functions so any fetchData calls with
|
||||
@@ -33,43 +33,43 @@ const OverrideWrapper = Class.extend({
|
||||
|
||||
/* Unchanged Api Provider Methods */
|
||||
|
||||
setConfig(config) {
|
||||
setConfig (config) {
|
||||
this.baseProvider.setConfig(config);
|
||||
},
|
||||
start() {
|
||||
start () {
|
||||
this.baseProvider.start();
|
||||
},
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.baseProvider.fetchCurrentWeather();
|
||||
},
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.baseProvider.fetchWeatherForecast();
|
||||
},
|
||||
fetchWeatherHourly() {
|
||||
fetchWeatherHourly () {
|
||||
this.baseProvider.fetchEatherHourly();
|
||||
},
|
||||
weatherForecast() {
|
||||
weatherForecast () {
|
||||
this.baseProvider.weatherForecast();
|
||||
},
|
||||
weatherHourly() {
|
||||
weatherHourly () {
|
||||
this.baseProvider.weatherHourly();
|
||||
},
|
||||
fetchedLocation() {
|
||||
fetchedLocation () {
|
||||
this.baseProvider.fetchedLocation();
|
||||
},
|
||||
setWeatherForecast(weatherForecastArray) {
|
||||
setWeatherForecast (weatherForecastArray) {
|
||||
this.baseProvider.setWeatherForecast(weatherForecastArray);
|
||||
},
|
||||
setWeatherHourly(weatherHourlyArray) {
|
||||
setWeatherHourly (weatherHourlyArray) {
|
||||
this.baseProvider.setWeatherHourly(weatherHourlyArray);
|
||||
},
|
||||
setFetchedLocation(name) {
|
||||
setFetchedLocation (name) {
|
||||
this.baseProvider.setFetchedLocation(name);
|
||||
},
|
||||
updateAvailable() {
|
||||
updateAvailable () {
|
||||
this.baseProvider.updateAvailable();
|
||||
},
|
||||
async fetchData(url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) {
|
||||
async fetchData (url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) {
|
||||
this.baseProvider.fetchData(url, type, requestHeaders, expectedResponseHeaders);
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ const OverrideWrapper = Class.extend({
|
||||
* Override to return this scope's
|
||||
* @returns {WeatherObject} The current weather object. May or may not contain overridden data.
|
||||
*/
|
||||
currentWeather() {
|
||||
currentWeather () {
|
||||
return this.currentOverrideWeatherObject;
|
||||
},
|
||||
|
||||
@@ -89,7 +89,7 @@ const OverrideWrapper = Class.extend({
|
||||
* api provider fetchData implementation.
|
||||
* @param {WeatherObject} currentWeatherObject - the api provider weather object
|
||||
*/
|
||||
setCurrentWeather(currentWeatherObject) {
|
||||
setCurrentWeather (currentWeatherObject) {
|
||||
this.currentOverrideWeatherObject = Object.assign(currentWeatherObject, this.notificationWeatherObject);
|
||||
},
|
||||
|
||||
@@ -101,7 +101,7 @@ const OverrideWrapper = Class.extend({
|
||||
* notification. Represents information to augment the
|
||||
* existing currentOverrideWeatherObject with.
|
||||
*/
|
||||
notificationReceived(payload) {
|
||||
notificationReceived (payload) {
|
||||
this.notificationWeatherObject = payload;
|
||||
|
||||
// setCurrentWeather combines the newly received notification weather with
|
||||
|
@@ -25,7 +25,7 @@ WeatherProvider.register("pirateweather", {
|
||||
lon: 0
|
||||
},
|
||||
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
if (!data || !data.currently || typeof data.currently.temperature === "undefined") {
|
||||
@@ -42,7 +42,7 @@ WeatherProvider.register("pirateweather", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
if (!data || !data.daily || !data.daily.data.length) {
|
||||
@@ -60,12 +60,12 @@ WeatherProvider.register("pirateweather", {
|
||||
},
|
||||
|
||||
// Create a URL from the config and base URL.
|
||||
getUrl() {
|
||||
getUrl () {
|
||||
return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=si&lang=${this.config.lang}`;
|
||||
},
|
||||
|
||||
// Implement WeatherDay generator.
|
||||
generateWeatherDayFromCurrentWeather(currentWeatherData) {
|
||||
generateWeatherDayFromCurrentWeather (currentWeatherData) {
|
||||
const currentWeather = new WeatherObject();
|
||||
|
||||
currentWeather.date = moment();
|
||||
@@ -80,7 +80,7 @@ WeatherProvider.register("pirateweather", {
|
||||
return currentWeather;
|
||||
},
|
||||
|
||||
generateWeatherObjectsFromForecast(forecasts) {
|
||||
generateWeatherObjectsFromForecast (forecasts) {
|
||||
const days = [];
|
||||
|
||||
for (const forecast of forecasts) {
|
||||
@@ -114,7 +114,7 @@ WeatherProvider.register("pirateweather", {
|
||||
},
|
||||
|
||||
// Map icons from Pirate Weather to our icons.
|
||||
convertWeatherType(weatherType) {
|
||||
convertWeatherType (weatherType) {
|
||||
const weatherTypes = {
|
||||
"clear-day": "day-sunny",
|
||||
"clear-night": "night-clear",
|
||||
|
@@ -24,7 +24,7 @@ WeatherProvider.register("smhi", {
|
||||
/**
|
||||
* Implements method in interface for fetching current weather.
|
||||
*/
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getURL())
|
||||
.then((data) => {
|
||||
const closest = this.getClosestToCurrentTime(data.timeSeries);
|
||||
@@ -40,7 +40,7 @@ WeatherProvider.register("smhi", {
|
||||
/**
|
||||
* Implements method in interface for fetching a multi-day forecast.
|
||||
*/
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getURL())
|
||||
.then((data) => {
|
||||
const coordinates = this.resolveCoordinates(data);
|
||||
@@ -55,7 +55,7 @@ WeatherProvider.register("smhi", {
|
||||
/**
|
||||
* Implements method in interface for fetching hourly forecasts.
|
||||
*/
|
||||
fetchWeatherHourly() {
|
||||
fetchWeatherHourly () {
|
||||
this.fetchData(this.getURL())
|
||||
.then((data) => {
|
||||
const coordinates = this.resolveCoordinates(data);
|
||||
@@ -71,7 +71,7 @@ WeatherProvider.register("smhi", {
|
||||
* Overrides method for setting config with checks for the precipitationValue being unset or invalid
|
||||
* @param {object} config The configuration object
|
||||
*/
|
||||
setConfig(config) {
|
||||
setConfig (config) {
|
||||
this.config = config;
|
||||
if (!config.precipitationValue || ["pmin", "pmean", "pmedian", "pmax"].indexOf(config.precipitationValue) === -1) {
|
||||
Log.log(`invalid or not set: ${config.precipitationValue}`);
|
||||
@@ -84,7 +84,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {object[]} times Array of time objects
|
||||
* @returns {object} The weatherdata closest to the current time
|
||||
*/
|
||||
getClosestToCurrentTime(times) {
|
||||
getClosestToCurrentTime (times) {
|
||||
let now = moment();
|
||||
let minDiff = undefined;
|
||||
for (const time of times) {
|
||||
@@ -100,7 +100,7 @@ WeatherProvider.register("smhi", {
|
||||
* Get the forecast url for the configured coordinates
|
||||
* @returns {string} the url for the specified coordinates
|
||||
*/
|
||||
getURL() {
|
||||
getURL () {
|
||||
const formatter = new Intl.NumberFormat("en-US", {
|
||||
minimumFractionDigits: 6,
|
||||
maximumFractionDigits: 6
|
||||
@@ -115,7 +115,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {object} weatherData Weatherdata to use for the calculation
|
||||
* @returns {number} The apparent temperature
|
||||
*/
|
||||
calculateApparentTemperature(weatherData) {
|
||||
calculateApparentTemperature (weatherData) {
|
||||
const Ta = this.paramValue(weatherData, "t");
|
||||
const rh = this.paramValue(weatherData, "r");
|
||||
const ws = this.paramValue(weatherData, "ws");
|
||||
@@ -132,7 +132,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {object} coordinates Coordinates of the locations of the weather
|
||||
* @returns {WeatherObject} The converted weatherdata at the specified location
|
||||
*/
|
||||
convertWeatherDataToObject(weatherData, coordinates) {
|
||||
convertWeatherDataToObject (weatherData, coordinates) {
|
||||
let currentWeather = new WeatherObject();
|
||||
|
||||
currentWeather.date = moment(weatherData.validTime);
|
||||
@@ -178,7 +178,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {string} groupBy The interval to use for grouping the data (day, hour)
|
||||
* @returns {WeatherObject[]} Array of weatherobjects
|
||||
*/
|
||||
convertWeatherDataGroupedBy(allWeatherData, coordinates, groupBy = "day") {
|
||||
convertWeatherDataGroupedBy (allWeatherData, coordinates, groupBy = "day") {
|
||||
let currentWeather;
|
||||
let result = [];
|
||||
|
||||
@@ -227,7 +227,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {object} data Response data from the weather service
|
||||
* @returns {{lon, lat}} the lat/long coordinates of the data
|
||||
*/
|
||||
resolveCoordinates(data) {
|
||||
resolveCoordinates (data) {
|
||||
return { lat: data.geometry.coordinates[0][1], lon: data.geometry.coordinates[0][0] };
|
||||
},
|
||||
|
||||
@@ -237,7 +237,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {object[]} data Response data from the weather service
|
||||
* @returns {object[]} Given data with filled gaps
|
||||
*/
|
||||
fillInGaps(data) {
|
||||
fillInGaps (data) {
|
||||
let result = [];
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
let to = moment(data[i].validTime);
|
||||
@@ -259,7 +259,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {string} name The name of the property
|
||||
* @returns {*} The value of the property in the weatherdata
|
||||
*/
|
||||
paramValue(currentWeatherData, name) {
|
||||
paramValue (currentWeatherData, name) {
|
||||
return currentWeatherData.parameters.filter((p) => p.name === name).flatMap((p) => p.values)[0];
|
||||
},
|
||||
|
||||
@@ -271,7 +271,7 @@ WeatherProvider.register("smhi", {
|
||||
* @param {boolean} isDayTime True if the icon should be for daytime, false for nighttime
|
||||
* @returns {string} The icon name for the MagicMirror
|
||||
*/
|
||||
convertWeatherType(input, isDayTime) {
|
||||
convertWeatherType (input, isDayTime) {
|
||||
switch (input) {
|
||||
case 1:
|
||||
return isDayTime ? "day-sunny" : "night-clear"; // Clear sky
|
||||
|
@@ -22,7 +22,7 @@ WeatherProvider.register("ukmetoffice", {
|
||||
},
|
||||
|
||||
// Overwrite the fetchCurrentWeather method.
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getUrl("3hourly"))
|
||||
.then((data) => {
|
||||
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
|
||||
@@ -43,7 +43,7 @@ WeatherProvider.register("ukmetoffice", {
|
||||
},
|
||||
|
||||
// Overwrite the fetchCurrentWeather method.
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getUrl("daily"))
|
||||
.then((data) => {
|
||||
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
|
||||
@@ -67,14 +67,14 @@ WeatherProvider.register("ukmetoffice", {
|
||||
/*
|
||||
* Gets the complete url for the request
|
||||
*/
|
||||
getUrl(forecastType) {
|
||||
getUrl (forecastType) {
|
||||
return this.config.apiBase + this.config.locationID + this.getParams(forecastType);
|
||||
},
|
||||
|
||||
/*
|
||||
* Generate a WeatherObject based on currentWeatherInformation
|
||||
*/
|
||||
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
||||
generateWeatherObjectFromCurrentWeather (currentWeatherData) {
|
||||
const currentWeather = new WeatherObject();
|
||||
const location = currentWeatherData.SiteRep.DV.Location;
|
||||
|
||||
@@ -119,7 +119,7 @@ WeatherProvider.register("ukmetoffice", {
|
||||
/*
|
||||
* Generate WeatherObjects based on forecast information
|
||||
*/
|
||||
generateWeatherObjectsFromForecast(forecasts) {
|
||||
generateWeatherObjectsFromForecast (forecasts) {
|
||||
const days = [];
|
||||
|
||||
// loop round the (5) periods getting the data
|
||||
@@ -150,7 +150,7 @@ WeatherProvider.register("ukmetoffice", {
|
||||
/*
|
||||
* Convert the Met Office icons to a more usable name.
|
||||
*/
|
||||
convertWeatherType(weatherType) {
|
||||
convertWeatherType (weatherType) {
|
||||
const weatherTypes = {
|
||||
0: "night-clear",
|
||||
1: "day-sunny",
|
||||
@@ -192,7 +192,7 @@ WeatherProvider.register("ukmetoffice", {
|
||||
* @param {string} forecastType daily or 3hourly forecast
|
||||
* @returns {string} url
|
||||
*/
|
||||
getParams(forecastType) {
|
||||
getParams (forecastType) {
|
||||
let params = "?";
|
||||
params += `res=${forecastType}`;
|
||||
params += `&key=${this.config.apiKey}`;
|
||||
|
@@ -53,7 +53,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
},
|
||||
|
||||
// Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
|
||||
getUrl(forecastType) {
|
||||
getUrl (forecastType) {
|
||||
let queryStrings = "?";
|
||||
queryStrings += `latitude=${this.config.lat}`;
|
||||
queryStrings += `&longitude=${this.config.lon}`;
|
||||
@@ -66,7 +66,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
// Build the list of headers for the request
|
||||
// For DataHub requests, the API key/secret are sent in the headers rather than as query strings.
|
||||
// Headers defined according to Data Hub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
|
||||
getHeaders() {
|
||||
getHeaders () {
|
||||
return {
|
||||
accept: "application/json",
|
||||
"x-ibm-client-id": this.config.apiKey,
|
||||
@@ -75,7 +75,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
},
|
||||
|
||||
// Fetch data using supplied URL and request headers
|
||||
async fetchWeather(url, headers) {
|
||||
async fetchWeather (url, headers) {
|
||||
const response = await fetch(url, { headers: headers });
|
||||
|
||||
// Return JSON data
|
||||
@@ -83,7 +83,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
},
|
||||
|
||||
// Fetch hourly forecast data (to use for current weather)
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchWeather(this.getUrl("hourly"), this.getHeaders())
|
||||
.then((data) => {
|
||||
// Check data is usable
|
||||
@@ -111,7 +111,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
},
|
||||
|
||||
// Create a WeatherObject using current weather data (data for the current hour)
|
||||
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
||||
generateWeatherObjectFromCurrentWeather (currentWeatherData) {
|
||||
const currentWeather = new WeatherObject();
|
||||
|
||||
// Extract the actual forecasts
|
||||
@@ -152,7 +152,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
},
|
||||
|
||||
// Fetch daily forecast data
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchWeather(this.getUrl("daily"), this.getHeaders())
|
||||
.then((data) => {
|
||||
// Check data is usable
|
||||
@@ -180,7 +180,7 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
},
|
||||
|
||||
// Create a WeatherObject for each day using daily forecast data
|
||||
generateWeatherObjectsFromForecast(forecasts) {
|
||||
generateWeatherObjectsFromForecast (forecasts) {
|
||||
const dailyForecasts = [];
|
||||
|
||||
// Extract the actual forecasts
|
||||
@@ -225,14 +225,14 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
},
|
||||
|
||||
// Set the fetched location name.
|
||||
setFetchedLocation: function (name) {
|
||||
setFetchedLocation (name) {
|
||||
this.fetchedLocationName = name;
|
||||
},
|
||||
|
||||
// Match the Met Office "significant weather code" to a weathericons.css icon
|
||||
// Use: https://metoffice.apiconnect.ibmcloud.com/metoffice/production/node/264
|
||||
// and: https://erikflowers.github.io/weather-icons/
|
||||
convertWeatherType(weatherType) {
|
||||
convertWeatherType (weatherType) {
|
||||
const weatherTypes = {
|
||||
0: "night-clear",
|
||||
1: "day-sunny",
|
||||
|
@@ -23,11 +23,11 @@ WeatherProvider.register("weatherbit", {
|
||||
lon: 0
|
||||
},
|
||||
|
||||
fetchedLocation: function () {
|
||||
fetchedLocation () {
|
||||
return this.fetchedLocationName || "";
|
||||
},
|
||||
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
if (!data || !data.data[0] || typeof data.data[0].temp === "undefined") {
|
||||
@@ -44,7 +44,7 @@ WeatherProvider.register("weatherbit", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
if (!data || !data.data) {
|
||||
@@ -67,7 +67,7 @@ WeatherProvider.register("weatherbit", {
|
||||
* Overrides method for setting config to check if endpoint is correct for hourly
|
||||
* @param {object} config The configuration object
|
||||
*/
|
||||
setConfig(config) {
|
||||
setConfig (config) {
|
||||
this.config = config;
|
||||
if (!this.config.weatherEndpoint) {
|
||||
switch (this.config.type) {
|
||||
@@ -88,12 +88,12 @@ WeatherProvider.register("weatherbit", {
|
||||
},
|
||||
|
||||
// Create a URL from the config and base URL.
|
||||
getUrl() {
|
||||
getUrl () {
|
||||
return `${this.config.apiBase}${this.config.weatherEndpoint}?lat=${this.config.lat}&lon=${this.config.lon}&units=M&key=${this.config.apiKey}`;
|
||||
},
|
||||
|
||||
// Implement WeatherDay generator.
|
||||
generateWeatherDayFromCurrentWeather(currentWeatherData) {
|
||||
generateWeatherDayFromCurrentWeather (currentWeatherData) {
|
||||
//Calculate TZ Offset and invert to convert Sunrise/Sunset times to Local
|
||||
const d = new Date();
|
||||
let tzOffset = d.getTimezoneOffset();
|
||||
@@ -115,7 +115,7 @@ WeatherProvider.register("weatherbit", {
|
||||
return currentWeather;
|
||||
},
|
||||
|
||||
generateWeatherObjectsFromForecast(forecasts) {
|
||||
generateWeatherObjectsFromForecast (forecasts) {
|
||||
const days = [];
|
||||
|
||||
for (const forecast of forecasts) {
|
||||
@@ -135,7 +135,7 @@ WeatherProvider.register("weatherbit", {
|
||||
},
|
||||
|
||||
// Map icons from Dark Sky to our icons.
|
||||
convertWeatherType(weatherType) {
|
||||
convertWeatherType (weatherType) {
|
||||
const weatherTypes = {
|
||||
t01d: "day-thunderstorm",
|
||||
t01n: "night-alt-thunderstorm",
|
||||
|
@@ -23,7 +23,7 @@ WeatherProvider.register("weatherflow", {
|
||||
stationid: ""
|
||||
},
|
||||
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
const currentWeather = new WeatherObject();
|
||||
@@ -44,7 +44,7 @@ WeatherProvider.register("weatherflow", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
const days = [];
|
||||
@@ -71,7 +71,7 @@ WeatherProvider.register("weatherflow", {
|
||||
},
|
||||
|
||||
// Create a URL from the config and base URL.
|
||||
getUrl() {
|
||||
getUrl () {
|
||||
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}`;
|
||||
}
|
||||
});
|
||||
|
@@ -37,24 +37,24 @@ WeatherProvider.register("weathergov", {
|
||||
stationObsURL: "tbd",
|
||||
|
||||
// Called to set the config, this config is the same as the weather module's config.
|
||||
setConfig: function (config) {
|
||||
setConfig (config) {
|
||||
this.config = config;
|
||||
this.config.apiBase = "https://api.weather.gov";
|
||||
this.fetchWxGovURLs(this.config);
|
||||
},
|
||||
|
||||
// Called when the weather provider is about to start.
|
||||
start: function () {
|
||||
start () {
|
||||
Log.info(`Weather provider: ${this.providerName} started.`);
|
||||
},
|
||||
|
||||
// This returns the name of the fetched location or an empty string.
|
||||
fetchedLocation: function () {
|
||||
fetchedLocation () {
|
||||
return this.fetchedLocationName || "";
|
||||
},
|
||||
|
||||
// Overwrite the fetchCurrentWeather method.
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
if (!this.configURLs) {
|
||||
Log.info("fetchCurrentWeather: fetch wx waiting on config URLs");
|
||||
return;
|
||||
@@ -75,7 +75,7 @@ WeatherProvider.register("weathergov", {
|
||||
},
|
||||
|
||||
// Overwrite the fetchWeatherForecast method.
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
if (!this.configURLs) {
|
||||
Log.info("fetchWeatherForecast: fetch wx waiting on config URLs");
|
||||
return;
|
||||
@@ -96,7 +96,7 @@ WeatherProvider.register("weathergov", {
|
||||
},
|
||||
|
||||
// Overwrite the fetchWeatherHourly method.
|
||||
fetchWeatherHourly() {
|
||||
fetchWeatherHourly () {
|
||||
if (!this.configURLs) {
|
||||
Log.info("fetchWeatherHourly: fetch wx waiting on config URLs");
|
||||
return;
|
||||
@@ -122,7 +122,7 @@ WeatherProvider.register("weathergov", {
|
||||
/*
|
||||
* Get specific URLs
|
||||
*/
|
||||
fetchWxGovURLs(config) {
|
||||
fetchWxGovURLs (config) {
|
||||
this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`)
|
||||
.then((data) => {
|
||||
if (!data || !data.properties) {
|
||||
@@ -162,12 +162,13 @@ WeatherProvider.register("weathergov", {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
generateWeatherObjectsFromHourly (forecasts) {
|
||||
const days = [];
|
||||
|
||||
// variable for date
|
||||
@@ -206,7 +207,7 @@ WeatherProvider.register("weathergov", {
|
||||
* Weather.gov API uses specific units; API does not include choice of units
|
||||
* ... object needs data in units based on config!
|
||||
*/
|
||||
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
|
||||
generateWeatherObjectFromCurrentWeather (currentWeatherData) {
|
||||
const currentWeather = new WeatherObject();
|
||||
|
||||
currentWeather.date = moment(currentWeatherData.timestamp);
|
||||
@@ -236,14 +237,14 @@ WeatherProvider.register("weathergov", {
|
||||
/*
|
||||
* Generate WeatherObjects based on forecast information
|
||||
*/
|
||||
generateWeatherObjectsFromForecast(forecasts) {
|
||||
generateWeatherObjectsFromForecast (forecasts) {
|
||||
return this.fetchForecastDaily(forecasts);
|
||||
},
|
||||
|
||||
/*
|
||||
* fetch forecast information for daily forecast.
|
||||
*/
|
||||
fetchForecastDaily(forecasts) {
|
||||
fetchForecastDaily (forecasts) {
|
||||
// initial variable declaration
|
||||
const days = [];
|
||||
// variables for temperature range and rain
|
||||
@@ -306,7 +307,7 @@ WeatherProvider.register("weathergov", {
|
||||
/*
|
||||
* Convert the icons to a more usable name.
|
||||
*/
|
||||
convertWeatherType(weatherType, isDaytime) {
|
||||
convertWeatherType (weatherType, isDaytime) {
|
||||
//https://w1.weather.gov/xml/current_obs/weather.php
|
||||
// There are way too many types to create, so lets just look for certain strings
|
||||
|
||||
|
@@ -24,7 +24,7 @@ WeatherProvider.register("yr", {
|
||||
currentForecastHours: 1 //1, 6 or 12
|
||||
},
|
||||
|
||||
start() {
|
||||
start () {
|
||||
if (typeof Storage === "undefined") {
|
||||
//local storage unavailable
|
||||
Log.error("The Yr weather provider requires local storage.");
|
||||
@@ -33,7 +33,7 @@ WeatherProvider.register("yr", {
|
||||
Log.info(`Weather provider: ${this.providerName} started.`);
|
||||
},
|
||||
|
||||
fetchCurrentWeather() {
|
||||
fetchCurrentWeather () {
|
||||
this.getCurrentWeather()
|
||||
.then((currentWeather) => {
|
||||
this.setCurrentWeather(currentWeather);
|
||||
@@ -45,7 +45,7 @@ WeatherProvider.register("yr", {
|
||||
});
|
||||
},
|
||||
|
||||
async getCurrentWeather() {
|
||||
async getCurrentWeather () {
|
||||
const [weatherData, stellarData] = await Promise.all([this.getWeatherData(), this.getStellarData()]);
|
||||
if (!stellarData) {
|
||||
Log.warn("No stellar data available.");
|
||||
@@ -73,7 +73,7 @@ WeatherProvider.register("yr", {
|
||||
return this.getWeatherDataFrom(forecast, stellarData, weatherData.properties.meta.units);
|
||||
},
|
||||
|
||||
getWeatherData() {
|
||||
getWeatherData () {
|
||||
return new Promise((resolve, reject) => {
|
||||
// If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes.
|
||||
// This is to avoid multiple similar calls to the API.
|
||||
@@ -99,7 +99,7 @@ WeatherProvider.register("yr", {
|
||||
});
|
||||
},
|
||||
|
||||
getWeatherDataFromYrOrCache(resolve, reject) {
|
||||
getWeatherDataFromYrOrCache (resolve, reject) {
|
||||
localStorage.setItem("yrIsFetchingWeatherData", "true");
|
||||
|
||||
let weatherData = this.getWeatherDataFromCache();
|
||||
@@ -131,16 +131,16 @@ WeatherProvider.register("yr", {
|
||||
}
|
||||
},
|
||||
|
||||
weatherDataIsValid(weatherData) {
|
||||
weatherDataIsValid (weatherData) {
|
||||
return (
|
||||
weatherData &&
|
||||
weatherData.timeout &&
|
||||
0 < moment(weatherData.timeout).diff(moment()) &&
|
||||
(!weatherData.geometry || !weatherData.geometry.coordinates || !weatherData.geometry.coordinates.length < 2 || (weatherData.geometry.coordinates[0] === this.config.lat && weatherData.geometry.coordinates[1] === this.config.lon))
|
||||
weatherData
|
||||
&& weatherData.timeout
|
||||
&& 0 < moment(weatherData.timeout).diff(moment())
|
||||
&& (!weatherData.geometry || !weatherData.geometry.coordinates || !weatherData.geometry.coordinates.length < 2 || (weatherData.geometry.coordinates[0] === this.config.lat && weatherData.geometry.coordinates[1] === this.config.lon))
|
||||
);
|
||||
},
|
||||
|
||||
getWeatherDataFromCache() {
|
||||
getWeatherDataFromCache () {
|
||||
const weatherData = localStorage.getItem("weatherData");
|
||||
if (weatherData) {
|
||||
return JSON.parse(weatherData);
|
||||
@@ -149,7 +149,7 @@ WeatherProvider.register("yr", {
|
||||
}
|
||||
},
|
||||
|
||||
getWeatherDataFromYr(currentDataFetchedAt) {
|
||||
getWeatherDataFromYr (currentDataFetchedAt) {
|
||||
const requestHeaders = [{ name: "Accept", value: "application/json" }];
|
||||
if (currentDataFetchedAt) {
|
||||
requestHeaders.push({ name: "If-Modified-Since", value: currentDataFetchedAt });
|
||||
@@ -171,7 +171,7 @@ WeatherProvider.register("yr", {
|
||||
});
|
||||
},
|
||||
|
||||
getConfigOptions() {
|
||||
getConfigOptions () {
|
||||
if (!this.config.lat) {
|
||||
Log.error("Latitude not provided.");
|
||||
throw new Error("Latitude not provided.");
|
||||
@@ -187,7 +187,7 @@ WeatherProvider.register("yr", {
|
||||
return { lat, lon, altitude };
|
||||
},
|
||||
|
||||
getForecastUrl() {
|
||||
getForecastUrl () {
|
||||
let { lat, lon, altitude } = this.getConfigOptions();
|
||||
|
||||
if (lat.includes(".") && lat.split(".")[1].length > 4) {
|
||||
@@ -204,11 +204,11 @@ WeatherProvider.register("yr", {
|
||||
return `${this.config.apiBase}/locationforecast/${this.config.forecastApiVersion}/complete?&altitude=${altitude}&lat=${lat}&lon=${lon}`;
|
||||
},
|
||||
|
||||
cacheWeatherData(weatherData) {
|
||||
cacheWeatherData (weatherData) {
|
||||
localStorage.setItem("weatherData", JSON.stringify(weatherData));
|
||||
},
|
||||
|
||||
getStellarData() {
|
||||
getStellarData () {
|
||||
// If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes.
|
||||
// This is to avoid multiple similar calls to the API.
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -234,7 +234,7 @@ WeatherProvider.register("yr", {
|
||||
});
|
||||
},
|
||||
|
||||
getStellarDataFromYrOrCache(resolve, reject) {
|
||||
getStellarDataFromYrOrCache (resolve, reject) {
|
||||
localStorage.setItem("yrIsFetchingStellarData", "true");
|
||||
|
||||
let stellarData = this.getStellarDataFromCache();
|
||||
@@ -292,7 +292,7 @@ WeatherProvider.register("yr", {
|
||||
}
|
||||
},
|
||||
|
||||
getStellarDataFromCache() {
|
||||
getStellarDataFromCache () {
|
||||
const stellarData = localStorage.getItem("stellarData");
|
||||
if (stellarData) {
|
||||
return JSON.parse(stellarData);
|
||||
@@ -301,7 +301,7 @@ WeatherProvider.register("yr", {
|
||||
}
|
||||
},
|
||||
|
||||
getStellarDataFromYr(date, days = 1) {
|
||||
getStellarDataFromYr (date, days = 1) {
|
||||
const requestHeaders = [{ name: "Accept", value: "application/json" }];
|
||||
return this.fetchData(this.getStellarDataUrl(date, days), "json", requestHeaders)
|
||||
.then((data) => {
|
||||
@@ -314,7 +314,7 @@ WeatherProvider.register("yr", {
|
||||
});
|
||||
},
|
||||
|
||||
getStellarDataUrl(date, days) {
|
||||
getStellarDataUrl (date, days) {
|
||||
let { lat, lon, altitude } = this.getConfigOptions();
|
||||
|
||||
if (lat.includes(".") && lat.split(".")[1].length > 4) {
|
||||
@@ -345,11 +345,11 @@ WeatherProvider.register("yr", {
|
||||
return `${this.config.apiBase}/sunrise/${this.config.sunriseApiVersion}/sun?lat=${lat}&lon=${lon}&date=${date}&offset=${utcOffsetPrefix}${hours}%3A${minutes}`;
|
||||
},
|
||||
|
||||
cacheStellarData(data) {
|
||||
cacheStellarData (data) {
|
||||
localStorage.setItem("stellarData", JSON.stringify(data));
|
||||
},
|
||||
|
||||
getWeatherDataFrom(forecast, stellarData, units) {
|
||||
getWeatherDataFrom (forecast, stellarData, units) {
|
||||
const weather = new WeatherObject();
|
||||
|
||||
weather.date = moment(forecast.time);
|
||||
@@ -370,7 +370,7 @@ WeatherProvider.register("yr", {
|
||||
return weather;
|
||||
},
|
||||
|
||||
convertWeatherType(weatherType, weatherTime) {
|
||||
convertWeatherType (weatherType, weatherTime) {
|
||||
const weatherHour = moment(weatherTime).format("HH");
|
||||
|
||||
const weatherTypes = {
|
||||
@@ -462,7 +462,7 @@ WeatherProvider.register("yr", {
|
||||
return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
|
||||
},
|
||||
|
||||
getForecastForXHoursFrom(weather) {
|
||||
getForecastForXHoursFrom (weather) {
|
||||
if (this.config.currentForecastHours === 1) {
|
||||
if (weather.next_1_hours) {
|
||||
return weather.next_1_hours;
|
||||
@@ -490,7 +490,7 @@ WeatherProvider.register("yr", {
|
||||
}
|
||||
},
|
||||
|
||||
fetchWeatherHourly() {
|
||||
fetchWeatherHourly () {
|
||||
this.getWeatherForecast("hourly")
|
||||
.then((forecast) => {
|
||||
this.setWeatherHourly(forecast);
|
||||
@@ -502,7 +502,7 @@ WeatherProvider.register("yr", {
|
||||
});
|
||||
},
|
||||
|
||||
async getWeatherForecast(type) {
|
||||
async getWeatherForecast (type) {
|
||||
const [weatherData, stellarData] = await Promise.all([this.getWeatherData(), this.getStellarData()]);
|
||||
if (!weatherData.properties.timeseries || !weatherData.properties.timeseries[0]) {
|
||||
Log.error("No weather data available.");
|
||||
@@ -528,7 +528,7 @@ WeatherProvider.register("yr", {
|
||||
return series;
|
||||
},
|
||||
|
||||
getHourlyForecastFrom(weatherData) {
|
||||
getHourlyForecastFrom (weatherData) {
|
||||
const series = [];
|
||||
|
||||
for (const forecast of weatherData.properties.timeseries) {
|
||||
@@ -543,7 +543,7 @@ WeatherProvider.register("yr", {
|
||||
return series;
|
||||
},
|
||||
|
||||
getDailyForecastFrom(weatherData) {
|
||||
getDailyForecastFrom (weatherData) {
|
||||
const series = [];
|
||||
|
||||
const days = weatherData.properties.timeseries.reduce(function (days, forecast) {
|
||||
@@ -593,7 +593,7 @@ WeatherProvider.register("yr", {
|
||||
return series;
|
||||
},
|
||||
|
||||
fetchWeatherForecast() {
|
||||
fetchWeatherForecast () {
|
||||
this.getWeatherForecast("daily")
|
||||
.then((forecast) => {
|
||||
this.setWeatherForecast(forecast);
|
||||
|
@@ -56,17 +56,17 @@ Module.register("weather", {
|
||||
firstEvent: null,
|
||||
|
||||
// Define required scripts.
|
||||
getStyles: function () {
|
||||
getStyles () {
|
||||
return ["font-awesome.css", "weather-icons.css", "weather.css"];
|
||||
},
|
||||
|
||||
// Return the scripts that are necessary for the weather module.
|
||||
getScripts: function () {
|
||||
getScripts () {
|
||||
return ["moment.js", "weatherutils.js", "weatherobject.js", this.file("providers/overrideWrapper.js"), "weatherprovider.js", "suncalc.js", this.file(`providers/${this.config.weatherProvider.toLowerCase()}.js`)];
|
||||
},
|
||||
|
||||
// Override getHeader method.
|
||||
getHeader: function () {
|
||||
getHeader () {
|
||||
if (this.config.appendLocationNameToHeader && this.weatherProvider) {
|
||||
if (this.data.header) return `${this.data.header} ${this.weatherProvider.fetchedLocation()}`;
|
||||
else return this.weatherProvider.fetchedLocation();
|
||||
@@ -76,7 +76,7 @@ Module.register("weather", {
|
||||
},
|
||||
|
||||
// Start the weather module.
|
||||
start: function () {
|
||||
start () {
|
||||
moment.locale(this.config.lang);
|
||||
|
||||
if (this.config.useKmh) {
|
||||
@@ -101,7 +101,7 @@ Module.register("weather", {
|
||||
},
|
||||
|
||||
// Override notification handler.
|
||||
notificationReceived: function (notification, payload, sender) {
|
||||
notificationReceived (notification, payload, sender) {
|
||||
if (notification === "CALENDAR_EVENTS") {
|
||||
const senderClasses = sender.data.classes.toLowerCase().split(" ");
|
||||
if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) {
|
||||
@@ -126,7 +126,7 @@ Module.register("weather", {
|
||||
},
|
||||
|
||||
// Select the template depending on the display type.
|
||||
getTemplate: function () {
|
||||
getTemplate () {
|
||||
switch (this.config.type.toLowerCase()) {
|
||||
case "current":
|
||||
return "current.njk";
|
||||
@@ -142,7 +142,7 @@ Module.register("weather", {
|
||||
},
|
||||
|
||||
// Add all the data to the template.
|
||||
getTemplateData: function () {
|
||||
getTemplateData () {
|
||||
const currentData = this.weatherProvider.currentWeather();
|
||||
const forecastData = this.weatherProvider.weatherForecast();
|
||||
|
||||
@@ -162,7 +162,7 @@ Module.register("weather", {
|
||||
},
|
||||
|
||||
// What to do when the weather provider has new information available?
|
||||
updateAvailable: function () {
|
||||
updateAvailable () {
|
||||
Log.log("New weather information available.");
|
||||
this.updateDom(0);
|
||||
this.scheduleUpdate();
|
||||
@@ -181,7 +181,7 @@ Module.register("weather", {
|
||||
this.sendNotification("WEATHER_UPDATED", notificationPayload);
|
||||
},
|
||||
|
||||
scheduleUpdate: function (delay = null) {
|
||||
scheduleUpdate (delay = null) {
|
||||
let nextLoad = this.config.updateInterval;
|
||||
if (delay !== null && delay >= 0) {
|
||||
nextLoad = delay;
|
||||
@@ -205,13 +205,13 @@ Module.register("weather", {
|
||||
}, nextLoad);
|
||||
},
|
||||
|
||||
roundValue: function (temperature) {
|
||||
roundValue (temperature) {
|
||||
const decimals = this.config.roundTemp ? 0 : 1;
|
||||
const roundValue = parseFloat(temperature).toFixed(decimals);
|
||||
return roundValue === "-0" ? 0 : roundValue;
|
||||
},
|
||||
|
||||
addFilters() {
|
||||
addFilters () {
|
||||
this.nunjucksEnvironment().addFilter(
|
||||
"formatTime",
|
||||
function (date) {
|
||||
|
@@ -16,10 +16,11 @@
|
||||
* @external Moment
|
||||
*/
|
||||
class WeatherObject {
|
||||
|
||||
/**
|
||||
* Constructor for a WeatherObject
|
||||
*/
|
||||
constructor() {
|
||||
constructor () {
|
||||
this.date = null;
|
||||
this.windSpeed = null;
|
||||
this.windFromDirection = null;
|
||||
@@ -36,7 +37,7 @@ class WeatherObject {
|
||||
this.feelsLikeTemp = null;
|
||||
}
|
||||
|
||||
cardinalWindDirection() {
|
||||
cardinalWindDirection () {
|
||||
if (this.windFromDirection > 11.25 && this.windFromDirection <= 33.75) {
|
||||
return "NNE";
|
||||
} else if (this.windFromDirection > 33.75 && this.windFromDirection <= 56.25) {
|
||||
@@ -79,11 +80,11 @@ class WeatherObject {
|
||||
* action for. Useful only in tests, defaults to the current time.
|
||||
* @returns {string} "sunset" or "sunrise"
|
||||
*/
|
||||
nextSunAction(date = moment()) {
|
||||
nextSunAction (date = moment()) {
|
||||
return date.isBetween(this.sunrise, this.sunset) ? "sunset" : "sunrise";
|
||||
}
|
||||
|
||||
feelsLike() {
|
||||
feelsLike () {
|
||||
if (this.feelsLikeTemp) {
|
||||
return this.feelsLikeTemp;
|
||||
}
|
||||
@@ -94,7 +95,7 @@ class WeatherObject {
|
||||
* Checks if the weatherObject is at dayTime.
|
||||
* @returns {boolean} true if it is at dayTime
|
||||
*/
|
||||
isDayTime() {
|
||||
isDayTime () {
|
||||
const now = !this.date ? moment() : this.date;
|
||||
return now.isBetween(this.sunrise, this.sunset, undefined, "[]");
|
||||
}
|
||||
@@ -106,7 +107,7 @@ class WeatherObject {
|
||||
* @param {number} lat latitude
|
||||
* @param {number} lon longitude
|
||||
*/
|
||||
updateSunTime(lat, lon) {
|
||||
updateSunTime (lat, lon) {
|
||||
const now = !this.date ? new Date() : this.date.toDate();
|
||||
const times = SunCalc.getTimes(now, lat, lon);
|
||||
this.sunrise = moment(times.sunrise);
|
||||
@@ -120,7 +121,7 @@ class WeatherObject {
|
||||
* Especially 'moment' object is not immutable, so original 'date', 'sunrise', 'sunset' could be corrupted or changed by other modules.
|
||||
* @returns {object} plained object clone of original weatherObject
|
||||
*/
|
||||
simpleClone() {
|
||||
simpleClone () {
|
||||
const toFlat = ["date", "sunrise", "sunset"];
|
||||
let clone = { ...this };
|
||||
for (const prop of toFlat) {
|
||||
|
@@ -30,84 +30,84 @@ const WeatherProvider = Class.extend({
|
||||
// All the following methods can be overwritten, although most are good as they are.
|
||||
|
||||
// Called when a weather provider is initialized.
|
||||
init: function (config) {
|
||||
init (config) {
|
||||
this.config = config;
|
||||
Log.info(`Weather provider: ${this.providerName} initialized.`);
|
||||
},
|
||||
|
||||
// Called to set the config, this config is the same as the weather module's config.
|
||||
setConfig: function (config) {
|
||||
setConfig (config) {
|
||||
this.config = config;
|
||||
Log.info(`Weather provider: ${this.providerName} config set.`, this.config);
|
||||
},
|
||||
|
||||
// Called when the weather provider is about to start.
|
||||
start: function () {
|
||||
start () {
|
||||
Log.info(`Weather provider: ${this.providerName} started.`);
|
||||
},
|
||||
|
||||
// This method should start the API request to fetch the current weather.
|
||||
// This method should definitely be overwritten in the provider.
|
||||
fetchCurrentWeather: function () {
|
||||
fetchCurrentWeather () {
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchCurrentWeather method.`);
|
||||
},
|
||||
|
||||
// This method should start the API request to fetch the weather forecast.
|
||||
// This method should definitely be overwritten in the provider.
|
||||
fetchWeatherForecast: function () {
|
||||
fetchWeatherForecast () {
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherForecast method.`);
|
||||
},
|
||||
|
||||
// This method should start the API request to fetch the weather hourly.
|
||||
// This method should definitely be overwritten in the provider.
|
||||
fetchWeatherHourly: function () {
|
||||
fetchWeatherHourly () {
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherHourly method.`);
|
||||
},
|
||||
|
||||
// This returns a WeatherDay object for the current weather.
|
||||
currentWeather: function () {
|
||||
currentWeather () {
|
||||
return this.currentWeatherObject;
|
||||
},
|
||||
|
||||
// This returns an array of WeatherDay objects for the weather forecast.
|
||||
weatherForecast: function () {
|
||||
weatherForecast () {
|
||||
return this.weatherForecastArray;
|
||||
},
|
||||
|
||||
// This returns an object containing WeatherDay object(s) depending on the type of call.
|
||||
weatherHourly: function () {
|
||||
weatherHourly () {
|
||||
return this.weatherHourlyArray;
|
||||
},
|
||||
|
||||
// This returns the name of the fetched location or an empty string.
|
||||
fetchedLocation: function () {
|
||||
fetchedLocation () {
|
||||
return this.fetchedLocationName || "";
|
||||
},
|
||||
|
||||
// Set the currentWeather and notify the delegate that new information is available.
|
||||
setCurrentWeather: function (currentWeatherObject) {
|
||||
setCurrentWeather (currentWeatherObject) {
|
||||
// We should check here if we are passing a WeatherDay
|
||||
this.currentWeatherObject = currentWeatherObject;
|
||||
},
|
||||
|
||||
// Set the weatherForecastArray and notify the delegate that new information is available.
|
||||
setWeatherForecast: function (weatherForecastArray) {
|
||||
setWeatherForecast (weatherForecastArray) {
|
||||
// We should check here if we are passing a WeatherDay
|
||||
this.weatherForecastArray = weatherForecastArray;
|
||||
},
|
||||
|
||||
// Set the weatherHourlyArray and notify the delegate that new information is available.
|
||||
setWeatherHourly: function (weatherHourlyArray) {
|
||||
setWeatherHourly (weatherHourlyArray) {
|
||||
this.weatherHourlyArray = weatherHourlyArray;
|
||||
},
|
||||
|
||||
// Set the fetched location name.
|
||||
setFetchedLocation: function (name) {
|
||||
setFetchedLocation (name) {
|
||||
this.fetchedLocationName = name;
|
||||
},
|
||||
|
||||
// Notify the delegate that new weather is available.
|
||||
updateAvailable: function () {
|
||||
updateAvailable () {
|
||||
this.delegate.updateAvailable(this);
|
||||
},
|
||||
|
||||
@@ -119,7 +119,7 @@ const WeatherProvider = Class.extend({
|
||||
* @param {Array.<string>} expectedResponseHeaders the expected HTTP headers to recieve
|
||||
* @returns {Promise} resolved when the fetch is done
|
||||
*/
|
||||
fetchData: async function (url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) {
|
||||
async fetchData (url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) {
|
||||
const mockData = this.config.mockData;
|
||||
if (mockData) {
|
||||
const data = mockData.substring(1, mockData.length - 1);
|
||||
|
@@ -5,12 +5,13 @@
|
||||
* MIT Licensed.
|
||||
*/
|
||||
const WeatherUtils = {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
beaufortWindSpeed (speedInMS) {
|
||||
const windInKmh = this.convertWind(speedInMS, "kmh");
|
||||
const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
|
||||
for (const [index, speed] of speeds.entries()) {
|
||||
@@ -29,7 +30,7 @@ const WeatherUtils = {
|
||||
* @param {string} outputUnit - The unit system (imperial/metric) the return value should have.
|
||||
* @returns {string} - A string with tha value and a unit postfix.
|
||||
*/
|
||||
convertPrecipitationUnit(value, valueUnit, outputUnit) {
|
||||
convertPrecipitationUnit (value, valueUnit, outputUnit) {
|
||||
if (valueUnit === "%") return `${value.toFixed(0)} ${valueUnit}`;
|
||||
|
||||
let convertedValue = value;
|
||||
@@ -52,7 +53,7 @@ const WeatherUtils = {
|
||||
* @param {string} unit can be 'imperial' or 'metric'
|
||||
* @returns {number} the converted temperature
|
||||
*/
|
||||
convertTemp(tempInC, unit) {
|
||||
convertTemp (tempInC, unit) {
|
||||
return unit === "imperial" ? tempInC * 1.8 + 32 : tempInC;
|
||||
},
|
||||
|
||||
@@ -63,7 +64,7 @@ const WeatherUtils = {
|
||||
* or 'metric' (mps)
|
||||
* @returns {number} the converted windspeed
|
||||
*/
|
||||
convertWind(windInMS, unit) {
|
||||
convertWind (windInMS, unit) {
|
||||
switch (unit) {
|
||||
case "beaufort":
|
||||
return this.beaufortWindSpeed(windInMS);
|
||||
@@ -82,7 +83,7 @@ const WeatherUtils = {
|
||||
/*
|
||||
* Convert the wind direction cardinal to value
|
||||
*/
|
||||
convertWindDirection(windDirection) {
|
||||
convertWindDirection (windDirection) {
|
||||
const windCardinals = {
|
||||
N: 0,
|
||||
NNE: 22,
|
||||
@@ -105,15 +106,15 @@ const WeatherUtils = {
|
||||
return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
|
||||
},
|
||||
|
||||
convertWindToMetric(mph) {
|
||||
convertWindToMetric (mph) {
|
||||
return mph / 2.2369362920544;
|
||||
},
|
||||
|
||||
convertWindToMs(kmh) {
|
||||
convertWindToMs (kmh) {
|
||||
return kmh * 0.27777777777778;
|
||||
},
|
||||
|
||||
calculateFeelsLike(temperature, windSpeed, humidity) {
|
||||
calculateFeelsLike (temperature, windSpeed, humidity) {
|
||||
const windInMph = this.convertWind(windSpeed, "imperial");
|
||||
const tempInF = this.convertTemp(temperature, "imperial");
|
||||
let feelsLike = tempInF;
|
||||
@@ -121,16 +122,16 @@ const WeatherUtils = {
|
||||
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 && humidity > 40) {
|
||||
feelsLike =
|
||||
-42.379 +
|
||||
2.04901523 * tempInF +
|
||||
10.14333127 * humidity -
|
||||
0.22475541 * tempInF * humidity -
|
||||
6.83783 * Math.pow(10, -3) * tempInF * tempInF -
|
||||
5.481717 * Math.pow(10, -2) * humidity * humidity +
|
||||
1.22874 * Math.pow(10, -3) * tempInF * tempInF * humidity +
|
||||
8.5282 * Math.pow(10, -4) * tempInF * humidity * humidity -
|
||||
1.99 * Math.pow(10, -6) * tempInF * tempInF * humidity * humidity;
|
||||
feelsLike
|
||||
= -42.379
|
||||
+ 2.04901523 * tempInF
|
||||
+ 10.14333127 * humidity
|
||||
- 0.22475541 * tempInF * humidity
|
||||
- 6.83783 * Math.pow(10, -3) * tempInF * tempInF
|
||||
- 5.481717 * Math.pow(10, -2) * humidity * humidity
|
||||
+ 1.22874 * Math.pow(10, -3) * tempInF * tempInF * humidity
|
||||
+ 8.5282 * Math.pow(10, -4) * tempInF * humidity * humidity
|
||||
- 1.99 * Math.pow(10, -6) * tempInF * tempInF * humidity * humidity;
|
||||
}
|
||||
|
||||
return ((feelsLike - 32) * 5) / 9;
|
||||
|
Reference in New Issue
Block a user