UNPKG

forecastweather

Version:

[thing-it-node] Device Plugin for Online Weather Forecast data.

418 lines (377 loc) 13 kB
/** * The module exports are used by the [thing-it-node]. * the first couple before state are mandatory for the device. * * State will be shown in many default screens and can very easily * be accessed in the HTML UI and other places. * * Services will be exposed in UIs as invocable by the user * and they will be exposed for orchestration. * * Configuration will be displayed when adding a device * on www.thing-it.com and in allows the device to access * the users' values during device creation on www.thing-it.com * */ module.exports = { metadata: { family: "weather", plugin: "weatherForecast", label: "Weather Forecast", tangible: true, discoverable: true, state: [{ id: "date", label: "Date", type: { id: "string" } }, { id: "minTemperature", label: "Minimum Temperature", type: { id: "decimal" } }, { id: "maxTemperature", label: "Maximum Temperature", type: { id: "decimal" } }, { id: "temperatureUnit", label: "Temperature Unit", type: { id: "string" } }, { id: "avgBarometricPressure", label: "Average Barometric Pressure", type: { id: "decimal" } }, { id: "avgHumidity", label: "Humidity", type: { id: "decimal" } }, { id: "frqWeatherMain", label: "Weather Main", type: { id: "string" } }, { id: "frqWeatherDescription", label: "Weather Description", type: { id: "string" } }, { id: "frqWeatherIconUrl", label: "Weather Description", type: { id: "string" } }, { id: "cityId", label: "City Id", type: { id: "string" } }, { id: "cityName", label: "City Name", type: { id: "string" } }, { id: "clouds", label: "Cloud Percentage", type: { id: "integer" } }, { id: "rainPrediction", label: "Predicted Rainfall", type: { id: "integer" } }, { id: "snowPrediction", label: "Predicted Snowfall", type: { id: "integer" } }, { id: "avgWindSpeed", label: "Average Wind Speed", type: { id: "integer" } }, { id: "windSpeedUnit", label: "Wind Speed Unit", type: { id: "string" } }, { id: "avgWindDirection", label: "Average Wind Direction", type: { id: "integer" } }], actorTypes: [], sensorTypes: [], services: [{ id: "update", label: "Update" }], configuration: [{ id: "cityName", label: "City Name", type: { id: "string" } }, { id: "countryCode", label: "Country Code", type: { id: "string" } }, { id: "languageCode", label: "Language Code", type: { id: "string" } }, { id: "units", label: "Units", type: { id: "string" } }, { id: "updateFrequencySeconds", label: "Update Frequency Seconds", type: { id: "integer" } }, { id: "openWeatherMapKey", label: "Open Weather Map Key", type: { id: "string" } }] }, /** * Invoked during start up to create the instance of * Weather for this specific device. * */ create: function (device) { return new Weather(); }, /** * Discovery is an advanced function we don't need * for our Hello World example. * */ discovery: function (options) { var discovery = new WeatherDiscovery(); discovery.options = options; return discovery; } }; var q = require('q'); var request; var https; //var WorldConnectionAPI; /** * Discovery is an advanced function we don't need * for our Hello World example. * */ function WeatherDiscovery() { /** * */ WeatherDiscovery.prototype.start = function () { }; /** * */ WeatherDiscovery.prototype.stop = function () { }; } /** * */ function Weather() { var updateInterval; /** * - Makes initial call to weather service * - Sets up update every 10 minutes * - Simulation mode isn't neded for this device * */ Weather.prototype.start = function () { var deferred = q.defer(); // Initialize state values this.state = { date: null, maxTemperature: null, minTemperature: null, avgBarometricPressure: null, avgHumidity: null, frqWeatherMain: null, frqWeatherDescription: null, frqWeatherIconURL: null, cityId: null, cityName: null, clouds: 0, rainPrediction: 0, snowPrediction: 0, avgWindSpeed: 0, avgWindDirection: 0, }; this.configError = false; if ((typeof this.configuration.openWeatherMapKey === undefined ) || !this.configuration.openWeatherMapKey || ("" == this.configuration.openWeatherMapKey)) { this.logError("An OpenWeatherMap Key is required for this device to work."); this.configError = true; } if ((typeof this.configuration.cityName === undefined ) || !this.configuration.cityName || ("" == this.configuration.cityName)) { this.configuration.cityName = "Frankfurt am Main"; } if ((typeof this.configuration.countryCode === undefined ) || !this.configuration.countryCode || ("" == this.configuration.countryCode)) { this.configuration.countryCode = "de"; } if ("metric" == this.configuration.units) { this.state.temperatureUnit = "C"; this.state.windSpeedUnit = "mps"; } else if ("imperial" == this.configuration.units) { this.state.temperatureUnit = "F"; this.state.windSpeedUnit = "fps"; } else { this.configuration.units = "metric"; this.state.temperatureUnit = "C"; this.state.windSpeedUnit = "mps"; } if ((typeof this.configuration.languageCode === undefined ) || !this.configuration.languageCode || ("" == this.configuration.languageCode)) { this.configuration.languageCode = "de"; } if ((typeof this.configuration.updateFrequencySeconds === undefined ) || !this.configuration.updateFrequencySeconds || (0 == this.configuration.updateFrequencySeconds)) { this.configuration.updateFrequencySeconds = 3600; } this.logDebug("Configuration", this.configuration); if (this.isSimulated()) { // ignore, all we need is an internet connection. } this.logInfo("Starting up Weather."); this.getWeather(); this.updateInterval = setInterval(function () { this.getWeather() }.bind(this), this.configuration.updateFrequencySeconds * 1000); deferred.resolve(); return deferred.promise; }; Weather.prototype.stop = function () { clearInterval(this.updateInterval); } /** * - Connects to OpenWeatherMap * - Sets the status */ Weather.prototype.getWeather = function () { var deferred = q.defer(); if (this.configError) { this.logError("Configuration error - cannot retrieve weather info."); } else { this.logInfo("Requesting weather update from http://api.openweathermap.org/"); this.logDebug("Polling weather.", this.configuration); var url = "http://api.openweathermap.org/data/2.5/forecast?q=" + this.configuration.cityName + "," + this.configuration.countryCode + "&units=" + this.configuration.units + "&lang=" + this.configuration.languageCode + "&APPID=" + this.configuration.openWeatherMapKey; this.logDebug("Request URL", url); if (!request) { request = require('request'); } request.get({ url: url }, function (error, response, body) { if (error) { this.logError("Error communicating to weather service.", error, body); deferred.reject("Error communicating to weather service."); } else { try { var weatherData = JSON.parse(body); if ((weatherData.cod) && (200 != weatherData.cod)) { var errorMessage = 'Could not get weather. Error code ' + weatherData.cod + ' with message "' + weatherData.message + '".'; this.logError(errorMessage); deferred.reject(errorMessage); } else { //where I need to figure out way to sort through data by adding functions this.state = { date: weatherData.list.dt_txt, temperatureUnit: this.state.temperatureUnit, maxTemperature: weatherData.list.main.temp_max, minTemperature: weatherData.list.main.temp_min, avgBarometricPressure: weatherData.list.main.pressure, avgHumidity: weatherData.list.main.humidity, frqWeatherMain: weatherData.list.weather[0].main, frqWeatherDescription: weatherData.list.weather[0].description, frqWeatherIconURL: "http://openweathermap.org/img/w/" + weatherData.list.weather[0].icon + ".png", cityId: weatherData.city.id, cityName: weatherData.city.name, clouds: weatherData.list.clouds.all, avgWindSpeed: weatherData.list.wind.speed, windSpeedUnit: this.state.windSpeedUnit, avgWindDirection: weatherData.list.wind.deg, }; try { this.state.rainPrediction = weatherData.list.rain['3h']; } catch (e) { //ignore } try { this.state.snowPrediction = weatherData.list.snow['3h']; } catch (e) { //ignore } this.publishStateChange(); deferred.resolve(); } } catch (e) { this.logError(e); deferred.reject(e); } } }.bind(this)); } return deferred.promise; }; /** * */ Weather.prototype.update = function () { this.getWeather(); } /** * */ Weather.prototype.setState = function (state) { this.state = state; this.publishStateChange(); }; /** * */ Weather.prototype.getState = function () { return this.state; }; }