Waze travel time update

i mean that you can use the code posted above as a custom_component, it has not been merged into the official release yet.

Petro’s reply in a different topic related to this:

if you place it in hass_loc/custom_components/sensor/ it will override it.

Heres a link to the source. Paste the code into a file named waze_travel_time.py in the directory above. Here’s a link to the code:

Hey guys, I updated the waze travel time sensor to handle device trackers, sensors, and zones. Take a look. Feedback is welcome. """ Support for Waze travel time sensor. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.waze_travel_time/ """ from datetime import timedelta import logging import requests import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ATT… 

I made a PR, so it should get into the regular HA build in the next release.

Ah, ok thank you!

1 Like

Perfect! thanks for the help and thanks too to @petro for doing this.

It all seems to work well (after the first few minutes at least!) except that I can confirm that it doesn’t seem to update when it first starts.

I’ll report back if I have any further feedback but thanks again.

Yeah, its not officially released. It’s sitting in the PR requests so it’s only a matter of time. Once that PR goes through, i’ll update it to report on startup.

This can be ignored, wazeroutecalculator does not like Pi-Hole.

Thanks,

I’m not a fan of wazeroutecalculator, but it’s what the original component writer used. There’s little to no configuration in that repo.

Hi, what region should I set if I’m from Chile / South America?

Or is it not supported? :sweat:

Have you tried NA? I didn’t write the WazeRouteCalculator which is a resource of this component. It looks like it only supports 3 regions; US, IL, and EU. The guy who made WazeRouteCalculator added NA which under the hood just flips it to US. US is basically NA. I may be able to update that calculator, but I don’t have control over it. I’ll see what can be done, but for the time being, try using NA or US. Let me know if that works.

Thanks for your reply.

I just tried that but I get the following error:
image

I tried it placing the GPS coordinates in origin and destination and i tried also putting the address of each one too. But I get the same error.

I’ll have to research it. I know exactly where to change it in the script. I was unable to find the correct code to supply the waze api for south america. They have to have it, I just need to find it. I’ll have some time next week to look around, but I may have to contact waze customer support for the info.

1 Like

Seems like this PR did not make it to 0.68 :frowning:

Do you have an update since the original that did not load on startup @petro ?

Please add a link if that’s something you recommend until the official waze sensor get’s this feature.

No, but i’ll start working on it. I was hoping it would make the update before I made changes. Looks like that won’t happen. I’ll update over the next few days

1 Like

Hi there’s, any news. :slight_smile:

Plus - a question:

You said polling happens every 5 minutes, but in the DB I see an update saved every 10 minutes - any idea why?

How can I control the time between polls in the config / code?

Thanks!

Yes, polling happens about every 5 minutes. If you want to change the interval, update this line of code:

SCAN_INTERVAL = timedelta(minutes=5)

It’s towards the top of the file.

I’ll let you know when I have an update. Haven’t had a chance to look at it yet.

1 Like

I’m wondering does this component supports other countries such as those in Asia?

It does not. I’ve been looking for a list of regions that the API supports but I cannot find one. I’m pretty sure that waze app on phones works in Asia. Once I find the region list, I can attempt to add support for the other area’s to the WazeRouteCalculator.py files.

1 Like

Give this a whirl and let me know if it updates immediately. The interval is still 5 minutes, i’m trying to have it match the google component.

"""
Support for Waze travel time sensor.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.waze_travel_time/
"""
from datetime import timedelta
import logging

import voluptuous as vol

from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
    ATTR_ATTRIBUTION, CONF_NAME, CONF_REGION, EVENT_HOMEASSISTANT_START,
    ATTR_LATITUDE, ATTR_LONGITUDE)
import homeassistant.helpers.config_validation as cv
import homeassistant.helpers.location as location
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle

REQUIREMENTS = ['WazeRouteCalculator==0.5']

_LOGGER = logging.getLogger(__name__)

ATTR_DURATION = 'duration'
ATTR_DISTANCE = 'distance'
ATTR_ROUTE = 'route'

CONF_ATTRIBUTION = "Data provided by the Waze.com"
CONF_DESTINATION = 'destination'
CONF_ORIGIN = 'origin'

DEFAULT_NAME = 'Waze Travel Time'

ICON = 'mdi:car'

REGIONS = ['US', 'NA', 'EU', 'IL']

SCAN_INTERVAL = timedelta(minutes=5)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_ORIGIN): cv.string,
    vol.Required(CONF_DESTINATION): cv.string,
    vol.Required(CONF_REGION): vol.In(REGIONS),
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})

TRACKABLE_DOMAINS = ['device_tracker', 'sensor', 'zone']


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Waze travel time sensor platform."""
    def run_setup(event):
        destination = config.get(CONF_DESTINATION)
        name = config.get(CONF_NAME)
        origin = config.get(CONF_ORIGIN)
        region = config.get(CONF_REGION)

        sensor = WazeTravelTime(hass, name, origin, destination, region)
        add_devices([sensor])

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, run_setup)


class WazeTravelTime(Entity):
    """Representation of a Waze travel time sensor."""

    def __init__(self, hass, name, origin, destination, region):
        """Initialize the Waze travel time sensor."""
        self._hass = hass
        self._name = name
        self._region = region
        self._state = None

        if origin.split('.', 1)[0] in TRACKABLE_DOMAINS:
            self._origin_entity_id = origin
        else:
            self._origin = origin

        if destination.split('.', 1)[0] in TRACKABLE_DOMAINS:
            self._destination_entity_id = destination
        else:
            self._destination = destination

        self._update()

    @property
    def name(self):
        """Return the name of the sensor."""
        return self._name

    @property
    def state(self):
        """Return the state of the sensor."""
        if self._state is None:
            return None

        if 'duration' in self._state:
            return round(self._state['duration'])
        return None

    @property
    def unit_of_measurement(self):
        """Return the unit of measurement."""
        return 'min'

    @property
    def icon(self):
        """Icon to use in the frontend, if any."""
        return ICON

    @property
    def device_state_attributes(self):
        """Return the state attributes of the last update."""
        if self._state is None:
            return None

        res = {ATTR_ATTRIBUTION: CONF_ATTRIBUTION}
        if 'duration' in self._state:
            res[ATTR_DURATION] = self._state['duration']
        if 'distance' in self._state:
            res[ATTR_DISTANCE] = self._state['distance']
        if 'route' in self._state:
            res[ATTR_ROUTE] = self._state['route']
        return res

    def _get_location_from_entity(self, entity_id):
        """Get the location from the entity state or attributes."""
        entity = self._hass.states.get(entity_id)

        if entity is None:
            _LOGGER.error("Unable to find entity %s", entity_id)
            return None

        # Check if the entity has location attributes (zone)
        if location.has_location(entity):
            return self._get_location_from_attributes(entity)

        # Check if device is in a zone (device_tracker)
        zone_entity = self._hass.states.get("zone.%s" % entity.state)
        if location.has_location(zone_entity):
            _LOGGER.debug(
                "%s is in %s, getting zone location",
                entity_id, zone_entity.entity_id
            )
            return self._get_location_from_attributes(zone_entity)

        # If zone was not found in state then use the state as the location
        if entity_id.startswith("sensor."):
            return entity.state

        # When everything fails just return nothing
        return None

    @staticmethod
    def _get_location_from_attributes(entity):
        """Get the lat/long string from an entities attributes."""
        attr = entity.attributes
        return "{},{}".format(attr.get(ATTR_LATITUDE), attr.get(ATTR_LONGITUDE))

    def _resolve_zone(self, friendly_name):
        entities = self._hass.states.all()
        for entity in entities:
            if entity.domain == 'zone' and entity.name == friendly_name:
                return self._get_location_from_attributes(entity)

        return friendly_name

    @Throttle(SCAN_INTERVAL)
    def update(self):
        self._update()

    def _update(self):
        """Fetch new state data for the sensor."""
        import WazeRouteCalculator

        if hasattr(self, '_origin_entity_id'):
            self._origin = self._get_location_from_entity(
                self._origin_entity_id
            )

        if hasattr(self, '_destination_entity_id'):
            self._destination = self._get_location_from_entity(
                self._destination_entity_id
            )

        self._destination = self._resolve_zone(self._destination)
        self._origin = self._resolve_zone(self._origin)

        if self._destination is not None and self._origin is not None:
            try:
                params = WazeRouteCalculator.WazeRouteCalculator(
                    self._origin, self._destination, self._region)
                routes = params.calc_all_routes_info()
                route = next(iter(routes))
                duration, distance = routes[route]
                route = bytes(route, 'ISO-8859-1').decode('UTF-8')
                self._state = {
                    'duration': duration,
                    'distance': distance,
                    'route': route}
            except WazeRouteCalculator.WRCError as exp:
                _LOGGER.error("Error on retrieving data: %s", exp)
                return
            except KeyError:
                _LOGGER.error("Error retrieving data from server")
                return

I have 4 Waze sensors setup

with the new code I see one updating immediately after HA launch complete (random - not the same sensor on each load) ** for the rest I see 3 * the following error in the log** (one per sensor):

2018-05-04 09:15:57 ERROR (MainThread) [homeassistant.core] Error doing job: Future exception was never retrieved
Traceback (most recent call last):
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/sensor/waze_travel_time.py", line 59, in run_setup
    sensor = WazeTravelTime(hass, name, origin, destination, region)
  File "/config/custom_components/sensor/waze_travel_time.py", line 85, in __init__
    self._update()
  File "/config/custom_components/sensor/waze_travel_time.py", line 194, in _update
    routes = params.calc_all_routes_info()
  File "/usr/lib/python3.6/site-packages/WazeRouteCalculator/WazeRouteCalculator.py", line 142, in calc_all_routes_info
    routes = self.get_route(npaths, time_delta)
  File "/usr/lib/python3.6/site-packages/WazeRouteCalculator/WazeRouteCalculator.py", line 92, in get_route
    response_json = response.json()
  File "/usr/lib/python3.6/site-packages/requests/models.py", line 892, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/lib/python3.6/site-packages/simplejson/__init__.py", line 518, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.6/site-packages/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/usr/lib/python3.6/site-packages/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.errors.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Okay. That’s odd because I didn’t change anything related to the calculator. I’ll have to see what the initial update is doing because it seems like that is causing the problem. Maybe during startup the devices aren’t initialized yet. I’ll take a look tonight.

what 4 waze sensors do you have setup? I’ve been running this with a 1 minute update (and it loads on startup) without errors for 3 days using 4 sensors: lat/long, device_trackers, zones, and a sensor. Can you link your configuration so I can mimic it?