Project
The location of the home assistant install is on a mobile platform (examples: boat, RV, vehicle), and the desired outcome was to dynamically update the Home on the Map as the physical location changed.
Hardware Setup
- WiFi/Network Router
- raspberry PI (rpi_haos) with network cable to router
- raspberry Pi (rpiclient) with network cable to router
- USB GPS compatible with gpsd connected to rpiclient
Software Setup
rpiclient has Raspberry PI OS configured with gpsd and python3 with these packages installed:
It is running a python3 script on a 5 minute cron job that sends the data to the HA MQTT instance. There are some hard coded portions in this script, like the locations that the gpsdclient is installed, the IP of HA, and the MQTT details. The device name that was used is rpiclient
, which does not matter, as long as it is consistent everywhere.
rpiclient > /home/pi/gps2mqtt.py - collect the GPS 3D fix, and send to MQTT
#!/usr/bin/python3
import subprocess
import json
import paho.mqtt.publish as publish
def main():
"""
This script can take a bit of time for the several 3D fixes to be acquired and then sent, in my use less than 30 seconds is typical, but depending on how many fixes the GPS can get may cause this to be slower
"""
json_result = None
mode3_counter = 0
app = subprocess.Popen(['/home/pi/.local/bin/gpsdclient', '--json'], stdout = subprocess.PIPE, text = True)
for line in app.stdout:
json_line = json.loads(line)
# look for TPV messages with 3D fix, but only after more than 5 3D fixes
if 'class' in json_line and json_line['class'] == 'TPV' \
and 'mode' in json_line and json_line['mode'] == 3:
mode3_counter = mode3_counter + 1
if mode3_counter > 5:
json_result = json_line
break
app.terminate()
print('lat {} lon {} time {} alt {} speed {}'.format(json_result['lat'], json_result['lon'], json_result['time'], json_result['alt'], json_result['speed']))
host_ip = "MY.HOME.ASSISTANT.IP"
creds = {"username":"FIXME", "password":"FIXME"}
# the JSON format is to satisfy the mqtt_json expectations
# {"longitude": 0.0, "latitude": 0.0, "gps_accuracy": 0}
publish.single("location/rpiclient", '{"longitude": ' + str(json_result['lon']) + ', "latitude": ' + str(json_result['lat']) + ', "gps_accuracy": 10}', hostname=host_ip, auth=creds)
if __name__ == "__main__":
main()
rpiclient > crontab - edit using crontab -e
, executes the script every 5 minutes
*/5 * * * * /home/pi/gps2mqtt.py 2>&1 | logger -t mygps
NOTE: by redirecting the output to logger
the output can be seen in the journalctl
output, this was very useful when the script was causing errors in cron but not when run manually. The default for cron is for the output to go to the default mail provider, which is not setup by default in a Raspberry Pi OS.
rpi_haos has Home Assistant OS configured with MQTT. The IP and MQTT username/password is required to use in the above script.
rpi_haos > configuraton.yaml - use mqtt_json to create a device with a location from the MQTT data
device_tracker:
- platform: mqtt_json
devices:
rpiclient: location/rpiclient
NOTE: The known_devices.yaml
entry was created automatically after the device_tracker
started working, Manually modified the entry so that it had an appropriate icon and other information for future use.
rpi_haos > known_devices.yaml
rpiclient:
name: RPi Client
mac: ABC123ABC123
icon: mdi:raspberry-pi
picture:
track: true
Finally the automation which runs every 15 minutes, and updates the home location. The entry was created in the automation UI, but used the YAML mode for the service portion.
rpi_haos > automations.yaml
- id: '1645004564981'
alias: Set Home Location
description: Update home location from mqtt data
trigger:
- platform: time_pattern
minutes: /15
condition: []
action:
- service: homeassistant.set_location
data_template:
latitude: '{{ state_attr(''device_tracker.rpiclient'', ''latitude'') }}'
longitude: '{{ state_attr(''device_tracker.rpiclient'', ''longitude'') }}'
mode: single
Conclusion
There was a lot of learning involved in this setup, the hope is this documentation helps others who are trying to do a similar setup. The python code is usable but quite terrible, no error handling, hard coded variables. The data_template
chunk was found from a different post, so it is still a bit magical. This setup could be modified to use any GPS data sent over MQTT.