Introduction
For my home automation, I have been using HomeAssistant for a long time. Once a friend asked me, saying, why does HomeAssistant have the ability to indicate only the current position of the tracker on the map, but you cannot display the entire route? Since then, this idea captured me. And once I realized that I myself really want to have this function right now. Anyone who cares what came of it, welcome under the cat…
Intelligence service
Actually, to display the route you need to have a set of points with coordinates, so the first step was to find out where HomeAssistant stores the necessary data (if it stores at all) and how to get it from there. A brief study of the original source immediately led to a solution: the included recorder module is needed to record the states of the necessary sensors in the database at different points in time, as well as the history module, which allows you to receive data from the database in a beautiful way. The history module has a well-documented
REST API . Exactly what is needed!
Next, you need to somehow display the data on the map. There are many different services that allow you to display the history of movements. I’ve probably tried far from all of them, but I’ll allow myself a few words about what I’ve tested:
A. yandex and google. Actually, for my needs there is everything and even more, but due to paid services and strong limitations of free versions, they did not suit me right away. Yandex, for example, allows free use only for open source projects (that is, anyone should be able to open your resource and take advantage of its capabilities at any time), not to mention other limitations in the number of requests. Only lazy didn’t write about changes in Google’s api policy. At the moment, as I understand it, each request to maps api or directions api is paid, the more requests - the cheaper. However, each user with a bank card connected to the account is given a free limit of $ 200 per month. Everything on top is immediately paid from your card. Linking a card to an account is not our way.
Correct, if I made a mistake somewhere about google and / or yandex.
')
B. A bunch of
OpenRouteService and OpenRouteService maps. In principle, the possibilities are not much different from google or yandex (in any case, I did not notice). Completely free (there are restrictions on the number of requests per day and per minute, above which it is advised to contact support ... there is no description of any paid tariffs at all). However, the use of the OpenRouteService maps resource turned out to be inconvenient (long application loading and annoying wide menu on the left, which opens by default and is not disabled by API, besides, the service does not open correctly from mobile devices). To be fair, OpenRouteService maps can be put on your server and it is quite possible that it is allowed to configure everything for yourself.
C. Mapbbcode . I stumbled upon an interesting implementation of maps in a simple format. In principle, the project is absolutely suitable for my task, but from this article I learned about
Leaflet and decided to turn to the original source. I finally stopped on it ...
G. Leaflet. Very good open-source js library for maps, easy to learn and well documented. From chips: allows you to use tiles from many services (openstreetmaps, yandex, google, mapbox, microsoft, etc., etc.). Additionally, I used the
leaflet.polylineDecorator plugin to indicate the direction of movement on the map.
It is worth mentioning that the last two considered resources do not support “routes”, that is, they do not know how to connect points along existing roads and / or sidewalks, but simply connect points with a straight line. For me personally, this is not a problem, but a deliberate step. If you just need to navigate the roads, then you need to look towards the paid google, yandex or free openrouteservice.
Implementation
The request to the history module through the REST-API is quite simple (hereinafter, the code will be in the HomeAssistant language, i.e. python) and allows you to get an answer in the form of easy-to-understand JSON:
response = requests.get(self._haddr + '/api/history/period/' + dayBegin + '?filter_entity_id=' + self._myid, headers={'Authorization': 'Bearer ' + self._token, 'content-type': 'application/json'}) data = response.json()[0]
here self._haddr is the address of your HA the same as specified in the frontend settings, self._myid is the device_tracker device id whose route we will build, dayBegin is the beginning of the period for displaying the route, I chose the beginning of the current day by default, self._token is a long-life token for accessing the api, which can be obtained from the HomeAssistant interface.
When the object whose history we are trying to display on the map is stationary for a long time or moves extremely slowly, we will get a bunch of points closely spaced and clogging the map. To correct the situation, let us pass the resulting array of coordinates through the filter: if the distance between the previous point and the next is less than 100 meters, then do not display the point on the map. To calculate the distances between two neighboring points, we use a simplified formula with
equiangular approximation . The approximation is applicable when the distance between adjacent points does not exceed a few km:
def getDistance(self, latA, lonA, latB, lonB): dst = 0 latRadA = math.radians(latA) lonRadA = math.radians(lonA) latRadB = math.radians(latB) lonRadB = math.radians(lonB) x = latRadB - latRadA y = (lonRadB-lonRadA)*math.cos((latRadB+latRadA)*0.5) dst = 6371*math.sqrt(x*x+y*y) return dst
Here dst distance in km.
Describe the Leaflet API here does not see the point. Behind this - on the
official site . The module works as follows: Every n seconds (I have been set to 300), a request is made to the current history of the object of interest to me. The resulting array of coordinates is run through the distance filter, reducing the number of points. Further, in the folder with the HomeAssistant configuration, 2 files are created in the www folder: index.html and route.html. The route.html file contains all the logic for creating a map. And the index.html file is a lifehack warning of page caching. By default, HomeAssistant caches everything that is possible, and only resetting the cache helped to update the data on the card, which, of course, is unacceptable. In the index.html file, the contents of route.html are invoked, however, with a randomly dynamically generated parameter that allows you to always request the current version of the route.html file from the server:
src = 'route.html?datetime=' + (new Date()).getTime() + Math.floor(Math.random() * 1000000)
Little security
HomeAssistant is designed so that all files within the www directory are public, that is, any file within the www directory can be opened in any browser without any authorization, knowing the direct link. In the case of my module, this link is:
your_address_homeassistant / local / route / index.html . If this is not critical for you, you can skip this section. I went a little further and screwed the authorization to the page with routes. For this, I used nginx (you can choose another web server with support for reverse proxy) as a proxy server. The HomeAssistant website has official
instructions for setting up this configuration. After setting up the proxy and checking the operation in the nginx configuration, you need to add authorization for the necessary pages:
location /local/route/route.html { proxy_pass http://localhost:8123/local/route/route.html; proxy_set_header Host $host; proxy_redirect http:// https://; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; auth_basic "Unauthorized"; auth_basic_user_file /etc/nginx/.htpasswd; }
Then create the file "/etc/nginx/.htpasswd", and in the console execute the following commands in sequence:
sh -c "echo -n 'admin:' >> /etc/nginx/.htpasswd" sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"
admin - replace with the desired login.
After that, we restart nginx and check: when trying to open a page with a route, the browser must request a login and password. I note that this is a separate authorization, not related to the authorization of the HomeAssistant itself.
Conclusion
Perhaps all that you can tell about this module.
Anyone interested,
here is the link to the module. The file should be located along the path: config_folder_homeassistant / custom_components / route / sensor.py, do not forget about the rights.
If it does not exist, create the folder config_folder_homeassistant / www and grant the corresponding rights to it.
Register the following lines in the configuration.yaml configuration file:
sensor: - platform: route name: route entityid: your_device_tracker_entity_id haddr: your_address_homeassistant token: your_long_life_token
here your_device_tracker_entity_id is the ID of your device device_tracker, your_address_homeassistant is the external address of your HomeAssistant, your_long_life_token is the access token previously received in the frontend of HomeAssistant to use REST API.
After that, restart HomeAssistant and enjoy. The map will be available through a direct link:
your_address_homeassistant / local / route / index.html . If you wish, you can add it to the HA menu using panel_iframe or to any HA window via the lovelace card “iframe”.
That's all, thank you for your attention.