/* global WeatherProvider, WeatherObject */ /* Magic Mirror * Module: Weather * Provider: Dark Sky * * By Nicholas Hubbard https://github.com/nhubbard * MIT Licensed * * This class is a provider for Dark Sky. * Note that the Dark Sky API does not provide rainfall. Instead it provides * snowfall and precipitation probability */ WeatherProvider.register("darksky", { // Set the name of the provider. // Not strictly required, but helps for debugging. providerName: "Dark Sky", // Set the default config properties that is specific to this provider defaults: { apiBase: "https://cors-anywhere.herokuapp.com/https://api.darksky.net", weatherEndpoint: "/forecast", apiKey: "", lat: 0, lon: 0 }, units: { imperial: "us", metric: "si" }, fetchCurrentWeather() { this.fetchData(this.getUrl()) .then((data) => { if (!data || !data.currently || typeof data.currently.temperature === "undefined") { // No usable data? return; } const currentWeather = this.generateWeatherDayFromCurrentWeather(data); this.setCurrentWeather(currentWeather); }) .catch(function (request) { Log.error("Could not load data ... ", request); }) .finally(() => this.updateAvailable()); }, fetchWeatherForecast() { this.fetchData(this.getUrl()) .then((data) => { if (!data || !data.daily || !data.daily.data.length) { // No usable data? return; } const forecast = this.generateWeatherObjectsFromForecast(data.daily.data); this.setWeatherForecast(forecast); }) .catch(function (request) { Log.error("Could not load data ... ", request); }) .finally(() => this.updateAvailable()); }, // Create a URL from the config and base URL. getUrl() { const units = this.units[this.config.units] || "auto"; return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=${units}&lang=${this.config.lang}`; }, // Implement WeatherDay generator. generateWeatherDayFromCurrentWeather(currentWeatherData) { const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); currentWeather.date = moment(); currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity); currentWeather.temperature = parseFloat(currentWeatherData.currently.temperature); currentWeather.windSpeed = parseFloat(currentWeatherData.currently.windSpeed); currentWeather.windDirection = currentWeatherData.currently.windBearing; currentWeather.weatherType = this.convertWeatherType(currentWeatherData.currently.icon); currentWeather.sunrise = moment(currentWeatherData.daily.data[0].sunriseTime, "X"); currentWeather.sunset = moment(currentWeatherData.daily.data[0].sunsetTime, "X"); return currentWeather; }, generateWeatherObjectsFromForecast(forecasts) { const days = []; for (const forecast of forecasts) { const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); weather.date = moment(forecast.time, "X"); weather.minTemperature = forecast.temperatureMin; weather.maxTemperature = forecast.temperatureMax; weather.weatherType = this.convertWeatherType(forecast.icon); weather.snow = 0; // The API will return centimeters if units is 'si' and will return inches for 'us' // Note that the Dark Sky API does not provide rainfall. // Instead it provides snowfall and precipitation probability if (forecast.hasOwnProperty("precipAccumulation")) { if (this.config.units === "imperial" && !isNaN(forecast.precipAccumulation)) { weather.snow = forecast.precipAccumulation; } else if (!isNaN(forecast.precipAccumulation)) { weather.snow = forecast.precipAccumulation * 10; } } weather.precipitation = weather.snow; days.push(weather); } return days; }, // Map icons from Dark Sky to our icons. convertWeatherType(weatherType) { const weatherTypes = { "clear-day": "day-sunny", "clear-night": "night-clear", rain: "rain", snow: "snow", sleet: "snow", wind: "wind", fog: "fog", cloudy: "cloudy", "partly-cloudy-day": "day-cloudy", "partly-cloudy-night": "night-cloudy" }; return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null; } });