I have built a component that uses OpenStreetMaps to provide reverse geocode lookups and gather some other data that I am finding pretty useful.
Apart from the usual reverse lookup ‘place’ information, the sensor will also calculate the users “distance from home” and their current “direction of travel” as either “towards home”, “away from home” or “stationary”. Each user being tracked can have their “home” set to be a different zone (which is necessary for a distributed family). The sensor also generates a URL for Apple Maps or Google Maps that can be attached to a notification and provide a clickable link to see where the user currently is. The component also doesn’t only rely on polling for it’s updates. It subscribes to DeviceTracker state change events and it generates it’s own update event with trigger data containing attributes essential to constructing a good notification.
It was my first python project and unfortunately it does not conform to the guidelines required to submit it for inclusion in the product - but it works well (for me) as a custom component, so I thought I’d share it here in case others also can find a use for it. I spent about 2.5 months developing, testing, tweaking and extending it - then I’ve spent the last 30+ days testing it without any tweaks, so I guess it’s as ready to share as it will ever be.
To use it, you provide a name and a device tracker entity. There are a bunch of other optional things you can provide to enable different behaviors. The documentation is built into the .py script and in the readme on GitHub.
The readme on Github also has examples of how to create automations that sends notifications for a single user and for all users.
I know that there are a couple of other similar sensors out there - but they didn’t do exactly what I needed when I needed it - so I decided to go the route of creating my own. Hope someone out there finds this one useful.
I tried ths and so far it works great. Would it be possible to make it so that the order of the values for the options is respected when constructing the sensor’s value?
At the moment this is my configuration:
- platform: places
name: Geocode Location
devicetracker_id: device_tracker.owntracks
options: street, street_number, postal_code, city, country
display_zone: show
map_provider: apple
map_zoom: 19
home_zone: zone.home
api_key: !secret openstreetmap_api_key
But the street number is written first and only then the street name. In Belgium the street name is put in front of the street number when constructing an address.
I’ve modified the component to do what you’ve asked. I just want to test it for a day before I release it - to make sure it acts the way it should. I’ll probably upload it to the Github repository tomorrow afternoon if everything works as it should.
I also want to point out that - if the component detects that the user is inside a defined ZONE (ie: zone.home, zone.work, zone.cottage, etc) - it doesn’t display any of the detailed information specified in the options list. It just displays the Zone name and the " (since hh:mm)" timestamp.
The detailed “place” information is only displayed when a device is outside of defined Zone (ie: devicetracker’s zone = ‘not_home’)
This makes sense to me since you obviously already know everything about the Zone or you wouldn’t have defined it and set it up to be a Zone. I just wanted to make sure this was clear to everyone who tries out the component. If they’re inside zone.home when they first enable the component - they may think it’s not working because it just displays the Zone name. They can tell it’s working if it has the " (since hh:mm)" suffix after the zone name.
I’ve added the changes you requested. Let me know if you have any other problems or suggestions!
Here are the comments for the new version:
20180509 - Updated to support new option value of "do_not_reorder" to disable the automatic ordered display of any specified options
- If "do_not_reorder" appears anywhere in the list of comma delimited options, the state display will be built
using the order of options as they are specified in the options config value.
ie: options: street, street_number, do_not_reorder, postal_code, city, country
will result in a state comprised of:
<street>, <street_number>, <postal_code>, <city>, <country>
without the "do_not_reorder" option, it would be:
<street_number>, <street>, <postal_code>, <city>, <country>
- The following attributes can be specified in any order for building the display string manually:
- do_not_reorder
- place_type, place_name, place_category, place_neighbourhood, street_number, street, city,
- postal_town, state, region, county, country, postal_code, formatted_address
Notes: All options must be specified in lower case.
State and Region return the same data (so only use one of them).
- Also added 'options' to the attribute list that gets populated by this sensor (to make it easier to see why a specific state is being generated)
Thank you very much for the changes. When I try the new version, I receive the following error message:
Update for sensor.geocode_location_osm fails
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 204, in async_update_ha_state
yield from self.async_device_update()
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 327, in async_device_update
yield from self.hass.async_add_job(self.update)
File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.6/site-packages/homeassistant/util/__init__.py", line 319, in wrapper
result = method(*args, **kwargs)
File "/home/homeassistant/.homeassistant/custom_components/sensor/places.py", line 431, in update
self.do_update("Scan Interval")
File "/home/homeassistant/.homeassistant/custom_components/sensor/places.py", line 665, in do_update
display_options.remove("do_not_reorder")
AttributeError: 'str' object has no attribute 'remove'
I used the example from your documentation for the options
options: street, street_number, do_not_reorder, postal_code, city, country
Your update solved the issue. I am however now facing another error:
2018-05-28 23:56:09 ERROR (MainThread) [homeassistant.helpers.entity] Update for sensor.geocode_location fails
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 204, in async_update_ha_state
yield from self.async_device_update()
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 327, in async_device_update
yield from self.hass.async_add_job(self.update)
File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.6/site-packages/homeassistant/util/__init__.py", line 319, in wrapper
result = method(*args, **kwargs)
File "/home/homeassistant/.homeassistant/custom_components/sensor/places.py", line 432, in update
self.do_update("Scan Interval")
File "/home/homeassistant/.homeassistant/custom_components/sensor/places.py", line 676, in do_update
user_display.append(targetoption)
NameError: name 'targetoption' is not defined
When I have a look at line 676 I see the following:
if option in locals():
user_display.append(targetoption)
Whereas line 674 uses target_option. When I change line 676 this does however throw another error.
Update for sensor.geocode_location fails
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 197, in async_update_ha_state
yield from self.async_device_update()
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 320, in async_device_update
yield from self.hass.async_add_job(self.update)
File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.6/site-packages/homeassistant/util/__init__.py", line 319, in wrapper
result = method(*args, **kwargs)
File "/home/homeassistant/.homeassistant/custom_components/sensor/places.py", line 432, in update
self.do_update("Scan Interval")
File "/home/homeassistant/.homeassistant/custom_components/sensor/places.py", line 462, in do_update
distance_m = distance(float(new_latitude), float(new_longitude), float(home_latitude), float(home_longitude))
ValueError: could not convert string to float: 'None'
For some reason, I’m not getting form notifications when @geoffrey posts - but I got yours today @ravensteijn .
I’ve been working on developing an iOS app and haven’t been doing much with HomeAssistant for the last two months so I haven’t been very active on the forums. I am still running on 0.65.3 (upgrading now) and I don’t see the error in my log files. Did this error begin occurring in conjunction with a version upgrade?
I looked at the code in question and I would ask you to check the values you have for the following:
Specifically, my guess is that your devicetracker (for some reason) doesn’t have a latitude and/or longitude. I’ll look at my log files again after my version upgrade completes to see if I have the error you guys are seeing. If I do, then it might be something version specific that I’ll need to track down.
Until then - please let me know if you did in fact have values for your devicetracker entity latitude and longitude (did the attribute names change?) and/or if there might have been an error with the places component prior to this one.
I added it again to the configurator.yaml file and it’s working now, after a few minutes waiting.
i’m feeling a bit ashamed because i changed 1 thing. I made an account at www.openstreetmap.org
I think it’s mandatory to get this API call working? Am i correct?
Not unless they’ve changed their policy since April…
Their API allowed completely anonymous access, but they requested that you include your email address in the APIKey field so that they would be able to contact you if they needed to - or to explain that they’ve had to throttle your requests because they were above some “non-published threshold” level.
I am tracking 3 family members, and for each one, I configured it to use the family members email address as the apikey value. I have never had requests rejected nor received any emails from openstreetmap.org
To be honest, now that google requires an account and form of payment for their service, I’m not sure why more people aren’t using my component simply to avoid having to register with Google. Google does provide a $200 credit each month which is enough to cover most people’s usage - but it still seems like a hassle to have to sign up for the apikey.
Glad it’s working for you now. Let me know if you experience any other problems.
I’m trying to integrate this into HA however the log indicates that cannot find the sensor. Here is what I have done:
Created a folder custom_components/sensors in the folder in which my configuration.yaml resides.
Place a copy of places.py within the custom_components/sensors folder
Edited configuration.yaml to include the following:
sensor_places_alan:
name: alan
devicetrackerid: device_tracker.iphone_
options: zone, street, city
display_zone: show
map_provider: google
map_zoom: 18
home_zone: zone.alan_home
api_key: !secret email_alan
I have all my sensors in a sensors.yaml file which I include from configuration.yaml with the following line:
sensor: !include sensors.yaml
Inside my sensors.yaml file, I have the following configuration for the “places” component:
- platform: places
name: jim
devicetracker_id: device_tracker.jim_iphone8plus
options: zone,place
display_zone: show
map_provider: google
map_zoom: 19
home_zone: zone.jim_home
api_key: !secret email_jim
There is nothing in your configuration that says to use the “places” component. It looks like you’ve tried to name it twice - once as “sensor_places_alan” and again as just “alan”.
If you’re configuring your sensors within your configuration.yaml, try something like this:
Sample Configuration.yaml configurations:
sensor places_jim:
- platform: places
name: jim
devicetracker_id: device_tracker.jim_iphone8
options: zone,place
display_zone: show
map_provider: google
map_zoom: 19
home_zone: zone.jim_home
api_key: !secret email_jim
sensor places_sharon:
- platform: places
name: sharon
devicetracker_id: device_tracker.sharon_iphone7
options: zone, place
map_provider: apple
map_zoom: 18
home_zone: zone.sharon_home
api_key: !secret email_sharon
Sorry for the delayed reply - I didn’t see your post until just today.
Which timestamp are you referring to? I’m in EST and all of the times I see appear to be local time. Is it possible that you didn’t correctly set the timezone on the computer you are using to run HomeAssistant?