We connect the GPS tracker Sinotrack ST-901 to the smart home HomeAssistant

Introduction


Somehow the Chinese GPS tracker ST-901 came into my hands. The device is designed mainly for use in auto and moto-technology, has a gsm 2G module for communication with the outside world, a sealed waterproof case, a small built-in battery that allows you to work without external power for about 2-3 days when the signal is transmitted every 3 minutes as well as an ignition signal wire, which allows to warn about the engine start. You can manage this tracker via SMS commands to the tracker number, and you can communicate and receive notifications via both SMS and connecting it to the cloud via GPRS. Having indulged with him for some time, I threw it into the drawer until HomeAssistant appeared at home. There was an idea to connect it to a smart home for real-time tracking, as well as automation when a car hits a certain zone (HomeAssistant terminology) on the map.

Tasks


To connect the tracker to HomeAssistant, you need to solve two problems: get the coordinates from the tracker and write them to HomeAssistant. If there are several possible solutions for the second task (for example, gpslogger or owntracks_http ), then the solution to the first task in my case was complicated by the fact that in the tracker settings for transmitting coordinates you can only specify the IP address, not the domain name. Since I don’t have a static address at home, the idea was to use an intermediary. Anyone who is interested in what came of it, welcome under cat.

Idea


As I said above, this tracker can be connected to many cloud services. Some of them with certain restrictions allow you to use the services for free. Some services have full-fledged APIs for interacting with them, however I didn’t find one among free ones. But almost all services provide the service of “sharing” the tracker's location by a permanent link. After going through several of these services and having rummaged in the source code of the shared pages, I found what I was looking for in the livegpstracks service: a request for getting coordinates. Thus, the general scheme of work is as follows: the tracker connects to the livegpstracks service and sends its coordinates, HomeAssistant periodically makes an http request to the service and receives the last recorded coordinates, which are recorded by another http request in the HomeAssistant.

Implementation


1. Getting coordinates by request

We register in the livegpstracks service and connect our tracker (there are detailed instructions for various models on the site). After that, through the toolbar on the site we create a private link for tracking. The link looks like:

https://livegpstracks.com/dv_USERID.html 

where USERID is the digital ID of your balls.

Everything. You can access the service through requests. In order not to torture you for a long time, I’ll just give the request format

 https://livegpstracks.com/viewer_coos_s.php?username=USER&ctp=one&code=USERID&tgst=site&tgsv=12&tkv11=TIMENOWMS 

Here, USER is the user under which you registered with the livegpstracks service, USERID is the digital ID that is assigned to the shared link, TIMENOWMS is the current time in milliseconds (unix time).

A typical answer is:

 [{"code":"xxx","id":"xxx","lat":"44","lng":"48","speed":"0","azimuth":"0","d":"2018-06-19","t":"09:35:17","altitude":"0","battery":"0","gpsaccuracy":""}] 

Note: I have significantly reduced the output, and also changed the parameters code, id, lat, lng.

The method for getting coordinates in python looks like this:

 def getInfoFrom(self): timenow = int(datetime.now().strftime("%s")) * 1000 response = requests.get('https://livegpstracks.com/viewer_coos_s.php', params={'username': self._user, 'ctp': 'one', 'code': self._myid, 'tgst': 'site', 'tgsv': 12, 'tkv11': timenow}) data = response.json() self._lat = data[0]["lat"] self._lon = data[0]["lng"] self._speed = data[0]["speed"] self._direction = data[0]["azimuth"] self._last_time_rcv = data[0]["d"] + ' ' + data[0]["t"] 

I think it’s not necessary to explain anything in this code: we get the current time, we get a get request, we get back json, we parse it and we get the latitude, longitude, speed, direction and the time of the last receipt of coordinates by the server.

2. Record of coordinates

For recording, I used the GPSLogger module for HomeAssistant, since it works through an http request and allows you to use a separate password that is different from the password for the whole HA. From the documentation ( gpslogger ) you can see that the request has the following format:

 https://HAADRESS:HAPORT/api/gpslogger?latitude=LAT&longitude=LON&device=DEV&accuracy=ACC&speed=SPD&direction=DIR&api_password=PASS 

Here HAADRESS is the ip address or server name with HA, HAPORT is the server port, LAT is latitude, LON is longitude, DEV is the name of the device to display in HA, ACC is the coordinate accuracy (for some reason it does not work in HA, it gives an error I did not use it), SPD - speed, DIR - direction of movement, PASS - password to transfer coordinates

The method for writing coordinates to python looks like this:

 def putInfoTo(self): if self._lat != '' and self._lon != '': req_str = self._haddr+'/api/gpslogger' response = requests.get(req_str, params={'latitude': self._lat, 'longitude': self._lon, 'accuracy': 30, 'speed': self._speed, 'direction': self._direction, 'device': self._name, ' api_password': self._pwd}) self._last_time_upd = time.strftime("%Y.%m.%d %H:%M") 

I think there are no comments here either.

3. Module

The full code of the module receiving and recording coordinates is given below.

Module code
 #!/usr/local/bin/python3 # coding: utf-8 import time import requests import json import logging from datetime import datetime from datetime import timedelta import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import (CONF_NAME) from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) CONF_USER = 'user' CONF_ID = 'myid' CONF_PWD = 'pwd' CONF_SITE = 'haddr' ATTR_LAT = '' ATTR_LON = '' ATTR_SPEED = '' DEFAULT_NAME = 'GPS_Sensor' SCAN_INTERVAL = timedelta(seconds=120) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_USER): cv.string, vol.Required(CONF_ID): cv.string, vol.Required(CONF_PWD): cv.string, vol.Required(CONF_SITE): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) def setup_platform(hass, config, add_devices, discovery_info=None): user = config.get(CONF_USER) name = config.get(CONF_NAME) pwd = config.get(CONF_PWD) myid = config.get(CONF_ID) haddr = config.get(CONF_SITE) add_devices([CarGPS(name, user, myid, haddr, pwd)]) class CarGPS(Entity): def __init__(self, name, user, myid, haddr, pwd): self._name = name self._user = user self._myid = myid self._haddr = haddr self._pwd = pwd self._lat = '' self._lon = '' self._speed = '0' self._direction = '0' self._last_time_rcv = '' self._last_time_upd = '' def getInfoFrom(self): try: today = int(datetime.now().strftime("%s")) * 1000 response = requests.get('https://livegpstracks.com/viewer_coos_s.php', params={'username': self._user, 'ctp': 'one', 'code': self._myid, 'tgst': 'site', 'tgsv': 12, 'tkv11': today}) data = response.json() self._lat = data[0]["lat"] self._lon = data[0]["lng"] self._speed = data[0]["speed"] self._direction = data[0]["azimuth"] self._last_time_rcv = data[0]["d"] + ' ' + data[0]["t"] except: _LOGGER.error('coudnt get parameters') def putInfoTo(self): if self._lat != '' and self._lon != '': try: req_str = self._haddr+'/api/gpslogger' response = requests.get(req_str, params={'latitude': self._lat, 'longitude': self._lon, 'accuracy': 30, 'speed': self._speed, 'direction': self._direction, 'device': self._name, ' api_password': self._pwd}) _LOGGER.info(response) self._last_time_upd = time.strftime("%Y.%m.%d %H:%M") except: _LOGGER.error('coudnt put parameters') #for HASS @property def name(self): return self._name @property def state(self): return self._last_time_upd def update(self): self.getInfoFrom() self.putInfoTo() @property def device_state_attributes(self): attr = {} attr[ATTR_LAT] = self._lat attr[ATTR_LON] = self._lon attr[ATTR_SPEED] = self._speed return attr 


To connect this module, the code must be copied to the “config_folder_homeassistant / custom_components / sensor / car_location.py” directory, and the following lines should be added to the configuration:

 device_tracker: - platform: gpslogger password: !secret gpslogger_password sensor: - platform: car_location name: car_sensor user: USER myid: USERID haddr: YOUR_HA_ADDRESS pwd: !secret gpslogger_password 

Here are all the variables from the “Get coordinates by request” section.

This module has been working in HA for more than one month without any failures or other problems.

That's all, thank you for your attention.

UPD:
HomeAssistant updated the GPSLogger component, in connection with which the new version of the mod and settings:

new settings
 device_tracker: - platform: gpslogger sensor: - platform: car_location name: car_sensor user: USER myid: USERID haddr: YOUR_HA_ADDRESS_WEBHOOK 

YOUR_HA_ADDRESS_WEBHOOK is the GPSHogger webhook address, you can get it in Settings - Integration - GPSLogger.


new module code
 #!/usr/local/bin/python3 # coding: utf-8 import time import requests import json import logging from datetime import datetime from datetime import timedelta import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import (CONF_NAME) from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) CONF_USER = 'user' CONF_ID = 'myid' CONF_SITE = 'haddr' CONF_NAME = 'name' ATTR_LAT = '' ATTR_LON = '' ATTR_SPEED = '' ATTR_DATE = '' DEFAULT_NAME = 'GPS_Sensor' SCAN_INTERVAL = timedelta(seconds=120) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_USER): cv.string, vol.Required(CONF_ID): cv.string, vol.Required(CONF_SITE): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) def setup_platform(hass, config, add_devices, discovery_info=None): user = config.get(CONF_USER) name = config.get(CONF_NAME) myid = config.get(CONF_ID) haddr = config.get(CONF_SITE) add_devices([CarGPS(name, user, myid, haddr)]) class CarGPS(Entity): def __init__(self, name, user, myid, haddr): self._name = name self._user = user self._myid = myid self._haddr = haddr self._lat = '' self._lon = '' self._speed = '0' self._direction = '0' self._last_time_rcv = '' self._last_time_upd = '' def getInfoFrom(self): try: today = int(datetime.now().strftime("%s")) * 1000 response = requests.get('https://livegpstracks.com/viewer_coos_s.php', params={'username': self._user, 'ctp': 'one', 'code': self._myid, 'tgst': 'site', 'tgsv': 12, 'tkv11': today}) data = response.json() self._lat = str(data[0]["lat"]) self._lon = str(data[0]["lng"]) self._speed = str(data[0]["speed"]) self._direction = str(data[0]["azimuth"]) self._last_time_rcv = data[0]["d"] + ' ' + data[0]["t"] except: _LOGGER.error('coudnt get parameters') def putInfoTo(self): if self._lat != '' and self._lon != '': try: header = {'Content-Type': 'application/x-www-form-urlencoded'} body = 'latitude=' + self._lat + '&longitude=' + self._lon + '&device=' + self._name + '&accuracy=30&battery=100&speed=' + self._speed + '&direction=' + self._direction + '&altitude=0&provider=0&activity=0' response = requests.post(self._haddr, headers=header, data=body) self._last_time_upd = time.strftime("%Y.%m.%d %H:%M") except: _LOGGER.error('coudnt put parameters') #for HASS @property def name(self): return self._name @property def state(self): return self._last_time_upd def update(self): self.getInfoFrom() self.putInfoTo() @property def device_state_attributes(self): attr = {} attr[ATTR_LAT] = self._lat attr[ATTR_LON] = self._lon attr[ATTR_SPEED] = self._speed attr[ATTR_DATE] = self._last_time_rcv return attr 

Source: https://habr.com/ru/post/414509/


All Articles