Driving Time and Distance using Waze [4.0.0.0;5.9.9.9]

This rule template uses the Waze RoutingManager API to query for and calculate the time and distance to drive between two points. My original idea for this template was to get an alert in the mornings so we know when to leave early because there’s yet another accident on the interstate.

The template has four properties:

  • starting coordinates in “lat,lon” format
  • ending coordinates in “lat,lon” format
  • Number:Time Item that will be updated with the current driving time
  • Number:Length Item that will be updated with the current driving distance

This rule template does not have any triggers or conditions. To avoid hammering the Waze servers this rule remains inert until you further add your own triggers and conditions. I recommend a polling period in minutes at the most and adding conditions so the rule does not run at times when it’s not needed.

If more than one route is desired, create multiple rules using this template, one for each route.

Language: JS Scripting

Dependencies:

  • JS Scripting add-on installed
  • Future versions may depend on OHRT

Changelog

Version 0.4

  • the region property had two options with the same mapping which caused problems, those two options were merged to avoid the problem

Version 0.3

  • changed to use Waze’s new URLs
  • minor changes to make URL generation based on region easier
  • moved code to github

Version 0.2

  • added property to choose region to avoid Internal Error problems for users outside the US
  • changed the logger name and added more logging at the debug and trace levels
  • added better error checking and reporting

Version 0.1

  • initial release

Resources

https://raw.githubusercontent.com/rkoshak/openhab-rules-tools/refs/heads/main/rule-templates/driveTime/driveTime.yaml

5 Likes

Hello everyone,

unfortunately this does not work for me, no matter whether I try from the rule or directly from a browser, the feedback is always.

My request looks like this

https://www.waze.com/RoutingManager/routingRequest?from=x%3A6.655048727989198+y%3A51.41853106532269+bd%3Atrue&to=x%3A6.735112667083741+y%3A51.131318036426684+bd%3Atrue&returnJSON=true&returnGeometries=true&returnInstructions=true&timeout=60000&nPaths=1
{"error": "Internal Error"}

Unfortunately this API is not well documented. I mostly figured it out by trail and error.

But I did discover there are different routing servers for different regions of the world in a python script (WazeRouteCalculator/WazeRouteCalculator/WazeRouteCalculator.py at master · kovacsbalu/WazeRouteCalculator · GitHub).

        'US': 'RoutingManager/routingRequest',
        'EU': 'row-RoutingManager/routingRequest',
        'IL': 'il-RoutingManager/routingRequest',
        'AU': 'row-RoutingManager/routingRequest'

Obviously that list is not comprehensive across the world, and I’m not sure what region IL is (Israel? Waze was founded as an Israeli company before being purchased by Google).

If you are in the EU try replacing `“RoutingManager/routingRequest” with “row-RoutingManager/routingRequest” in the URL and let me know if that works.

I’ll figure out how to make that part of the URL configurable through a property.

Hi @rlkoshak, thanks for the rule and your answer.
I am from Germany so EU, and yes with

 'EU': 'row-RoutingManager/routingRequest',

the rule works.

Perhaps an error query should be included if the rawJSON return value does not contain

{“response”:{“results”:[{"path”

Already does. A new version of the rule template is posted now which has a property to choose the region, logs out the raw JSON at the trace level, and logs our what;'s returned by the server if the parsed JSON doesn’t include what we expect.

I just got done testing it and verifying it works so remove your existing rule and template, add back the template and create a new rule. You should now have a property to choose the region which will change the URL of the request.

For an example of alerting when the travel time gets too long or a different route from usual is see below. I configured the rule template to only run every minute between 07:00 and 07:20.

items.School_CheckTime.postUpdate(time.toZDT());

var usualDistance = Quantity("17.6 mi");
var distanceBuffer = Quantity("0.5 mi");
var usualTime = Quantity("19.1 min");
var timeBuffer = Quantity("5 min");
var notificationId = "schoolDriveTime";

console.debug('Received travel info from Waze');

var arrivalTime = time.toZDT(items.School_TravelTime).toLocalTime();

function getTime(inst) {
  let hour = inst.hour();
  let meridian = "AM"
  if(hour == 12) meridian = 'PM';
  if(hour > 12) {
    hour -= 12;
    meridian = 'PM'
  }
  
  return hour + ":" + String(inst.minute()).padStart(2, '0') + " " + meridian;
}

// If route is more than distanceBuffer from the usual route
var differentRoute = items.School_TravelDistance.quantityState.subtract(usualDistance).greaterThan(distanceBuffer);
// If the travel time is more than timeBuffer from the usual route
var longerTime = items.School_TravelTime.quantityState.subtract(usualTime).greaterThan(timeBuffer);

var msg = "As of " + getTime(time.toZDT().toLocalTime());
if(differentRoute) msg += " a different route is suggested by Waze"
else msg += " the usual route is still the best"
msg += " to school and travel duration is " 
       + items.School_TravelTime.quantityState.toUnit("min").float.toPrecision(3)
       + " minutes for an arrival time of " + getTime(arrivalTime);

console.info(msg);
items.School_TravelMessage.postUpdate(msg);

if(differentRoute || longerTime) {
  actions.notificationBuilder(msg).addUserId('rlkoshak@gmail.com')
                                  .withTitle('Time to leave!')
                                  .withIcon('f7:car-fill')
                                  .withOnClickAction('app:android=com.waze') // untested
                                  .withReferenceId(notificationId)
                                  .send();
  cache.private.get(notificationId)?.cancel();
  cache.private.put(notificationId, actions.ScriptExecution.createTimer(ruleID, time.toZDT('PT10M'), () => {
    actions.notificationBuilder('cancel notification').withReferenceId(notificationId).hide().send();
    cache.private.remove(notificationId);
  }));
  actions.Voice.say(msg, null, "sink:id"); // all speakers group
}
else {
  cache.private.get(notificationId)?.cancel();
  actions.notificationBuilder('cancel notification').withReferenceId(notificationId).hide().send();
  cache.private.remove(notificationId);
}

The School_TravelMessage Item is a String Item I use with Embedded Waze Live Traffic Map Widget as the footer so I can see the travel time and the current traffic conditions in MainUI in the same widget. I use =items.Shcool_TravelMessage.state for the footer property of the widget.

Waze has changed its server addresses again. They are now:

    'US': 'https://routing-livemap-am.waze.com/RoutingManager/routingRequest'
    'EU': 'https://routing-livemap-row.waze.com/RoutingManager/routingRequest'
    'IL': 'https://routing-livemap-il.waze.com/RoutingManager/routingRequest'
    'AU': 'https://routing-livemap-row.waze.com/RoutingManager/routingRequest
1 Like

I’ll get an update posted later today. Thanks for the heads up!

Code has been fixed. It took a little longer because I needed to rework how the URL was generated based on regional settings.

Remove and re-add the template from the add-on store and then regenerate your rule(s) based on the template. Don’t forget to reselect your region when you regnerate becuase I changed what the options turn into meaning you must replace your current setting.

Thank you, @rlkoshak, for offering and updating the rule template. One question: On entering data, it allows region selection. “EU” cannot be chosen, selector instantly moves over to “AU”. Yet, it results in valid data. So is this move intended behaviour?
Found that “region” can be edited to “EU” in rule code afterwards.

It is not intended behavior, and it appears I can reproduce it so I should be able to fix it. Note you now have to be a little careful in how you set it in the code now. Rather than do this relatively complicated mapping between the selection and the actual value Waze uses for each region, I do the mapping in the selector. Both “EU” and “AU” map to row.

Note, editing the region in the configuration section on the code tab doesn’t actually do anything. When editing the region variable in the code of the script action you have to be careful to choose the correct value. For “EU” you need to enter “row”, not “EU”.

The fact that two values map to the same value might be the root of the problem.

For now, selecting either EU or AU will work so the fact that it selects AU when trying to select EU is startling but does not result in a broken rule. I’ll get an update posted once I figure out what the actual problem is.

Edit: New version has been posted.

Thank you again, also for the details regarding region selection. Reviewed the changed template, works well.