Google Maps widget with traffic

widgetgallery
googlemaps
Tags: #<Tag:0x00007fe054c8d4a8> #<Tag:0x00007fe054c8d2a0>

(Mr. Yoinkz) #41

Hey Daniel,

I got 6 lines of code and yesterday i changed the update interval from 6000 to 300000, but that was after I got the exceeded error.

Him Distance
Him Normal travel time
Him Traffic travel time
Her Distance
Her Normal travel time
Her Traffic travel time.


(Daniel Walters) #42

There are a couple of ways but here’s one (typed from memory so may be small issues/typos)

googlemaps.items

Number	GoogleMaps_me_distance			(gGoogleMaps)	
Number	GoogleMaps_me_duration			(gGoogleMaps)	
Number	GoogleMaps_me_duration_traffic	(gGoogleMaps)	
String	GoogleMaps_me						(gGoogleMaps)	{ http="<[https://maps.googleapis.com/maps/api/distancematrix/json?origins=Amsterdam&destinations=Rotterdam&language=NL&departure_time=now&traffic_model=best_guess&mode=driving&key=YOUR_API_KEY:60000:default]" }

Number	GoogleMaps_wife_distance			(gGoogleMaps)
Number	GoogleMaps_wife_duration			(gGoogleMaps)
Number	GoogleMaps_wife_duration_traffic	(gGoogleMaps)
String	GoogleMaps_wife					(gGoogleMaps)	{ http="<[https://maps.googleapis.com/maps/api/distancematrix/json?origins=Amsterdam&destinations=Haarlem&language=NL&departure_time=now&traffic_model=best_guess&mode=driving&key=YOUR_API_KEY:60000:default]" }

I would then have two rules:

googlemaps.rules

rule "google maps - me"
when 
Item GoogleMaps_me received update
then
var String json = GoogleMaps_me.state.toString
var distance = transform("JSONPATH","$.rows[0].elements[0].distance.text",json )
var duration = transform("JSONPATH","$.rows[0].elements[0].duration.text",json )
var duration_traffic = transform("JSONPATH","$.rows[0].elements[0].duration_in_traffic.text",json )
GoogleMaps_me_distance.sendUpdate(distance)
GoogleMaps_me_duration.sendUpdate(duration)
GoogleMaps_me_duration_traffic.sendUpdate(duration_traffic)
end

rule "google maps - wife"
when 
Item GoogleMaps_wife received update
then
var String json = GoogleMaps_wife.state.toString
var distance = transform("JSONPATH","$.rows[0].elements[0].distance.text",json )
var duration = transform("JSONPATH","$.rows[0].elements[0].duration.text",json )
var duration_traffic = transform("JSONPATH","$.rows[0].elements[0].duration_in_traffic.text",json )
GoogleMaps_wife_distance.sendUpdate(distance)
GoogleMaps_wife_duration.sendUpdate(duration)
GoogleMaps_wife_duration_traffic.sendUpdate(duration_traffic)
end

An alternative would be to keep the HTTP binding definitions as they are and utilise the request caching function.


(Jörg Lemmer) #43

Great Job! This helps a lot. My wife has three branch offices she has to visit regulary, and I have to travel to my company at least once a week. All destinations are along the A2 Autobahn in Germany which is always congested. Now I set up a panel with the route and time for each location with this widget.

But “getting hungry while eating” I thought about a rule that will give a warning (sending an e.mail) when the actual time for a route exceeds a given time. I read the Google documentation of the JSON, but I am obviously not experienced enough to understand how to get the duration in a “calcuable” Format:
{
“status”: “OK”,
“duration”: {
“value”: 24487,
“text”: “6 heures 48 minutes”
},

I am looking for something like:

If GoogleMaps_me_duration_traffic > “130 minutes” then …

Any idea?

I could then combine this in a rule that uses the typical day of the week for our trips, calculate back from our typical needed time of Arrival to see if it is time to start earlier than normal.


(Daniel Walters) #44

Why can’t you reuse the above item definitions and then do exactly as you suggested?

rule "travel alert"
when
  Item GoogleMaps_me_duration_traffic changed
then
 if (GoogleMaps_me_duration.state > 130) {
   // send email alert
 }
end

(Jörg Lemmer) #45

May be me thoughts are to complicated, but looking at the json, the value did not look like a time in minutes, and the formatted string did not look usable, too.

I tried your example rule never the less, but it does not work.

rule "gifhorn>60_Minuten"
when
    Item GoogleMaps_gifhorn_duration_traffic changed
then
    if (GoogleMaps_gifhorn_duration_traffic.state > 60) {
        sendMail("xxx@yyy.de", "Fahrzeit Gifhorn > 1h", "Fahrzeit Gifhorn > 1h")
    }
end

I think I need the GoogleMaps_gifhorn_duration_traffic.state instead of the GoogleMaps_gifhorn_duration.state, as I want to use the duration with the actual traffic situation. So this is a change to your code. But although I had several situations yesterday and today that show up in the log with a duration of more than 60 minutes like these:

2018-03-07 08:05:45.716 [vent.ItemStateChangedEvent] - GoogleMaps_gifhorn_duration_traffic changed from 1 Stunde, 3 Minuten to 1 Stunde, 1 Minute

2018-03-07 08:10:47.088 [vent.ItemStateChangedEvent] - GoogleMaps_gifhorn_duration_traffic changed from 1 Stunde, 1 Minute to 1 Stunde, 2 Minuten

2018-03-07 08:20:50.032 [vent.ItemStateChangedEvent] - GoogleMaps_gifhorn_duration_traffic changed from 1 Stunde, 2 Minuten to 1 Stunde, 1 Minute

2018-03-07 08:30:52.502 [vent.ItemStateChangedEvent] - GoogleMaps_gifhorn_duration_traffic changed from 1 Stunde, 1 Minute to 1 Stunde, 0 Minuten

I did not get any mails.


(Bastiaan van Haastrecht) #46

Thanks @danielwalters86, I have update the first post so readers can choose.


(Daniel Walters) #47

The “value” 24487 is the time in seconds. So you will want to divide the “value” in the JSON by 60 if you want minutes.


(Daniel Walters) #48

Thanks @bastiaan_van_h and thank you for your work.

I also noticed that using the map.html in HABpanel dashboard exhausted my Google Maps quota. Having looking a the javascript code I noticed that it refreshes every 10 seconds.

window.setInterval(function(){
        			console.log("Updating Google Maps traffic and travel time");
        			reloadTiles();
        			if (gm_travel == 'true') {
        				calculateAndDisplayRoute();
        			}			
}, 10000);

A call every 10 seconds = 6 per minute = 360 per hour = 8640 per day.


(Jörg Lemmer) #49

Ups, I must have calulated something stupid then, when trying to identify the value. You are absolutely right, it is a value in seconds. But for the code in the rule this would mean, that I should have gotten an E-Mail with every change, as all values are above one minute (instead of one hour as intended) then. But I did not get any at all.

So there must be another problem above seconds instead of minutes.


(Jörg Lemmer) #50

Getting the most actual values always sounds great, but here I think it is worth to take in mind, that a delay of several minutes (something above statistical noise) needs exactly this time to happen. There cannot be a relevant new delay of several minutes between a reading now and a reading in ten seconds.

Therefor I use a five minutes interval instead of a ten second intervall. As I now monitor three routes I have not seen any bigger difference between two readings than two minutes. And that is still statistical noise. So I do not see that there would be any use in a ten second intervall, and that there really could be a problem with an Intervall that does not exceed the daily quota.


(Daniel Walters) #51

This looks like your item is a String, not a number. I would need to see the rest of your log to confirm but I would imagine that checking your String is greater than 60 would either error, or give you an unexpected result.

The above issue aside, the rule would send an email every time the the duration changed but was above 60minutes. You may end up with several consecutive emails alerting you to the traffic so you may want to factor in some proxy item or some kind repetition restriction.


(Jörg Lemmer) #52

Thas was my initial question/concern when asking for a calculatable value :wink: The log does not show anything else than the already cited messages of the changing time with the full formatted text hours/minutes. So no errors on type mismatches.

The item is generated by the frist defintion that given here this way:

String	GoogleMaps_gifhorn_duration_traffic		"Duration [%s]"		(gGoogleMaps)	{ http="<[https://maps.googleapis.com/maps/api/distancematrix/json?origins=Langenhagen&destinations=Gifhorn&language=DE&departure_time=now&traffic_model=best_guess&mode=driving&key=mykey:300000:JSONPATH($.rows[0].elements[0].duration_in_traffic.text)]" }

But I think I now found the solution by myself: As this definition generates a String from JSONPATH($.rows[0].elements[0].duration_in_traffic.text) I tried to define a number and went back to the JSON defintion that has a string and a value line. So I tried to define an item like this

Number  GoogleMaps_gifhorn_duration_traffic_time "Duration [%d]"    (gGoogleMaps)   { http="<[https://maps.googleapis.com/maps/api/distancematrix/json?origins=Langenhagen&destinations=Gifhorn&language=DE&departure_time=now&traffic_model=best_guess&mode=driving&key=mykey:300000:JSONPATH($.rows[0].elements[0].duration_in_traffic.value)]" }

And this item has the duration in seconds so that I can make calculations with it.

The rule up to now is just sort of a PoC and as it works now, it really generates a lot of mails.

So the next challenge would be something like:

var mail=false
if day_of_week=Wednesday and actual_time > 07:30 and actual_time < 10:30 and actual_time + duration_in_seconds > planned_arrival_time and mail=false
send E-Mail
mail=true

This would mean, that I would get just one mail on wednesday mornings when it is time to leave to arrive in time.


(Daniel Walters) #53

Sorry for confusion - I’ve updated my post to indicate the the values should indeed be Numbers.

However I’m glad to see you have made good progress now!


(Christian) #54

me too. The frame just displays the first HABpanel dashboard.

I there any input/solution?

EDIT:
This issue is solved. I fogot to edit the parameters directly in widget placed on a dashboard…


(Bastiaan van Haastrecht) #55

Do you have the same when the widget is placed on a dashboard?


(Robin) #57

Hi Guys! Great plugin, however I get the error:

Directions request failed due to NOT_FOUND

everytime I start it up.
I googled this Error msg and found that it is caused bye the maps API not knowing the Start and End Location. However, this also happens if I try any locations (like generic “Berlin” to “Hamburg”)

Any Idea?

edit: I figured it out!

  1. I should not set a zoom level :slight_smile: if i want distances
  2. Seems like you dont support german letters: ä;ö;ü (Köln) for example does not work!
  3. MOST IMPORTANT: You dont support “ß” - common in “Straße” which… you guessed right, translates to “Street” :smiley:
    Example locations that do not work:
    “Von-Werth-Straße+240,+50259+Pulheim”
    “Anystreet, Köln”

(charlie) #58

Hi sceppi!

Can you give me your full entry in “Server Path” at the configuration panel?

My issue: I can not reach my map.html !

What I`ve done:

  • http-binding installed DONE
  • map.html copied to /etc/openhab2/html/google-maps/ DONE
  • switched to local config > delete browser cache > changed back to server config DONE

I’m using openHABIAN openHAB 2.2.0-1 (Release Build)

Thx
Charlie


(sceppi) #59

Can you give me your full entry in “Server Path” at the configuration panel?

/static/google-maps/map.html


(zolakk) #60

Nice work! This is going to go well with the Alexa control binding in development (here) to also yell at me if my estimated commute is running long :slight_smile:


(Nicke) #61

Use GPS coordinates instead.

example:
https://maps.googleapis.com/maps/api/distancematrix/json?origins=50.964546,6.7974744&destinations=50.9562823,6.7803137&language=SE&departure_time=now&traffic_model=best_guess&mode=driving&key=YOURAPIKEY