mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-27 17:01:08 -04:00
Thanks to: @Developer-Incoming, @eltociear, @geraki, @khassel, @KristjanESPERANTO, @MagMar94, @mixasgr, @n8many, @OWL4C, @rejas, @savvadam, @sdetweil. > ⚠️ This release needs nodejs version `v22.14.0 or higher` ### Added - Add CSS support to the digital clock hour/minute/second through the use of the classes `clock-hour-digital`, `clock-minute-digital`, and `clock-second-digital`. - Add Arabic (#3719) and Esperanto translation. - Mark option `secondsColor` as deprecated in clock module. - Add Greek translation to Alerts module. - [newsfeed] Add specific ignoreOlderThan value (override) per feed (#3360) - [weather] Added option Humidity to hourly View - [weather] Added option to hide hourly entries that are Zero, hiding the entire column if empty. - [updatenotification] Added option to iterate over modules directory instead using modules defined in `config.js` (#3739) ### Changed - [core] starting clientonly now checks for needed env var `WAYLAND_DISPLAY` or `DISPLAY` and starts electron with needed parameters (if both are set wayland is used) (#3677) - [core] Optimize systeminformation calls and output (#3689) - [core] Add issue templates for feature requests and bug reports (#3695) - [core] Adapt `start:x11:dev` script - [weather/yr] The Yr weather provider now enforces a minimum `updateInterval` of 600 000 ms (10 minutes) to comply with the terms of service. If a lower value is set, it will be automatically increased to this minimum. - [weather/weatherflow] Fixed icons and added hourly support as well as UV, precipitation, and location name support. - [workflow] Run `sudo apt-get update` before installing packages to avoid install errors - [workflow] Exclude issues with label `ready (coming with next release)` from stale job ### Removed ### Updated - [core] Update requirements and dependencies including electron to v35 and formatting (#3593, #3693, #3717) - [core] Update prettier, ESLint and simplify config - Update Greek translation ### Fixed - [calendar] Fix clipping events being broadcast (#3678) - [tests] Fix Electron tests by running them under new github image ubuntu-24.04, replace xserver with labwc, running under xserver and labwc depending on env variable WAYLAND_DISPLAY is set (#3676) - [calendar] Fix arrayed symbols, #3267, again, add testcase, add testcase for #3678 - [weather] Fix wrong weatherCondition name in openmeteo provider which lead to n/a icon (#3691) - [core] Fix wrong port in log message when starting server only (#3696) - [calendar] Fix NewYork event processed on system in Central timezone shows wrong time #3701 - [weather/yr] The Yr weather provider is now able to recover from bad API responses instead of freezing (#3296) - [compliments] Fix evening events being shown during the day (#3727) - [weather] Fixed minor spacing issues when using UV Index in Hourly - [workflow] Fix command to run spellcheck --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Michael Teeuw <michael@xonaymedia.nl> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Ross Younger <crazyscot@gmail.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: jkriegshauser <joshuakr@nvidia.com> Co-authored-by: illimarkangur <116028111+illimarkangur@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: vppencilsharpener <tim.pray@gmail.com> Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com> Co-authored-by: Brian O'Connor <btoconnor@users.noreply.github.com> Co-authored-by: WallysWellies <59727507+WallysWellies@users.noreply.github.com> Co-authored-by: Jason Stieber <jrstieber@gmail.com> Co-authored-by: jargordon <50050429+jargordon@users.noreply.github.com> Co-authored-by: Daniel <32464403+dkallen78@users.noreply.github.com> Co-authored-by: Ryan Williams <65094007+ryan-d-williams@users.noreply.github.com> Co-authored-by: Panagiotis Skias <panagiotis.skias@gmail.com> Co-authored-by: Marc Landis <dirk.rettschlag@gmail.com> Co-authored-by: HeikoGr <20295490+HeikoGr@users.noreply.github.com> Co-authored-by: Pedro Lamas <pedrolamas@gmail.com> Co-authored-by: veeck <gitkraken@veeck.de> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com> Co-authored-by: DevIncomin <56730075+Developer-Incoming@users.noreply.github.com> Co-authored-by: Nathan <n8nyoung@gmail.com> Co-authored-by: mixasgr <mixasgr@users.noreply.github.com> Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr> Co-authored-by: Konstantinos <geraki@gmail.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com>
545 lines
19 KiB
JavaScript
545 lines
19 KiB
JavaScript
/* global WeatherProvider, WeatherObject */
|
|
|
|
/*
|
|
* This class is a provider for Open-Meteo,
|
|
* see https://open-meteo.com/
|
|
*/
|
|
|
|
// https://www.bigdatacloud.com/docs/api/free-reverse-geocode-to-city-api
|
|
const GEOCODE_BASE = "https://api.bigdatacloud.net/data/reverse-geocode-client";
|
|
const OPEN_METEO_BASE = "https://api.open-meteo.com/v1";
|
|
|
|
WeatherProvider.register("openmeteo", {
|
|
|
|
/*
|
|
* Set the name of the provider.
|
|
* Not strictly required, but helps for debugging.
|
|
*/
|
|
providerName: "Open-Meteo",
|
|
|
|
// Set the default config properties that is specific to this provider
|
|
defaults: {
|
|
apiBase: OPEN_METEO_BASE,
|
|
lat: 0,
|
|
lon: 0,
|
|
pastDays: 0,
|
|
type: "current"
|
|
},
|
|
|
|
// https://open-meteo.com/en/docs
|
|
hourlyParams: [
|
|
// Air temperature at 2 meters above ground
|
|
"temperature_2m",
|
|
// Relative humidity at 2 meters above ground
|
|
"relativehumidity_2m",
|
|
// Dew point temperature at 2 meters above ground
|
|
"dewpoint_2m",
|
|
// Apparent temperature is the perceived feels-like temperature combining wind chill factor, relative humidity and solar radiation
|
|
"apparent_temperature",
|
|
// Atmospheric air pressure reduced to mean sea level (msl) or pressure at surface. Typically pressure on mean sea level is used in meteorology. Surface pressure gets lower with increasing elevation.
|
|
"pressure_msl",
|
|
"surface_pressure",
|
|
// Total cloud cover as an area fraction
|
|
"cloudcover",
|
|
// Low level clouds and fog up to 3 km altitude
|
|
"cloudcover_low",
|
|
// Mid level clouds from 3 to 8 km altitude
|
|
"cloudcover_mid",
|
|
// High level clouds from 8 km altitude
|
|
"cloudcover_high",
|
|
// Wind speed at 10, 80, 120 or 180 meters above ground. Wind speed on 10 meters is the standard level.
|
|
"windspeed_10m",
|
|
"windspeed_80m",
|
|
"windspeed_120m",
|
|
"windspeed_180m",
|
|
// Wind direction at 10, 80, 120 or 180 meters above ground
|
|
"winddirection_10m",
|
|
"winddirection_80m",
|
|
"winddirection_120m",
|
|
"winddirection_180m",
|
|
// Gusts at 10 meters above ground as a maximum of the preceding hour
|
|
"windgusts_10m",
|
|
// Shortwave solar radiation as average of the preceding hour. This is equal to the total global horizontal irradiation
|
|
"shortwave_radiation",
|
|
// Direct solar radiation as average of the preceding hour on the horizontal plane and the normal plane (perpendicular to the sun)
|
|
"direct_radiation",
|
|
"direct_normal_irradiance",
|
|
// Diffuse solar radiation as average of the preceding hour
|
|
"diffuse_radiation",
|
|
// Vapor Pressure Deificit (VPD) in kilopascal (kPa). For high VPD (>1.6), water transpiration of plants increases. For low VPD (<0.4), transpiration decreases
|
|
"vapor_pressure_deficit",
|
|
// Evapotranspration from land surface and plants that weather models assumes for this location. Available soil water is considered. 1 mm evapotranspiration per hour equals 1 liter of water per spare meter.
|
|
"evapotranspiration",
|
|
// ET₀ Reference Evapotranspiration of a well watered grass field. Based on FAO-56 Penman-Monteith equations ET₀ is calculated from temperature, wind speed, humidity and solar radiation. Unlimited soil water is assumed. ET₀ is commonly used to estimate the required irrigation for plants.
|
|
"et0_fao_evapotranspiration",
|
|
// Total precipitation (rain, showers, snow) sum of the preceding hour
|
|
"precipitation",
|
|
// Precipitation Probability
|
|
"precipitation_probability",
|
|
// UV index
|
|
"uv_index",
|
|
// Snowfall amount of the preceding hour in centimeters. For the water equivalent in millimeter, divide by 7. E.g. 7 cm snow = 10 mm precipitation water equivalent
|
|
"snowfall",
|
|
// Rain from large scale weather systems of the preceding hour in millimeter
|
|
"rain",
|
|
// Showers from convective precipitation in millimeters from the preceding hour
|
|
"showers",
|
|
// Weather condition as a numeric code. Follow WMO weather interpretation codes.
|
|
"weathercode",
|
|
// Snow depth on the ground
|
|
"snow_depth",
|
|
// Altitude above sea level of the 0°C level
|
|
"freezinglevel_height",
|
|
// Temperature in the soil at 0, 6, 18 and 54 cm depths. 0 cm is the surface temperature on land or water surface temperature on water.
|
|
"soil_temperature_0cm",
|
|
"soil_temperature_6cm",
|
|
"soil_temperature_18cm",
|
|
"soil_temperature_54cm",
|
|
// Average soil water content as volumetric mixing ratio at 0-1, 1-3, 3-9, 9-27 and 27-81 cm depths.
|
|
"soil_moisture_0_1cm",
|
|
"soil_moisture_1_3cm",
|
|
"soil_moisture_3_9cm",
|
|
"soil_moisture_9_27cm",
|
|
"soil_moisture_27_81cm"
|
|
],
|
|
|
|
dailyParams: [
|
|
// Maximum and minimum daily air temperature at 2 meters above ground
|
|
"temperature_2m_max",
|
|
"temperature_2m_min",
|
|
// Maximum and minimum daily apparent temperature
|
|
"apparent_temperature_min",
|
|
"apparent_temperature_max",
|
|
// Sum of daily precipitation (including rain, showers and snowfall)
|
|
"precipitation_sum",
|
|
// Sum of daily rain
|
|
"rain_sum",
|
|
// Sum of daily showers
|
|
"showers_sum",
|
|
// Sum of daily snowfall
|
|
"snowfall_sum",
|
|
// The number of hours with rain
|
|
"precipitation_hours",
|
|
// The most severe weather condition on a given day
|
|
"weathercode",
|
|
// Sun rise and set times
|
|
"sunrise",
|
|
"sunset",
|
|
// Maximum wind speed and gusts on a day
|
|
"windspeed_10m_max",
|
|
"windgusts_10m_max",
|
|
// Dominant wind direction
|
|
"winddirection_10m_dominant",
|
|
// The sum of solar radiation on a given day in Megajoules
|
|
"shortwave_radiation_sum",
|
|
//UV Index
|
|
"uv_index_max",
|
|
// Daily sum of ET₀ Reference Evapotranspiration of a well watered grass field
|
|
"et0_fao_evapotranspiration"
|
|
],
|
|
|
|
fetchedLocation () {
|
|
return this.fetchedLocationName || "";
|
|
},
|
|
|
|
fetchCurrentWeather () {
|
|
this.fetchData(this.getUrl())
|
|
.then((data) => this.parseWeatherApiResponse(data))
|
|
.then((parsedData) => {
|
|
if (!parsedData) {
|
|
// No usable data?
|
|
return;
|
|
}
|
|
|
|
const currentWeather = this.generateWeatherDayFromCurrentWeather(parsedData);
|
|
this.setCurrentWeather(currentWeather);
|
|
})
|
|
.catch(function (request) {
|
|
Log.error("Could not load data ... ", request);
|
|
})
|
|
.finally(() => this.updateAvailable());
|
|
},
|
|
|
|
fetchWeatherForecast () {
|
|
this.fetchData(this.getUrl())
|
|
.then((data) => this.parseWeatherApiResponse(data))
|
|
.then((parsedData) => {
|
|
if (!parsedData) {
|
|
// No usable data?
|
|
return;
|
|
}
|
|
|
|
const dailyForecast = this.generateWeatherObjectsFromForecast(parsedData);
|
|
this.setWeatherForecast(dailyForecast);
|
|
})
|
|
.catch(function (request) {
|
|
Log.error("Could not load data ... ", request);
|
|
})
|
|
.finally(() => this.updateAvailable());
|
|
},
|
|
|
|
fetchWeatherHourly () {
|
|
this.fetchData(this.getUrl())
|
|
.then((data) => this.parseWeatherApiResponse(data))
|
|
.then((parsedData) => {
|
|
if (!parsedData) {
|
|
// No usable data?
|
|
return;
|
|
}
|
|
|
|
const hourlyForecast = this.generateWeatherObjectsFromHourly(parsedData);
|
|
this.setWeatherHourly(hourlyForecast);
|
|
})
|
|
.catch(function (request) {
|
|
Log.error("Could not load data ... ", request);
|
|
})
|
|
.finally(() => this.updateAvailable());
|
|
},
|
|
|
|
/**
|
|
* Overrides method for setting config to check if endpoint is correct for hourly
|
|
* @param {object} config The configuration object
|
|
*/
|
|
setConfig (config) {
|
|
this.config = {
|
|
lang: config.lang ?? "en",
|
|
...this.defaults,
|
|
...config
|
|
};
|
|
|
|
// Set properly maxNumberOfDays and max Entries properties according to config and value ranges allowed in the documentation
|
|
const maxEntriesLimit = ["daily", "forecast"].includes(this.config.type) ? 7 : this.config.type === "hourly" ? 48 : 0;
|
|
if (this.config.hasOwnProperty("maxNumberOfDays") && !isNaN(parseFloat(this.config.maxNumberOfDays))) {
|
|
const daysFactor = ["daily", "forecast"].includes(this.config.type) ? 1 : this.config.type === "hourly" ? 24 : 0;
|
|
this.config.maxEntries = Math.max(1, Math.min(Math.round(parseFloat(this.config.maxNumberOfDays)) * daysFactor, maxEntriesLimit));
|
|
this.config.maxNumberOfDays = Math.ceil(this.config.maxEntries / Math.max(1, daysFactor));
|
|
}
|
|
this.config.maxEntries = Math.max(1, Math.min(this.config.maxEntries, maxEntriesLimit));
|
|
|
|
if (!this.config.type) {
|
|
Log.error("type not configured and could not resolve it");
|
|
}
|
|
|
|
this.fetchLocation();
|
|
},
|
|
|
|
// Generate valid query params to perform the request
|
|
getQueryParameters () {
|
|
let params = {
|
|
latitude: this.config.lat,
|
|
longitude: this.config.lon,
|
|
timeformat: "unixtime",
|
|
timezone: "auto",
|
|
past_days: this.config.pastDays ?? 0,
|
|
daily: this.dailyParams,
|
|
hourly: this.hourlyParams,
|
|
// Fixed units as metric
|
|
temperature_unit: "celsius",
|
|
windspeed_unit: "ms",
|
|
precipitation_unit: "mm"
|
|
};
|
|
|
|
const startDate = moment().startOf("day");
|
|
const endDate = moment(startDate)
|
|
.add(Math.max(0, Math.min(7, this.config.maxNumberOfDays)), "days")
|
|
.endOf("day");
|
|
|
|
params.start_date = startDate.format("YYYY-MM-DD");
|
|
|
|
switch (this.config.type) {
|
|
case "hourly":
|
|
case "daily":
|
|
case "forecast":
|
|
params.end_date = endDate.format("YYYY-MM-DD");
|
|
break;
|
|
case "current":
|
|
params.current_weather = true;
|
|
params.end_date = params.start_date;
|
|
break;
|
|
default:
|
|
// Failsafe
|
|
return "";
|
|
}
|
|
|
|
return Object.keys(params)
|
|
.filter((key) => (!!params[key]))
|
|
.map((key) => {
|
|
switch (key) {
|
|
case "hourly":
|
|
case "daily":
|
|
return `${encodeURIComponent(key)}=${params[key].join(",")}`;
|
|
default:
|
|
return `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`;
|
|
}
|
|
})
|
|
.join("&");
|
|
},
|
|
|
|
// Create a URL from the config and base URL.
|
|
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]
|
|
};
|
|
}, {}));
|
|
},
|
|
|
|
// Sanitize and validate API response
|
|
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,
|
|
daily: data.daily && data.daily.time && Array.isArray(data.daily.time) && data.daily.time.length > 0
|
|
};
|
|
// backwards compatibility
|
|
const type = ["daily", "forecast"].includes(this.config.type) ? "daily" : this.config.type;
|
|
|
|
if (!validByType[type]) return;
|
|
|
|
switch (type) {
|
|
case "current":
|
|
if (!validByType.daily && !validByType.hourly) {
|
|
return;
|
|
}
|
|
break;
|
|
case "hourly":
|
|
case "daily":
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
for (const key of ["hourly", "daily"]) {
|
|
if (typeof data[key] === "object") {
|
|
data[key] = this.transposeDataMatrix(data[key]);
|
|
}
|
|
}
|
|
|
|
if (data.current_weather) {
|
|
data.current_weather.time = moment.unix(data.current_weather.time);
|
|
}
|
|
|
|
return data;
|
|
},
|
|
|
|
// Reverse geocoding from latitude and longitude provided
|
|
fetchLocation () {
|
|
this.fetchData(`${GEOCODE_BASE}?latitude=${this.config.lat}&longitude=${this.config.lon}&localityLanguage=${this.config.lang}`)
|
|
.then((data) => {
|
|
if (!data || !data.city) {
|
|
// No usable data?
|
|
return;
|
|
}
|
|
this.fetchedLocationName = `${data.city}, ${data.principalSubdivisionCode}`;
|
|
})
|
|
.catch((request) => {
|
|
Log.error("Could not load data ... ", request);
|
|
});
|
|
},
|
|
|
|
// Implement WeatherDay generator.
|
|
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.
|
|
* For the current weather case, the response have the following structure (after transposing):
|
|
* ```
|
|
* {
|
|
* current_weather: { ...<some current weather here> },
|
|
* hourly: [
|
|
* 0: {...<data for hour zero here> },
|
|
* 1: {...<data for hour one here> },
|
|
* ...
|
|
* ],
|
|
* daily: [
|
|
* {...<summary data for current day here> },
|
|
* ]
|
|
* }
|
|
* ```
|
|
* Some data should be returned from `hourly` array data when the index matches the current hour,
|
|
* some data from the first and only one object received in `daily` array and some from the
|
|
* `current_weather` object.
|
|
*/
|
|
const h = moment().hour();
|
|
const currentWeather = new WeatherObject();
|
|
|
|
currentWeather.date = weather.current_weather.time;
|
|
currentWeather.windSpeed = weather.current_weather.windspeed;
|
|
currentWeather.windFromDirection = weather.current_weather.winddirection;
|
|
currentWeather.sunrise = weather.daily[0].sunrise;
|
|
currentWeather.sunset = weather.daily[0].sunset;
|
|
currentWeather.temperature = parseFloat(weather.current_weather.temperature);
|
|
currentWeather.minTemperature = parseFloat(weather.daily[0].temperature_2m_min);
|
|
currentWeather.maxTemperature = parseFloat(weather.daily[0].temperature_2m_max);
|
|
currentWeather.weatherType = this.convertWeatherType(weather.current_weather.weathercode, currentWeather.isDayTime());
|
|
currentWeather.humidity = parseFloat(weather.hourly[h].relativehumidity_2m);
|
|
currentWeather.rain = parseFloat(weather.hourly[h].rain);
|
|
currentWeather.snow = parseFloat(weather.hourly[h].snowfall * 10);
|
|
currentWeather.precipitationAmount = parseFloat(weather.hourly[h].precipitation);
|
|
currentWeather.precipitationProbability = parseFloat(weather.hourly[h].precipitation_probability);
|
|
currentWeather.uv_index = parseFloat(weather.hourly[h].uv_index);
|
|
|
|
return currentWeather;
|
|
},
|
|
|
|
// Implement WeatherForecast generator.
|
|
generateWeatherObjectsFromForecast (weathers) {
|
|
const days = [];
|
|
|
|
weathers.daily.forEach((weather) => {
|
|
const currentWeather = new WeatherObject();
|
|
|
|
currentWeather.date = weather.time;
|
|
currentWeather.windSpeed = weather.windspeed_10m_max;
|
|
currentWeather.windFromDirection = weather.winddirection_10m_dominant;
|
|
currentWeather.sunrise = weather.sunrise;
|
|
currentWeather.sunset = weather.sunset;
|
|
currentWeather.temperature = parseFloat((weather.temperature_2m_max + weather.temperature_2m_min) / 2);
|
|
currentWeather.minTemperature = parseFloat(weather.temperature_2m_min);
|
|
currentWeather.maxTemperature = parseFloat(weather.temperature_2m_max);
|
|
currentWeather.weatherType = this.convertWeatherType(weather.weathercode, true);
|
|
currentWeather.rain = parseFloat(weather.rain_sum);
|
|
currentWeather.snow = parseFloat(weather.snowfall_sum * 10);
|
|
currentWeather.precipitationAmount = parseFloat(weather.precipitation_sum);
|
|
currentWeather.precipitationProbability = parseFloat(weather.precipitation_hours * 100 / 24);
|
|
currentWeather.uv_index = parseFloat(weather.uv_index_max);
|
|
|
|
days.push(currentWeather);
|
|
});
|
|
|
|
return days;
|
|
},
|
|
|
|
// Implement WeatherHourly generator.
|
|
generateWeatherObjectsFromHourly (weathers) {
|
|
const hours = [];
|
|
const now = moment();
|
|
|
|
weathers.hourly.forEach((weather, i) => {
|
|
if ((hours.length === 0 && weather.time <= now) || hours.length >= this.config.maxEntries) {
|
|
return;
|
|
}
|
|
|
|
const currentWeather = new WeatherObject();
|
|
const h = Math.ceil((i + 1) / 24) - 1;
|
|
|
|
currentWeather.date = weather.time;
|
|
currentWeather.windSpeed = weather.windspeed_10m;
|
|
currentWeather.windFromDirection = weather.winddirection_10m;
|
|
currentWeather.sunrise = weathers.daily[h].sunrise;
|
|
currentWeather.sunset = weathers.daily[h].sunset;
|
|
currentWeather.temperature = parseFloat(weather.temperature_2m);
|
|
currentWeather.minTemperature = parseFloat(weathers.daily[h].temperature_2m_min);
|
|
currentWeather.maxTemperature = parseFloat(weathers.daily[h].temperature_2m_max);
|
|
currentWeather.weatherType = this.convertWeatherType(weather.weathercode, currentWeather.isDayTime());
|
|
currentWeather.humidity = parseFloat(weather.relativehumidity_2m);
|
|
currentWeather.rain = parseFloat(weather.rain);
|
|
currentWeather.snow = parseFloat(weather.snowfall * 10);
|
|
currentWeather.precipitationAmount = parseFloat(weather.precipitation);
|
|
currentWeather.precipitationProbability = parseFloat(weather.precipitation_probability);
|
|
currentWeather.uv_index = parseFloat(weather.uv_index);
|
|
|
|
hours.push(currentWeather);
|
|
});
|
|
|
|
return hours;
|
|
},
|
|
|
|
// Map icons from Dark Sky to our icons.
|
|
convertWeatherType (weathercode, isDayTime) {
|
|
const weatherConditions = {
|
|
0: "clear",
|
|
1: "mainly-clear",
|
|
2: "partly-cloudy",
|
|
3: "overcast",
|
|
45: "fog",
|
|
48: "depositing-rime-fog",
|
|
51: "drizzle-light-intensity",
|
|
53: "drizzle-moderate-intensity",
|
|
55: "drizzle-dense-intensity",
|
|
56: "freezing-drizzle-light-intensity",
|
|
57: "freezing-drizzle-dense-intensity",
|
|
61: "rain-slight-intensity",
|
|
63: "rain-moderate-intensity",
|
|
65: "rain-heavy-intensity",
|
|
66: "freezing-rain-light-intensity",
|
|
67: "freezing-rain-heavy-intensity",
|
|
71: "snow-fall-slight-intensity",
|
|
73: "snow-fall-moderate-intensity",
|
|
75: "snow-fall-heavy-intensity",
|
|
77: "snow-grains",
|
|
80: "rain-showers-slight",
|
|
81: "rain-showers-moderate",
|
|
82: "rain-showers-violent",
|
|
85: "snow-showers-slight",
|
|
86: "snow-showers-heavy",
|
|
95: "thunderstorm",
|
|
96: "thunderstorm-slight-hail",
|
|
99: "thunderstorm-heavy-hail"
|
|
};
|
|
|
|
if (!Object.keys(weatherConditions).includes(`${weathercode}`)) return null;
|
|
|
|
switch (weatherConditions[`${weathercode}`]) {
|
|
case "clear":
|
|
return isDayTime ? "day-sunny" : "night-clear";
|
|
case "mainly-clear":
|
|
case "partly-cloudy":
|
|
return isDayTime ? "day-cloudy" : "night-alt-cloudy";
|
|
case "overcast":
|
|
return isDayTime ? "day-sunny-overcast" : "night-alt-partly-cloudy";
|
|
case "fog":
|
|
case "depositing-rime-fog":
|
|
return isDayTime ? "day-fog" : "night-fog";
|
|
case "drizzle-light-intensity":
|
|
case "rain-slight-intensity":
|
|
case "rain-showers-slight":
|
|
return isDayTime ? "day-sprinkle" : "night-sprinkle";
|
|
case "drizzle-moderate-intensity":
|
|
case "rain-moderate-intensity":
|
|
case "rain-showers-moderate":
|
|
return isDayTime ? "day-showers" : "night-showers";
|
|
case "drizzle-dense-intensity":
|
|
case "rain-heavy-intensity":
|
|
case "rain-showers-violent":
|
|
return isDayTime ? "day-thunderstorm" : "night-thunderstorm";
|
|
case "freezing-rain-light-intensity":
|
|
return isDayTime ? "day-rain-mix" : "night-rain-mix";
|
|
case "freezing-drizzle-light-intensity":
|
|
case "freezing-drizzle-dense-intensity":
|
|
return "snowflake-cold";
|
|
case "snow-grains":
|
|
return isDayTime ? "day-sleet" : "night-sleet";
|
|
case "snow-fall-slight-intensity":
|
|
case "snow-fall-moderate-intensity":
|
|
return isDayTime ? "day-snow-wind" : "night-snow-wind";
|
|
case "snow-fall-heavy-intensity":
|
|
case "freezing-rain-heavy-intensity":
|
|
return isDayTime ? "day-snow-thunderstorm" : "night-snow-thunderstorm";
|
|
case "snow-showers-slight":
|
|
case "snow-showers-heavy":
|
|
return isDayTime ? "day-rain-mix" : "night-rain-mix";
|
|
case "thunderstorm":
|
|
return isDayTime ? "day-thunderstorm" : "night-thunderstorm";
|
|
case "thunderstorm-slight-hail":
|
|
return isDayTime ? "day-sleet" : "night-sleet";
|
|
case "thunderstorm-heavy-hail":
|
|
return isDayTime ? "day-sleet-storm" : "night-sleet-storm";
|
|
default:
|
|
return "na";
|
|
}
|
|
},
|
|
|
|
// Define required scripts.
|
|
getScripts () {
|
|
return ["moment.js"];
|
|
}
|
|
});
|