We connect the GPS tracker Sinotrack ST-901 to the smart home HomeAssistant
- Tutorial
Introduction
Somehow the Chinese GPS tracker ST-901 came into my hands. The device is designed mainly for use in auto and moto-technology, it 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 transmitting a signal every 3 minutes as well as the 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 pampered with him for some time, I threw him into the box until HomeAssistant appeared at home. The idea was to connect it to a smart home for real-time tracking,
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 do not have a static address at home, the idea arose to use an intermediary. Anyone who is interested in what came of this, welcome under the 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 such among free ones. But almost all services provide the service of “sharing” the location of the tracker through 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 torment 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 in 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 to get the coordinates in python looks like this:
defgetInfoFrom(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, 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 for transmitting coordinates
The method for recording coordinates in python looks like this:
defputInfoTo(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 for receiving and recording coordinates is given below.
Module code
#!/usr/local/bin/python3# coding: utf-8import 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,
})
defsetup_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)])
classCarGPS(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 = ''defgetInfoFrom(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')
defputInfoTo(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 @propertydefname(self):return self._name
@propertydefstate(self):return self._last_time_upd
defupdate(self):
self.getInfoFrom()
self.putInfoTo()
@propertydefdevice_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, you need to copy the code to the “config_folder_homeassistant / custom_components / sensor / car_location.py” directory, and add the following lines 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
YOUR_HA_ADDRESS_WEBHOOK is the GPSHogger webhook address, you can get it in the Settings - Integration - GPSLogger section.
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 the Settings - Integration - GPSLogger section.
new module code
#!/usr/local/bin/python3# coding: utf-8import 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,
})
defsetup_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)])
classCarGPS(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 = ''defgetInfoFrom(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')
defputInfoTo(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 @propertydefname(self):return self._name
@propertydefstate(self):return self._last_time_upd
defupdate(self):
self.getInfoFrom()
self.putInfoTo()
@propertydefdevice_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
UPD2:
HomeAssistant updated the logic of work from version 0.88, in connection with which a new version of the mod: sensor