What did you build/automated today (with pictures)?

I’ll post another one to show that hardware doesn’t always have to be involved. Traffic in my area has grown worse and worse over the years I’ve lived here, and I have a ten-minute window in which to drop my kid off to school (7:50am to 8:00 am). Some mornings I’ll leave at 7:20 and we end up sitting at the school for ten minutes. Other mornings I’ll leave at the same time and the kid gets a tardy notice because there was an accident on the interstate.

My solution involves multiple parts.

  1. A rule to poll Waze’s API to get how long the drive is taking right now. You can find the rule as a rule template at Driving Time and Distance using Waze [4.0.0.0;5.9.9.9]. This will populate a Number:Time Item with the amount of time it’s expected to take to drive and a Number:Length Item for the distance. Why the distance? Because if the distance changes from normal, it means Waze is taking me a different route from normal which means traffic is really backed up, and I need to pay attention that I don’t just start heading for the interstate. Note that it’s up to you to set the rule triggers for this rule. Please do not hammer the Waze APIs unnecessarily. I have mine configured with a cron expression and rule conditions to only run once every five minutes between 6:45 and 7:30 on school days.

  2. I have a second rule that triggers when the time Item changes that waits until the arrival time is after 7:49 and sends a notification and a TTS announcement on the smart speakers. I’ve a further limit that it does not announce more than once every ten minutes which means right now it only announces once but when school starts up again I will play with that again.

configuration: {}
triggers:
  - id: "2"
    configuration:
      itemName: School_TravelTime
    type: core.ItemStateUpdateTrigger
conditions: []
actions:
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript
      script: >
        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;
        }


        var notificationId = "aaclDriveTime";


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


        var currArrivalTime = time.toZDT(items.School_TravelTime);
          
        // Update the item

        var msg = "As of " + getTime(time.toZDT()) + " if you leave for school
        now, you will arrive at " + getTime(currArrivalTime);

        items.School_TravelMessage.postUpdate(msg);


        var timeSinceLast =
        time.Duration.between(cache.private.get("lastReport", () =>
        time.toZDT().minusDays(1)), time.toZDT());

        console.debug("Time since last report is " + timeSinceLast);

        if(currArrivalTime.isAfter(time.toZDT("7:49 am")) &&
        timeSinceLast.compareTo(time.Duration.ofMinutes(10)) > 0) {
          console.info(msg);
          cache.private.put("lastReport", time.toZDT());

          // Announce it's time to leave
          actions.Voice.say(msg, null, "chromecast:audiogroup:21632c10-9553-4136-80c3-21202c34e900"); // all speakers group
          
          // Send the notification
          actions.notificationBuilder(msg).addUserId('rlkoshak@gmail.com')
                                          .withTitle('Time to leave!')
                                          .withIcon('f7:car-fill')
                                          .withOnClickAction('app:android=com.waze')
                                          .withReferenceId(notificationId)
                                          .send();
          
          cache.private.put("timer", actions.ScriptExecution.createTimer(time.toZDT("PT20M"), () => {
            actions.notificationBuilder('cancel notification').withReferenceId(notificationId).hide().send();
          }))
        }
    type: script.ScriptAction

  1. Finally, I’ve a widget that shows the current traffic conditions. It also shows a caption under the map which is the contents of that School_TravelMessage. This gets updated every time the travel time is calculated so I can visually check and quickly see what the commute is going to look like before the announcement.

Note the pin is roughly halfway between my home and the school to center the map where I can see the traffic over the roads I need.

This widget is on the marketplace at Embedded Waze Live Traffic Map Widget. There is also a Google Maps version at Embedded Google Maps Widget which is a good choice if you only care about the one route between two points instead of the general traffic conditions over an area. The Google Maps version requires a Google Developer account and API key. Waze’s API is open and doesn’t require anything.

With 1 through 3 combined I’m able to get a heads-up in the morning and easily check when I need to leave to arrive on time without it being annoying.

Sometimes it’s the little things like this that make all the difference.

9 Likes