mirror of
				https://github.com/MichMich/MagicMirror.git
				synced 2025-11-04 05:15:42 +00:00 
			
		
		
		
	Adding new weather provider for weather.gov
This commit is contained in:
		@@ -50,6 +50,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 | 
			
		||||
- Added fade, fadePoint and maxNumberOfDays properties to the forecast mode [#1516](https://github.com/MichMich/MagicMirror/issues/1516)
 | 
			
		||||
- Fixed Loading string and decimalSymbol string replace [#1538](https://github.com/MichMich/MagicMirror/issues/1538)
 | 
			
		||||
- Show Snow amounts in new weather module [#1545](https://github.com/MichMich/MagicMirror/issues/1545)
 | 
			
		||||
- Added weather.gov as a new weather provider for US locations
 | 
			
		||||
 | 
			
		||||
## [2.6.0] - 2019-01-01
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@ The following properties can be configured:
 | 
			
		||||
| ---------------------------- | -----------
 | 
			
		||||
| `apiVersion`                 | The OpenWeatherMap API version to use. <br><br> **Default value:**  `2.5`
 | 
			
		||||
| `apiBase`                    | The OpenWeatherMap base URL. <br><br> **Default value:**  `'http://api.openweathermap.org/data/'`
 | 
			
		||||
| `weatherEndpoint`	       | The OpenWeatherMap API endPoint. <br><br> **Possible values:** `/weather`, `/forecast` (free users) or `/forecast/daily` (paying users or old apiKey only) <br> **Default value:**  `'/weather'`
 | 
			
		||||
| `weatherEndpoint`	           | The OpenWeatherMap API endPoint. <br><br> **Possible values:** `/weather`, `/forecast` (free users) or `/forecast/daily` (paying users or old apiKey only) <br> **Default value:**  `'/weather'`
 | 
			
		||||
| `locationID`                 | Location ID from [OpenWeatherMap](https://openweathermap.org/find) **This will override anything you put in location.** <br> Leave blank if you want to use location. <br> **Example:** `1234567` <br> **Default value:** `false` <br><br> **Note:** When the `location` and `locationID` are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used.
 | 
			
		||||
| `location`                   | The location used for weather information. <br><br> **Example:** `'Amsterdam,Netherlands'` <br> **Default value:** `false` <br><br> **Note:** When the `location` and `locationID` are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used.
 | 
			
		||||
| `apiKey`                     | The [OpenWeatherMap](https://home.openweathermap.org) API key, which can be obtained by creating an OpenWeatherMap account. <br><br>  This value is **REQUIRED**
 | 
			
		||||
@@ -91,11 +91,20 @@ The following properties can be configured:
 | 
			
		||||
| Option                       | Description
 | 
			
		||||
| ---------------------------- | -----------
 | 
			
		||||
| `apiBase`                    | The DarkSky base URL. The darksky api has disabled [cors](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), therefore a proxy is required. <br><br> **Possible value:**  `'https://cors-anywhere.herokuapp.com/https://api.darksky.net'` <br>  This value is **REQUIRED**
 | 
			
		||||
| `weatherEndpoint`	       | The DarkSky API endPoint. <br><br> **Possible values:** `/forecast` <br>  This value is **REQUIRED**
 | 
			
		||||
| `weatherEndpoint`	           | The DarkSky API endPoint. <br><br> **Possible values:** `/forecast` <br>  This value is **REQUIRED**
 | 
			
		||||
| `apiKey`                     | The [DarkSky](https://darksky.net/dev/register) API key, which can be obtained by creating an DarkSky account. <br><br>  This value is **REQUIRED**
 | 
			
		||||
| `lat`                        | The geo coordinate latitude. <br><br>  This value is **REQUIRED**
 | 
			
		||||
| `lon`                        | The geo coordinate longitude. <br><br>  This value is **REQUIRED**
 | 
			
		||||
 | 
			
		||||
### Weather.gov options
 | 
			
		||||
 | 
			
		||||
| Option                       | Description
 | 
			
		||||
| ---------------------------- | -----------
 | 
			
		||||
| `apiBase`                    | The weather.gov base URL. <br><br> **Possible value:**  `'https://api.weather.gov/points/'` <br>  This value is **REQUIRED**
 | 
			
		||||
| `weatherEndpoint`	           | The weather.gov API endPoint. <br><br> **Possible values:** `/forecast` for forecast and `/forecast/hourly` for current. <br>  This value is **REQUIRED**
 | 
			
		||||
| `lat`                        | The geo coordinate latitude. <br><br>  This value is **REQUIRED**
 | 
			
		||||
| `lon`                        | The geo coordinate longitude. <br><br>  This value is **REQUIRED**
 | 
			
		||||
 | 
			
		||||
## API Provider Development
 | 
			
		||||
 | 
			
		||||
If you want to add another API provider checkout the [Guide](providers).
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										268
									
								
								modules/default/weather/providers/weathergov.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								modules/default/weather/providers/weathergov.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,268 @@
 | 
			
		||||
/* global WeatherProvider, WeatherObject */
 | 
			
		||||
 | 
			
		||||
/* Magic Mirror
 | 
			
		||||
 * Module: Weather
 | 
			
		||||
 * Provider: weather.gov
 | 
			
		||||
 *
 | 
			
		||||
 * By Vince Peri
 | 
			
		||||
 * MIT Licensed.
 | 
			
		||||
 *
 | 
			
		||||
 * This class is a provider for weather.gov.
 | 
			
		||||
 * Note that this is only for US locations (lat and lon) and does not require an API key
 | 
			
		||||
 * Since it is free, there are some items missing - like sunrise, sunset, humidity, etc.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
WeatherProvider.register("weathergov", {
 | 
			
		||||
 | 
			
		||||
	// Set the name of the provider.
 | 
			
		||||
	// This isn't strictly necessary, since it will fallback to the provider identifier
 | 
			
		||||
	// But for debugging (and future alerts) it would be nice to have the real name.
 | 
			
		||||
	providerName: "Weather.gov",
 | 
			
		||||
 | 
			
		||||
	// Overwrite the fetchCurrentWeather method.
 | 
			
		||||
	fetchCurrentWeather() {
 | 
			
		||||
		this.fetchData(this.getUrl())
 | 
			
		||||
			.then(data => {
 | 
			
		||||
				if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) {
 | 
			
		||||
					// Did not receive usable new data.
 | 
			
		||||
					// Maybe this needs a better check?
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				//this.setFetchedLocation(`${data.name}, ${data.sys.country}`);
 | 
			
		||||
 | 
			
		||||
				const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties.periods[0]);
 | 
			
		||||
				this.setCurrentWeather(currentWeather);
 | 
			
		||||
			})
 | 
			
		||||
			.catch(function(request) {
 | 
			
		||||
				Log.error("Could not load data ... ", request);
 | 
			
		||||
			})
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	// Overwrite the fetchCurrentWeather method.
 | 
			
		||||
	fetchWeatherForecast() {
 | 
			
		||||
		this.fetchData(this.getUrl())
 | 
			
		||||
			.then(data => {
 | 
			
		||||
				if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) {
 | 
			
		||||
					// Did not receive usable new data.
 | 
			
		||||
					// Maybe this needs a better check?
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				//this.setFetchedLocation(`${data.city.name}, ${data.city.country}`);
 | 
			
		||||
 | 
			
		||||
				const forecast = this.generateWeatherObjectsFromForecast(data.properties.periods);
 | 
			
		||||
				this.setWeatherForecast(forecast);
 | 
			
		||||
			})
 | 
			
		||||
			.catch(function(request) {
 | 
			
		||||
				Log.error("Could not load data ... ", request);
 | 
			
		||||
			})
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/** Weather.gov Specific Methods - These are not part of the default provider methods */
 | 
			
		||||
	/*
 | 
			
		||||
	 * Gets the complete url for the request
 | 
			
		||||
	 */
 | 
			
		||||
	getUrl() {
 | 
			
		||||
		return this.config.apiBase + this.config.lat + "," + this.config.lon + this.config.weatherEndpoint;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Generate a WeatherObject based on currentWeatherInformation
 | 
			
		||||
	 */
 | 
			
		||||
	generateWeatherObjectFromCurrentWeather(currentWeatherData) {
 | 
			
		||||
		const currentWeather = new WeatherObject(this.config.units);
 | 
			
		||||
 | 
			
		||||
		//currentWeather.humidity = currentWeatherData.main.humidity;
 | 
			
		||||
		currentWeather.temperature = currentWeatherData.temperature;
 | 
			
		||||
		currentWeather.windSpeed = currentWeatherData.windSpeed.split(" ", 1);
 | 
			
		||||
		currentWeather.windDirection = this.convertDirectiontoDegrees(currentWeatherData.windDirection);
 | 
			
		||||
		currentWeather.weatherType = this.convertWeatherType(currentWeatherData.shortForecast, currentWeatherData.isDaytime);
 | 
			
		||||
		//currentWeather.sunrise = moment(currentWeatherData.sys.sunrise, "X");
 | 
			
		||||
		//currentWeather.sunset = moment(currentWeatherData.sys.sunset, "X");
 | 
			
		||||
 | 
			
		||||
		return currentWeather;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Generate WeatherObjects based on forecast information
 | 
			
		||||
	 */
 | 
			
		||||
	generateWeatherObjectsFromForecast(forecasts) {
 | 
			
		||||
		return this.fetchForecastDaily(forecasts);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * fetch forecast information for daily forecast.
 | 
			
		||||
	 */
 | 
			
		||||
	fetchForecastDaily(forecasts) {
 | 
			
		||||
		// initial variable declaration
 | 
			
		||||
		const days = [];
 | 
			
		||||
		// variables for temperature range and rain
 | 
			
		||||
		var minTemp = [];
 | 
			
		||||
		var maxTemp = [];
 | 
			
		||||
		// variable for date
 | 
			
		||||
		let date = "";
 | 
			
		||||
		var weather = new WeatherObject(this.config.units);
 | 
			
		||||
		weather.precipitation = 0;
 | 
			
		||||
 | 
			
		||||
		for (const forecast of forecasts) {
 | 
			
		||||
 | 
			
		||||
			if (date !== moment(forecast.startTime).format("YYYY-MM-DD")) {
 | 
			
		||||
 | 
			
		||||
				// calculate minimum/maximum temperature, specify rain amount
 | 
			
		||||
				weather.minTemperature = Math.min.apply(null, minTemp);
 | 
			
		||||
				weather.maxTemperature = Math.max.apply(null, maxTemp);
 | 
			
		||||
 | 
			
		||||
				// push weather information to days array
 | 
			
		||||
				days.push(weather);
 | 
			
		||||
				// create new weather-object
 | 
			
		||||
				weather = new WeatherObject(this.config.units);
 | 
			
		||||
 | 
			
		||||
				minTemp = [];
 | 
			
		||||
				maxTemp = [];
 | 
			
		||||
				weather.precipitation = 0;
 | 
			
		||||
 | 
			
		||||
				// set new date
 | 
			
		||||
				date = moment(forecast.startTime).format("YYYY-MM-DD");
 | 
			
		||||
 | 
			
		||||
				// specify date
 | 
			
		||||
				weather.date = moment(forecast.startTime);
 | 
			
		||||
 | 
			
		||||
				// If the first value of today is later than 17:00, we have an icon at least!
 | 
			
		||||
				weather.weatherType = this.convertWeatherType(forecast.shortForecast, forecast.isDaytime);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (moment(forecast.startTime).format("H") >= 8 && moment(forecast.startTime).format("H") <= 17) {
 | 
			
		||||
				weather.weatherType = this.convertWeatherType(forecast.shortForecast, forecast.isDaytime);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// the same day as before
 | 
			
		||||
			// add values from forecast to corresponding variables
 | 
			
		||||
			minTemp.push(forecast.temperature);
 | 
			
		||||
			maxTemp.push(forecast.temperature);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// last day
 | 
			
		||||
		// calculate minimum/maximum temperature, specify rain amount
 | 
			
		||||
		weather.minTemperature = Math.min.apply(null, minTemp);
 | 
			
		||||
		weather.maxTemperature = Math.max.apply(null, maxTemp);
 | 
			
		||||
 | 
			
		||||
		// push weather information to days array
 | 
			
		||||
		days.push(weather);
 | 
			
		||||
		return days.slice(1);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Convert the icons to a more usable name.
 | 
			
		||||
	 */
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
		if (weatherType.includes("Cloudy") || weatherType.includes("Partly")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "day-cloudy";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-cloudy";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Overcast")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "cloudy";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-cloudy";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Freezing") || weatherType.includes("Ice")) {
 | 
			
		||||
			return "rain-mix";
 | 
			
		||||
		} else if (weatherType.includes("Snow")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "snow";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-snow";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Thunderstorm")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "thunderstorm";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-thunderstorm";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Showers")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "showers";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-showers";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Rain")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "rain";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-rain";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Breezy") || weatherType.includes("Windy")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "cloudy-windy";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-alt-cloudy-windy";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Fair") || weatherType.includes("Clear") || weatherType.includes("Few")) {
 | 
			
		||||
			if (isDaytime) {
 | 
			
		||||
				return "day-sunny";
 | 
			
		||||
			} else {
 | 
			
		||||
				return "night-clear";
 | 
			
		||||
			}
 | 
			
		||||
		} else if (weatherType.includes("Fog")) {
 | 
			
		||||
			return "fog";
 | 
			
		||||
		} else if (weatherType.includes("Smoke")) {
 | 
			
		||||
			return "smoke";
 | 
			
		||||
		} else if (weatherType.includes("Haze")) {
 | 
			
		||||
			return "day-haze";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return null;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/* getParams(compliments)
 | 
			
		||||
	 * Generates an url with api parameters based on the config.
 | 
			
		||||
	 *
 | 
			
		||||
	 * return String - URL params.
 | 
			
		||||
	 */
 | 
			
		||||
	getParams() {
 | 
			
		||||
		
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	Convert the direction into Degrees
 | 
			
		||||
	*/
 | 
			
		||||
	convertDirectiontoDegrees(direction) {
 | 
			
		||||
		if (direction === "NNE"){
 | 
			
		||||
			return 33.75;
 | 
			
		||||
		} else if (direction === "NE") {
 | 
			
		||||
			return 56.25;
 | 
			
		||||
		} else if (direction === "ENE") {
 | 
			
		||||
			return 78.75;
 | 
			
		||||
		} else if (direction === "E") {
 | 
			
		||||
			return 101.25;
 | 
			
		||||
		} else if (direction === "ESE") {
 | 
			
		||||
			return 123.75;
 | 
			
		||||
		} else if (direction === "SE") {
 | 
			
		||||
			return 146.25;
 | 
			
		||||
		} else if (direction === "SSE") {
 | 
			
		||||
			return 168.75;
 | 
			
		||||
		} else if (direction === "S") {
 | 
			
		||||
			return 191.25;
 | 
			
		||||
		} else if (direction === "SSW") {
 | 
			
		||||
			return 213.75;
 | 
			
		||||
		} else if (direction === "SW") {
 | 
			
		||||
			return 236.25;
 | 
			
		||||
		} else if (direction === "WSW") {
 | 
			
		||||
			return 258.75;
 | 
			
		||||
		} else if (direction === "W") {
 | 
			
		||||
			return 281.25;
 | 
			
		||||
		} else if (direction === "WNW") {
 | 
			
		||||
			return 303.75;
 | 
			
		||||
		} else if (direction === "NW") {
 | 
			
		||||
			return 326.25;
 | 
			
		||||
		} else if (direction === "NNW") {
 | 
			
		||||
			return 348.75;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user