forecastweather
Version:
[thing-it-node] Device Plugin for Online Weather Forecast data.
418 lines (377 loc) • 13 kB
JavaScript
/**
* 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;
};
}