Skip to content

Commit

Permalink
Merge pull request #20 from Raminios/weather-node-dev
Browse files Browse the repository at this point in the history
Added weather nodes
  • Loading branch information
knolleary committed Oct 8, 2014
2 parents 16a52f4 + 782cf30 commit 2d18c37
Show file tree
Hide file tree
Showing 3 changed files with 389 additions and 0 deletions.
Binary file added weather/icons/weather.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
228 changes: 228 additions & 0 deletions weather/weather.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<script type="text/x-red" data-template-name="openweathermap">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="weather-location-type-select"><i class="fa fa-globe"></i> Location</label>
<select id="weather-location-type-select" style="width: 288px"><option value="city">City</option><option value="coordinates">Coordinates</option></select>
</div>
<div class="form-row weather-location-type" id="weather-location-type-city">
<label for=""><i class="weather-location-type"></i> City</label>
<input type="text" class="weather-location-input" style="width: 180px; margin-bottom:7px" id="node-input-city" placeholder="City"></input>
</br>
<label for=""><i class="weather-location-type"></i> Country</label>
<input type="text" class="weather-location-input" style="width: 180px; margin-bottom:7px" id="node-input-country" placeholder="Country"></input>
</div>
<div class="form-row weather-location-type hidden" id="weather-location-type-coordinates">
<label for=""><i class="weather-location-type"></i> Latitude</label><input type="text" class="weather-location-input" id="node-input-lat" style="width: 180px; margin-bottom:7px" placeholder="Latitude">
</br>
<label for=""><i class="weather-location-type"></i> Longitude</label><input type="text" class="weather-location-input" id="node-input-lon" style="width: 180px; margin-bottom:7px" placeholder="Longitude">
</div>
</script>

<script type="text/javascript">
RED.nodes.registerType('openweathermap',{
category: 'weather',
color: '#FFCC66',
defaults: {
name: {value:""},
lon: {value:"", validate:function(v) {return ((v>=-180) && (v<=180));} },
lat: {value:"", validate:function(v) {return ((v>=-90) && (v<=90));} },
city: {value:""},
country: {value:""},
},
inputs:1,
outputs:1,
icon: "weather.png",
label: function() {
return this.name||"openweathermap";
},
oneditprepare: function() {
$("#weather-location-type-select").change(function() {
var id = $("#weather-location-type-select option:selected").val();
$(".weather-location-type").hide();
$("#weather-location-type-"+id).show();
});
if(this.lon !== ""||this.lat !== ""){
$("#weather-location-type-select").val("coordinates");
} else {
$("#weather-location-type-select").val("city");
}
var id = $("#weather-location-type-select option:selected").val();
$(".weather-location-type").hide();
$("#weather-location-type-"+id).show();
},
oneditsave: function() {
var type = $("#weather-location-type-select option:selected").val();
if(type == "coordinates"){
$("#node-input-city").val("");
$("#node-input-country").val("");
} else if (type == "city") {
$("#node-input-lon").val("");
$("#node-input-lat").val("");
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>

<script type="text/x-red" data-help-name="openweathermap">
<p>A node which polls a server for current weather data when an input is received.</p>

<p> This is done using either:</p>
<ul>
<li> a city and the country in which that city lies</li>
<li> a latitude and longitude set of coordinates </li>
</ul>
<p>These can be passed in as settings on the node, or as the:</p>
<ul>
<li> <b>msg.payload.lat</b> and <b>msg.payload.lon</b>, or </li>
<li> <b>msg.payload.city</b> and <b>msg.payload.country</b> </li>
</ul>
<p>of the message input. </p>
<p>The node will always prioritise the parameters passed in when both of <b>lat/lon</b> or <b>country/city</b> are present.</p>

<p>The node sets the following properties of <b>msg.payload</b>:</p>
<ul>
<li><b>description</b> - a brief verbal description of the current weather for human reading.</li><br>
<li><b>weather</b> - a short description of the current weather.</li><br>
<li><b>detail</b> - a more detailed expansion on <b>weather</b>.</li><br>
<li><b>tempk</b> - the current gorund temperature at that location in Kelvin.</li><br>
<li><b>humidity</b> - the current humidity at the location in percent.</li><br>
<li><b>maxtemp</b> - the current maximum temperature at the location in Kelvin.</li><br>
<li><b>mintemp</b> - the current minimum temperature at the location in Kelvin.</li><br>
<li><b>windspeed</b> - the current wind speed at the location in Metres per second.</li><br>
<li><b>winddirection</b> - the current wind direction at the location in meteorological degrees.</li><br>
<li><b>town</b> - the name of the location from which the data was sourced.</li><br>
<li><b>lon</b> - the longitude of the location from which the data was sourced.</li><br>
<li><b>lat</b> - to the latitude of the location from which the data was sourced.</li><br>
<li><b>sunrise</b> - the time at which the sun rose in Unix UTC format.</li><br>
<li><b>sunset</b> - the time at which the sun will set in Unix UTC format.</li><br>
<li><b>clouds</b> - the current cloud coverage of the location in percent.</li><br>
</ul>
<p>Weather data provided by <a href="http://openweathermap.org/" target="_blank">openweathermap.org/</a></p>
</script>



<script type="text/x-red" data-template-name="openweathermap in">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="weather-location-type-select"><i class="fa fa-globe"></i> Location</label>
<select id="weather-location-type-select" style="width: 288px"><option value="city">City</option><option value="coordinates">Coordinates</option></select>
</div>
<div class="form-row weather-location-type" id="weather-location-type-city">
<label for=""><i class="weather-location-type"></i> City</label>
<input type="text" class="weather-location-input" style="width: 180px; margin-bottom:7px" id="node-input-city" placeholder="City"></input>
</br>
<label for=""><i class="weather-location-type"></i> Country</label>
<input type="text" class="weather-location-input" style="width: 180px; margin-bottom:7px" id="node-input-country" placeholder="Country"></input>
</div>
<div class="form-row weather-location-type hidden" id="weather-location-type-coordinates">
<label for=""><i class="weather-location-type"></i> Latitude</label><input type="text" class="weather-location-input" id="node-input-lat" style="width: 180px; margin-bottom:7px" placeholder="Latitude">
</br>
<label for=""><i class="weather-location-type"></i> Longitude</label><input type="text" class="weather-location-input" id="node-input-lon" style="width: 180px; margin-bottom:7px" placeholder="Longitude">
</div>
</script>

<script type="text/javascript">
RED.nodes.registerType('openweathermap in',{
category: 'weather',
color: '#FFCC66',
defaults: {
name: {value:""},
lon: {value:"", validate:function(v) {return ((v>=-180) && (v<=180));} },
lat: {value:"", validate:function(v) {return ((v>=-90) && (v<=90));} },
city: {value:""},
country: {value:""},
},
inputs:0,
outputs:1,
icon: "weather.png",
label: function() {
return this.name||"openweathermap";
},
oneditprepare: function() {
$("#weather-location-type-select").change(function() {
var id = $("#weather-location-type-select option:selected").val();
$(".weather-location-type").hide();
$("#weather-location-type-"+id).show();
});
if(this.lon !== ""||this.lat !== ""){
$("#weather-location-type-select").val("coordinates");
} else {
$("#weather-location-type-select").val("city");
}
var id = $("#weather-location-type-select option:selected").val();
$(".weather-location-type").hide();
$("#weather-location-type-"+id).show();


},
oneditsave: function() {
var type = $("#weather-location-type-select option:selected").val();
if(type == "coordinates"){
$("#node-input-city").val("");
$("#node-input-country").val("");
} else if (type == "city") {
$("#node-input-lon").val("");
$("#node-input-lat").val("");
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>

<script type="text/x-red" data-help-name="openweathermap in">
<p>A node which polls a server for current weather data periodically and returns when a change is detected.</p>

<p> This is done using either:</p>
<ul>
<li> a city and the country in which that city lies</li>
<li> a latitude and longitude set of coordinates </li>
</ul>

<p>The node sets the following properties of <b>msg.payload</b>:</p>
<ul>
<li><b>description</b> - a brief verbal description of the current weather for human reading.</li><br>
<li><b>weather</b> - a short description of the current weather.</li><br>
<li><b>detail</b> - a more detailed expansion on <b>weather</b>.</li><br>
<li><b>tempk</b> - the current gorund temperature at that location in Kelvin.</li><br>
<li><b>humidity</b> - the current humidity at the location in percent.</li><br>
<li><b>maxtemp</b> - the current maximum temperature at the location in Kelvin.</li><br>
<li><b>mintemp</b> - the current minimum temperature at the location in Kelvin.</li><br>
<li><b>windspeed</b> - the current wind speed at the location in Metres per second.</li><br>
<li><b>winddirection</b> - the current wind direction at the location in meteorological degrees.</li><br>
<li><b>town</b> - the name of the location from which the data was sourced.</li><br>
<li><b>lon</b> - the longitude of the location from which the data was sourced.</li><br>
<li><b>lat</b> - to the latitude of the location from which the data was sourced.</li><br>
<li><b>sunrise</b> - the time at which the sun rose in Unix UTC format.</li><br>
<li><b>sunset</b> - the time at which the sun will set in Unix UTC format.</li><br>
<li><b>clouds</b> - the current cloud coverage of the location in percent.</li><br>
</ul>
<p>Weather data provided by <a href="http://openweathermap.org/" target="_blank">openweathermap.org/</a></p>
</script>

<style>
.weather-location-type {
padding-left: 110px;
}

.weather-data-credit {
font-size: 70%;
font-color: gray;
text-align: right;
}

.weather-location-input{
margin-bottom: 10px;
}
</style>
161 changes: 161 additions & 0 deletions weather/weather.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
module.exports = function(RED) {
"use strict";
var http = require("http");

function weatherPoll(node, n, msg, callback) {
var url;
var lat;
var lon;
var city;
var country;

if (n.city !== "" || n.country !== "") {
city = n.city;
country = n.country;
} else if (n.lat !== "" || n.lon !== "") {
lat = n.lat;
lon = n.lon;
}

//if there is data in the message input, it overwrites the node setting values.
//If the data is erroneous or not there, the values remain the node settings.
if(msg.payload){
//query node code to check the input for information.
if (msg.payload.city && msg.payload.country) {
city = msg.payload.city;
country = msg.payload.country;
lat = "";
lon = "";
}
if (msg.payload.lat && msg.payload.lon){
if(90 >= msg.payload.lat && 180 >= msg.payload.lon && msg.payload.lat >= -90 && msg.payload.lon >= -180){
lat = msg.payload.lat;
lon = msg.payload.lon;
city = "";
country = "";
} else {
node.warn("Invalid lat/lon in input payload");
}
}
}
//wipe clear the payload if it exists, or create it if it doesn't
msg.payload = {};

//If there is a value missing, the URL is not initialised.
if (lat && lon){
url = "http://api.openweathermap.org/data/2.5/weather?lat=" + lat + "&lon=" + lon;
} else if (city && country) {
url = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + country;
}

//If the URL is not initialised, there has been an error with the input data,
//and a node.error is reported.
if(url){
http.get(url, function(res) {
var weather = "";

res.on('data', function(d) {
weather += d;
});

res.on('end', function() {
var jsun = JSON.parse(weather);
if(jsun.weather){
msg.payload.weather = jsun.weather[0].main;
msg.payload.detail = jsun.weather[0].description;
msg.payload.tempk = jsun.main.temp;
msg.payload.humidity = jsun.main.humidity;
msg.payload.maxtemp = jsun.main.temp_max;
msg.payload.mintemp = jsun.main.temp_min;
msg.payload.windspeed = jsun.wind.speed;
msg.payload.winddirection = jsun.wind.deg;
msg.payload.location = jsun.name;
msg.payload.lon = jsun.coord.lon;
msg.payload.lat = jsun.coord.lat;
msg.payload.sunrise = jsun.sys.sunrise;
msg.payload.sunset = jsun.sys.sunset;
msg.payload.clouds = jsun.clouds.all;
msg.payload.description = ("The weather in " + jsun.name + " at coordinates: " + jsun.coord.lat + ", " + jsun.coord.lon + " is " + jsun.weather[0].main + " (" + jsun.weather[0].description + ")." );
callback();
} else {
if (jsun.message === "Not found city"){
if (n.city && n.country && country != n.country && city != n.city){
node.warn("Invalid city/country in input payload, trying node city/country");
msg.payload.country = n.country;
msg.payload.city = n.city;
weatherPoll(node, n, msg, function(){
node.send(msg);
});
} else if (n.lat && n.lon) {
node.warn("Invalid city/country in input payload, trying node lat/lon");
msg.payload.lat = n.lat;
msg.payload.lon = n.lon;
weatherPoll(node, n, msg, function(){
node.send(msg);
});
} else {
if(!n.city && !n.country){
node.error("Invalid city/country in input payload");
} else {
node.error("Invalid city/country in node settings");
}
}
} else {
node.error(jsun.cod + " " + jsun.message);
}
}
});
}).on('error', function(e) {
node.error(e);
});
} else {
node.error("Invalid location information provided");
}
}

function OpenWeatherMapInputNode(n) {
RED.nodes.createNode(this, n);
var node = this;
this.repeat = 300000;
this.interval_id = null;
var previousdata = null;

this.interval_id = setInterval( function() {
node.emit("input",{});
}, this.repeat );

this.on('input', function(msg) {
weatherPoll(node, n, msg, function(){
var msgString = JSON.stringify(msg);
if(msgString !== previousdata){
previousdata = msgString;
node.send(msg);
}

});
});

this.on("close", function() {
if (this.interval_id !== null) {
clearInterval(this.interval_id);
}
});

node.emit("input",{});
}

function OpenWeatherMapQueryNode(n) {
RED.nodes.createNode(this,n);
var node = this;

this.on ('input', function(msg) {
weatherPoll(node, n, msg, function(){
node.send(msg);
});
});
}

RED.nodes.registerType("openweathermap",OpenWeatherMapQueryNode);
RED.nodes.registerType("openweathermap in",OpenWeatherMapInputNode);

};

0 comments on commit 2d18c37

Please sign in to comment.