Skip to content

Instantly share code, notes, and snippets.

@sighmin
Last active July 11, 2017 15:03
Show Gist options
  • Save sighmin/5628306 to your computer and use it in GitHub Desktop.
Save sighmin/5628306 to your computer and use it in GitHub Desktop.
Traffic widget and job for dashing dashboard framework.

Description

Simple Dashing widget and job to display driving times of a route. Uses TomTom for free traffic information.

We at platform45 use it to display our driving times home so we know when to leave work to get home to our loved ones in time.

##Dependencies

Uses json, uri and net/http net/https libraries.

##Usage

To use this widget, copy traffic.html, traffic.coffee, and traffic.scss into the /widgets/traffic directory. Put the traffic.rb file in your /jobs folder.

To include the widget in a dashboard, add the following snippet to the dashboard layout file:

<li class="purple" data-row="1" data-col="1" data-sizex="1" data-sizey="2">
  <div class="purple" data-id="tomtom" data-view="Traffic" data-title="Home Time"></div>
</li>

##Settings

You'll need to grab your office location and everyone's home address location from tomtom's maps here, and add them as shown to office_location and the location array.

You'll also need to generate a tomtom developer api key, this is free, it just takes 24 hours to activate. Get one here.

##Preview

Live Demo Here

class Dashing.Traffic extends Dashing.Widget
ready: ->
# This is fired when the widget is done being rendered
onData: (data) ->
# Handle incoming data
# You can access the html node of this widget with `@node`
# Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in.
<div class="non-semantic-protector">
<!-- ribbons and other content in here -->
<h1 class="ribbon">
<strong class="ribbon-content">
<h1 class="title" data-bind="title"></h1>
</strong>
</h1>
</div>
<br />
<ol>
<li data-foreach-result="results">
<span data-bind="result.name"></span> at <span class="drive-time" data-bind="result.time"></span>
<span class="drive-road" data-bind="result.road"></span>
</li>
</ol>
<p class="more-info" data-bind="moreinfo | raw"></p>
<p class="updated-at" data-bind="updatedAtMessage"></p>
require 'net/http'
require 'net/https'
require 'uri'
require 'json'
office_location = URI::encode('-26.116525,28.031015')
key = URI::encode('TOMTOM_APP_API_KEY')
locations = []
locations << { name: "Sam", location: URI::encode('-25.764803,28.34625') } # example location format
SCHEDULER.every '10m', :first_in => '15s' do |job|
routes = []
# pull data
locations.each do |location|
uri = URI.parse("https://api.tomtom.com/lbs/services/route/3/#{office_location}:#{location[:location]}/Quickest/json?avoidTraffic=true&includeTraffic=true&language=en&day=today&time=now&iqRoutes=2&avoidTolls=false&includeInstructions=true&projection=EPSG4326&key=#{key}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
routes << { name: location[:name], location: location[:location], route: JSON.parse(response.body)["route"] }
end
# find winner
if routes
routes.sort! { |route1, route2| route2[:route]["summary"]["totalTimeSeconds"] <=> route1[:route]["summary"]["totalTimeSeconds"] }
routes.map! do |r|
{ name: r[:name],
time: seconds_in_words(r[:route]["summary"]["totalTimeSeconds"]),
road: delay(r[:route]["summary"]["totalDelaySeconds"]) + longest_leg(r[:route]["instructions"]["instruction"]) }
end
end
# send event
send_event('tomtom', { results: routes } )
end
def seconds_in_words(secs)
m, s = secs.divmod(60)
h, m = m.divmod(60)
plural_hours = if h > 1 then "s" else "" end
plural_minutes = if m > 1 then "s" else "" end
if secs >= 3600
"#{h} hour#{plural_hours}, #{m} min#{plural_minutes}"
else
"#{m} min#{plural_minutes}"
end
end
def longest_leg(instructions)
instructions.sort! { |leg1, leg2| leg2["travelTimeSeconds"] <=> leg1["travelTimeSeconds"] }
if instructions[0]["roadNumber"].empty?
instructions[0]["roadName"]
elsif instructions[0]["roadName"].empty?
instructions[0]["roadNumber"]
else
"#{instructions[0]["roadName"]}, #{instructions[0]["roadNumber"]}"
end
end
def delay(delay_seconds)
m, s = delay_seconds.divmod(60)
h, m = m.divmod(60)
if delay_seconds >= 60
"#{m} min delay on "
elsif delay_seconds == 0
""
else
"#{s} sec delay on "
end
end
@jonoeoo
Copy link

jonoeoo commented Jul 15, 2015

Found a solution.
Easiest way is to add locations when defining the array

locations = [ { name: "Sam", location: URI::encode('-25.764803,28.34625') }, { name: "John", location: URI::encode('-25.764803,28.34625') }]

@mika4president
Copy link

mika4president commented Sep 26, 2016

Hi @jonoeoo,

Sorry to bother you but do you happen to know how to define this array? I'm new at ruby and am having trouble to implement this widget with more then one address, similiair like you.

I now have

locations       = []
locations << { name: "Same, location: URI::encode('52.37829,4.89983') }

Which works, but when I change that to

locations       = []
locations = [ { name: "Sam", location: URI::encode('-25.764803,28.34625') }, { name: "John", location: URI::encode('-25.764803,28.34625') }]

The widget doesn't show any traffic info anymore.
Could you help me with the proper syntax maybe?

Kind regards,

Michel

@karlashi
Copy link

karlashi commented Nov 2, 2016

@mika4president
maybe you already figured it out. This is the format I have it:
locations << { name: "xxx", location: URI::encode('45.7685623,-72.9380278') }
locations << { name: "yyy", location: URI::encode('45.728491,-72.859983') }

Each line is one person.

@titusece
Copy link

titusece commented Apr 4, 2017

Hello,

I'm also trying to work.
Its display empty.
Can you please help ?

require 'net/http'
require 'net/https'
require 'uri'
require 'json'

office_location = URI::encode('-26.116525,28.031015')
key = URI::encode('wD9DZdZbclVBtMMY')
#key = URI::encode('u3oMj4stA2SPyH4quz4Ahq5Q8VREK7mo')

#locations = []
#locations << { name: "Sam", location: URI::encode('-25.764803,28.34625') }

#locations << { name: "xxx", location: URI::encode('45.7685623,-72.9380278') }
#locations << { name: "yyy", location: URI::encode('45.728491,-72.859983') }

locations = []
locations << { name: "Same, location: URI::encode('52.37829,4.89983') }

SCHEDULER.every '10m', :first_in => '15s' do |job|
routes = []

# pull data
locations.each do |location|
    uri = URI.parse("https://api.tomtom.com/routing/1/calculateRoute/#{office_location}:#{location[:location]}/json?routeType=fastest&traffic=true&travelMode=car&key=#{key}")
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE

    request = Net::HTTP::Get.new(uri.request_uri)
    response = http.request(request)
    routes << { name: location[:name], location: location[:location], route: JSON.parse(response.body)["routes"][0] }
end

# find winner
if routes
    routes.sort! { |route1, route2| route2[:route]["summary"]["travelTimeInSeconds"] <=> route1[:route]["summary"]["travelTimeInSeconds"] }
    routes.map! do |r|
        { name: r[:name],
            time: seconds_in_words(r[:route]["summary"]["travelTimeInSeconds"].to_i),
            road: delay(r[:route]["summary"]["trafficDelayInSeconds"])}
    end
end

# send event

send_event('tomtom', { results: routes } )
end

def seconds_in_words(secs)
m, s = secs.divmod(60)
h, m = m.divmod(60)

plural_hours = if h > 1 then "s" else "" end
plural_minutes = if m > 1 then "s" else "" end

if secs >= 3600
    "#{h} hour#{plural_hours}, #{m} min#{plural_minutes}"
else
    "#{m} min#{plural_minutes}"
end

end

def delay(delay_seconds)
m, s = delay_seconds.divmod(60)
h, m = m.divmod(60)

if delay_seconds >= 60
    "#{m} min delay"
elsif delay_seconds == 0
    ""
else
    "#{s} sec delay"
end

end

Regards,
Titus S.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment