Skip to content

Instantly share code, notes, and snippets.

@Brunas
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Brunas/ad6b7493902145b54a8c to your computer and use it in GitHub Desktop.
Save Brunas/ad6b7493902145b54a8c to your computer and use it in GitHub Desktop.
HAMWeather.com widget
require 'net/http'
require 'json'
class HAMWeather
# Your HAMWeather.com client ID
CLIENT_ID = 'Client ID'
# Your HAMWeather.com client secret
CLIENT_SECRET = 'Client Secret'
DEBUG = 0
SETTINGS_FILE = 'assets/config/hamw_settings.json'
def debug
DEBUG
end
def settingsFile
SETTINGS_FILE
end
# function to validate json
def valid_json? (json)
JSON.parse(json, { :symbolize_names => true } )
return true
rescue JSON::ParserError
return false
end
def get_weather(request_params)
# use proxy url/port if needed
http = Net::HTTP.new('api.aerisapi.com', nil, nil, nil)
response = http.request(Net::HTTP::Get.new("/observations/#{request_params['placeId']}?client_id=#{CLIENT_ID}&client_secret=#{CLIENT_SECRET}"))
JSON.parse(response.body)['response'] if response and response.body and !response.body.empty? and valid_json?(response.body)
rescue Timeout::Error
puts DateTime.now.to_s+" Timeout occured while requesting weather for #{request_params}" if DEBUG > 0
rescue Errno::ECONNRESET => e
puts DateTime.now.to_s+" Connection reset by pear exception occured while requesting weather for #{request_params}" if DEBUG > 0
end
def climacon_class(weather_codes)
out = ''
weather_codes.split(',').reverse.each do |subCode|
case subCode.split(':').last
when 'CL'
out = 'sun'
when 'FW', 'SC'
out = 'cloud sun'
when 'BK', 'OV'
out = 'cloud'
when 'A'
out = 'hail'
when 'BS', 'RS', 'S', 'SI', 'SW'
out = 'snow'
when 'BY', 'L', 'ZL'
out = 'drizzle'
when 'BR', 'F', 'IC', 'IF', 'ZF'
out = 'fog'
when 'FR'
out = 'thermometer low'
when 'H'
out = 'haze'
when 'IP'
out = 'sleet'
when 'R', 'RW', 'ZR', 'ZY'
out = 'rain'
when 'T'
out = 'lightning'
end
end
out
end
def get_degree_char(request_params)
return 'C' if request_params['tempField'].downcase.index 'tempc'
'F'
end
def get_wind_speed (speed, request_params)
return speed.to_f.round(1).to_s+' mph' if request_params['windSpeedField'].downcase.index 'mph'
(speed.to_f/3.6).round(1).to_s+' m/s'
end
def get_wind_direction_code(degrees)
degrees = degrees.to_i
return 'N' if degrees == 0 or degrees == 360
return 'N-NE' if (1..29).include?(degrees)
return 'NE' if (30..59).include?(degrees)
return 'E-NE' if (60..89).include?(degrees)
return 'E' if degrees == 90
return 'E-SE' if (91..119).include?(degrees)
return 'SE' if (120..149).include?(degrees)
return 'S-SE' if (150..179).include?(degrees)
return 'S' if degrees == 180
return 'S-SW' if (181..209).include?(degrees)
return 'SW' if (210..239).include?(degrees)
return 'W-SW' if (240..269).include?(degrees)
return 'W' if degrees == 270
return 'W-NW' if (271..299).include?(degrees)
return 'NW' if (300..329).include?(degrees)
return 'N-NW' if (330..359).include?(degrees)
''
end
end
@HW = HAMWeather.new()
SCHEDULER.every '20m', :first_in => 0 do |job|
str = IO.read(@HW.settingsFile)
if str and @HW.valid_json?(str)
JSON.parse(str).each do |widget, request_params|
puts "Working with #{widget} and #{request_params}"
weather_data = @HW.get_weather(request_params)
puts weather_data if weather_data and @HW.debug > 1
send_event(widget, { :temp => weather_data['ob'][request_params['tempField']].to_f.round.to_s+"°"+@HW.get_degree_char(request_params),
:condition => weather_data['ob']['weatherShort'],
:humidity => weather_data['ob']['humidity'].to_f.round.to_s+"%",
:windSpeed => @HW.get_wind_speed(weather_data['ob'][request_params['windSpeedField']], request_params),
:windDirection => @HW.get_wind_direction_code(weather_data['ob']['windDirDEG']),
:title => request_params['placeName'],
:updated => weather_data['ob']['timestamp'],
:climacon => @HW.climacon_class(weather_data['ob']['weatherCoded'])
} )
end
end
end
{"weather_kaunas":{"placeId":"kaunas,lt","windSpeedField":"windSpeedKPH","tempField":"tempC","placeName":"Kaunas"},"weather_swindon":{"placeId":"swindon,gb","windSpeedField":"windSpeedMPH","tempField":"tempC","placeName":"Swindon"}}}

Description

This is extended version of Dashing Weather widget. Weather information is retrieved from HAMWeather.com.

Installation

Put the files weather.coffee, weather.html and weather.scss in the /widget/weather directory, the hamw.rb in the /jobs directory and the hamw_settings.json to /assets/config.

Usage

Put the following in your dashing board file to show the status:

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
  <div data-id="weather_kaunas" data-view="Weather" data-date-time-format="%Y-%m-%d %H:%M:%S"></div>
</li>

Settings

Amend /assets/config/hamw_settings.json with data for your region. Visit HAMWeather.com for more details what to use in fields. You have to be registered there and not to exceed maximum number of requests to use service freely.

There is no need to restart service if job is already running and settings file is amended.

class Dashing.Weather extends Dashing.Widget
ready: ->
# This is fired when the widget is done being rendered
@setClimacon()
@handleWind()
@handleDate()
onData: (data) ->
@setClimacon()
@handleWind()
@handleDate()
setClimacon: ->
icon = $(@node).find('i.climacon')
return if !icon
if @get('climacon')
icon.attr 'class', "climacon icon-background #{@get('climacon')}"
else
icon.attr 'class', "climacon icon-background"
handleWind: ->
return if not @get('windSpeed')
wind = @get('windDirection') + ' ' if @get('windDirection')
wind += @get('windSpeed')
@set('wind', wind)
handleDate: ->
nTime = new Date()
nTime.setTime(@get('updated')*1000)
if nTime.getFullYear()
@set('updated', @formatDateTime(nTime))
formatDateTime: (dateTime) ->
format = $(@node).data('date-time-format')
format = "%Y-%m-%d %H:%M:%S" if !format
if format
format.replace('%Y',dateTime.getFullYear()).replace('%m', @zeroLPad(dateTime.getMonth()+1)).replace('%d',@zeroLPad(dateTime.getDate())).replace('%H',@zeroLPad(dateTime.getHours())).replace('%M', @zeroLPad(dateTime.getMinutes())).replace('%S', @zeroLPad(dateTime.getSeconds()))
else
dateTime.toLocaleDateString()+" "+dateTime.toLocaleTimeString()
zeroLPad: (i) ->
if i < 10 then "0" + i else i
<i class="climacon icon-background"></i>
<h1 class="title" data-bind="title | append ' Weather'"></h1>
<h2 class="temp" data-bind="temp | raw"></h2>
<p class="condition" data-bind="condition"></p>
<p class="wind" data-bind="wind | prepend 'Wind: '"></p>
<p class="humidity" data-bind="humidity | prepend 'Humidity: '"></p>
<p class="condition-updated-at" data-bind="updated | prepend 'As of '"></p>
<p class="updated-at" data-bind="updatedAtMessage"></p>
// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
$background-color: #47bbb3;
$value-color: #fff;
$humidity-color: rgba(255, 255, 255, 0.6);
$title-color: rgba(255, 255, 255, 0.9);
$moreinfo-color: rgba(255, 255, 255, 0.7);
// ----------------------------------------------------------------------------
// Widget-weather styles
// ----------------------------------------------------------------------------
.widget-weather {
background-color: $background-color;
.title {
color: $title-color;
font-size:+2.5em;
}
.temp {
color: $value-color;
font-size:+8em;
text-shadow:
-2px -2px 0 #000,
2px -2px 0 #000,
-2px 2px 0 #000,
2px 2px 0 #000;
}
.icon-background {
height:100%;
margin:0;
padding:0;
opacity: 0.2;
font-size:325px;
}
.condition {
font-weight: 600;
font-size: +2em;
color: $value-color;
}
.humidity, .wind {
font-size: 0.8em;
color: $humidity-color;
}
.condition-updated-at {
font-size: 15px;
position: absolute;
bottom: 25px;
left: 0;
right: 0;
color: rgba(0, 0, 0, 0.3);
}
.updated-at {
color: rgba(0, 0, 0, 0.3);
bottom: 7px;
}
}
@font-face {
font-family: 'Climacons-Font';
src:url('climacons-webfont.eot');
src:url('climacons-webfont.eot?#iefix') format('embedded-opentype'),
url('climacons-webfont.svg#Climacons-Font') format('svg'),
url('climacons-webfont.woff') format('woff'),
url('climacons-webfont.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
.climacon:before{
font-family: 'Climacons-Font';
speak: none;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
}
.climacon.cloud:before {
content: "\e000";
}
.climacon.cloud.sun:before {
content: "\e001";
}
.climacon.cloud.moon:before {
content: "\e002";
}
.climacon.rain:before,
.climacon.rain.cloud:before {
content: "\e003";
}
.climacon.rain.sun:before,
.climacon.rain.cloud.sun:before {
content: "\e004";
}
.climacon.rain.moon:before,
.climacon.rain.cloud.moon:before {
content: "\e005";
}
.climacon.showers:before,
.climacon.showers.cloud:before {
content: "\e006";
}
.climacon.showers.sun:before,
.climacon.showers.cloud.sun:before {
content: "\e007";
}
.climacon.showers.moon:before,
.climacon.showers.cloud.moon:before {
content: "\e008";
}
.climacon.downpour:before,
.climacon.downpour.cloud:before {
content: "\e009";
}
.climacon.downpour.sun:before,
.climacon.downpour.cloud.sun:before {
content: "\e00a";
}
.climacon.downpour.moon:before,
.climacon.downpour.cloud.moon:before {
content: "\e00b";
}
.climacon.drizzle:before,
.climacon.drizzle.cloud:before {
content: "\e00c";
}
.climacon.drizzle.sun:before,
.climacon.drizzle.cloud.sun:before {
content: "\e00d";
}
.climacon.drizzle.moon:before,
.climacon.drizzle.cloud.moon:before {
content: "\e00e";
}
.climacon.sleet:before,
.climacon.sleet.cloud:before {
content: "\e00f";
}
.climacon.sleet.sun:before,
.climacon.sleet.cloud.sun:before {
content: "\e010";
}
.climacon.sleet.moon:before,
.climacon.sleet.cloud.moon:before {
content: "\e011";
}
.climacon.hail:before,
.climacon.hail.cloud:before {
content: "\e012";
}
.climacon.hail.sun:before,
.climacon.hail.cloud.sun:before {
content: "\e013";
}
.climacon.hail.moon:before,
.climacon.hail.cloud.moon:before {
content: "\e014";
}
.climacon.flurries:before,
.climacon.flurries.cloud:before {
content: "\e015";
}
.climacon.flurries.sun:before,
.climacon.flurries.cloud.sun:before {
content: "\e016";
}
.climacon.flurries.moon:before,
.climacon.flurries.cloud.moon:before {
content: "\e017";
}
.climacon.snow:before,
.climacon.snow.cloud:before {
content: "\e018";
}
.climacon.snow.sun:before,
.climacon.snow.cloud.sun:before {
content: "\e019";
}
.climacon.snow.moon:before,
.climacon.snow.cloud.moon:before {
content: "\e01a";
}
.climacon.fog:before,
.climacon.fog.cloud:before {
content: "\e01b";
}
.climacon.fog.sun:before,
.climacon.fog.cloud.sun:before {
content: "\e01c";
}
.climacon.fog.moon:before,
.climacon.fog.cloud.moon:before {
content: "\e01d";
}
.climacon.haze:before {
content: "\e01e";
}
.climacon.haze.sun:before {
content: "\e01f";
}
.climacon.haze.moon:before {
content: "\e020";
}
.climacon.wind:before {
content: "\e021";
}
.climacon.wind.cloud:before {
content: "\e022";
}
.climacon.wind.sun:before,
.climacon.wind.cloud.sun:before {
content: "\e023";
}
.climacon.wind.moon:before,
.climacon.wind.cloud.moon:before {
content: "\e024";
}
.climacon.lightning:before,
.climacon.lightning.cloud:before {
content: "\e025";
}
.climacon.lightning.sun:before,
.climacon.lightning.cloud.sun:before {
content: "\e026";
}
.climacon.lightning.moon:before,
.climacon.lightning.cloud.moon:before {
content: "\e027";
}
.climacon.sun:before {
content: "\e028";
}
.climacon.sun.set:before,
.climacon.sunset:before {
content: "\e029";
}
.climacon.sun.rise:before,
.climacon.sunrise:before {
content: "\e02a";
}
.climacon.sun.low:before,
.climacon.sun-low:before,
.climacon.low-sun:before {
content: "\e02b";
}
.climacon.sun.lower:before,
.climacon.sun-lower:before,
.climacon.lower-sun:before {
content: "\e02c";
}
.climacon.moon:before {
content: "\e02d";
}
.climacon.moon.new:before {
content: "\e02e";
}
.climacon.moon.waxing.crescent:before,
.climacon.moon.first-crescent:before {
content: "\e02f";
}
.climacon.moon.waxing.quarter:before,
.climacon.moon.first-quarter:before,
.climacon.moon.waxing.half:before,
.climacon.moon.first-half:before{
content: "\e030";
}
.climacon.moon.waxing.gibbous:before,
.climacon.moon.first-gibbous:before,
.climacon.moon.waxing.three-quarter:before,
.climacon.moon.first-three-quarter:before {
content: "\e031";
}
.climacon.moon.full:before {
content: "\e032";
}
.climacon.moon.waning.gibbous:before,
.climacon.moon.last-gibbous:before,
.climacon.moon.waning.three-quarter:before,
.climacon.moon.last-three-quarter:before {
content: "\e033";
}
.climacon.moon.waning.quarter:before,
.climacon.moon.last-quarter:before,
.climacon.moon.waning.half:before,
.climacon.moon.last-half:before {
content: "\e034";
}
.climacon.moon.waning.crescent:before,
.climacon.moon.last-crescent:before {
content: "\e035";
}
.climacon.snowflake:before {
content: "\e036";
}
.climacon.tornado:before {
content: "\e037";
}
.climacon.thermometer.empty:before,
.climacon.thermometer:before {
content: "\e038";
}
.climacon.thermometer.low:before {
content: "\e039";
}
.climacon.thermometer.medium-low:before {
content: "\e03a";
}
.climacon.thermometer.medium-high:before {
content: "\e03b";
}
.climacon.thermometer.high:before {
content: "\e03c";
}
.climacon.thermometer.full:before {
content: "\e03d";
}
.climacon.celcius:before {
content: "\e03e";
}
.climacon.farenheit:before {
content: "\e03f";
}
.climacon.compass:before {
content: "\e040";
}
.climacon.compass.north:before {
content: "\e041";
}
.climacon.compass.east:before {
content: "\e042";
}
.climacon.compass.south:before {
content: "\e043";
}
.climacon.compass.west:before {
content: "\e044";
}
.climacon.umbrella:before {
content: "\e045";
}
.climacon.sunglasses:before {
content: "\e046";
}
.climacon.cloud.cycle:before,
.climacon.cloud.refresh:before {
content: "\e047";
}
.climacon.cloud.down:before,
.climacon.cloud.download:before {
content: "\e048";
}.climacon.cloud.up:before,
.climacon.cloud.upload:before {
content: "\e049";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment