Rationale:
For advanced presence detection (and another project I’m working on) I wanted to get the GPS locations from the smartphones of my family members. At first, I considered using a specialized app, however since my family already uses Google Maps location sharing extensively and it works extremely well, I decided it would be easiest and probably the most reliable of all the options available to me.
Approach:
The major complication is that Google does not provide a real API to get locations from the location sharing. That said, there are workarounds, namely locationsharinglib, a python library used to do just this. Then, to get these actual values into OpenHAB, I decided to use MQTT as it’s what I’m most familiar with and already use extensively. This could probably also be done using the REST API or something similar.
The script:
This Python script is what fetches the location data and publishes it to MQTT.
import random
import time
from paho.mqtt import client as mqtt_client
from locationsharinglib import Service
#Location Sharing Library config
cookies_file = 'COOKIE_FILE_PATH.txt'
google_email = 'GOOGLE_USER@gmail.com'
#MQTT Configuration
broker = '192.168.1.114'
port = 1883
topic = "googlelocation/"
client_id = 'python-mqtt-{random.randint(0, 1000)}'
username = ''
password = ''
#Update Interval (in seconds)
update_interval = 60
service = Service(cookies_file=cookies_file, authenticating_account=google_email)
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
return client
def publish(client):
while True:
time.sleep(update_interval)
for person in service.get_all_people():
for data in dir(person):
if not data.startswith('_'):
print(topic + person.nickname + "/" + data, str(getattr(person, data)))
client.publish(topic + person.nickname + "/" + data, str(getattr(person, data)))
def run():
client = connect_mqtt()
client.loop_start()
publish(client)
if __name__ == '__main__':
run()
Things, items, and transforms
.things file
//NAME Location
Thing mqtt:topic:googlelocation_NAME "Google Location: NAME" (mqtt:broker:e0c4d01e) @ "Server Room"{
Channels:
Type number : Accuracy [ stateTopic="googlelocation/NAME/accuracy"]
Type string : Address [ stateTopic="googlelocation/NAME/address"]
Type number : Battery_Level [ stateTopic="googlelocation/NAME/battery_level"]
Type contact : Charging [ stateTopic="googlelocation/NAME/charging", on="True", off="False"]
Type string : Country_Code [ stateTopic="googlelocation/NAME/country_code"]
Type datetime : Timestamp [ stateTopic="googlelocation/NAME/datetime", transformationPattern="JS:googletimestamp.js"]
Type string : Full_Name [ stateTopic="googlelocation/NAME/full_name"]
Type string : Id_number [ stateTopic="googlelocation/NAME/id"]
Type number : Latitude [ stateTopic="googlelocation/NAME/latitude"]
Type number : Longitude [ stateTopic="googlelocation/NAME/longitude"]
Type string : Photo_URL [ stateTopic="googlelocation/NAME/picture_url"]
}
.items file
//NAME Location
Number GPSLocation_NAME_Accuracy "Accuracy" (Logged) {channel="mqtt:topic:googlelocation_NAME:Accuracy" }
String GPSLocation_NAME_Address "Address" (Logged) {channel="mqtt:topic:googlelocation_NAME:Address" }
Number GPSLocation_NAME_Battery_Level "Battery Level" (Logged) {channel="mqtt:topic:googlelocation_NAME:Battery_Level" }
Contact GPSLocation_NAME_Charging "Chargin" (Logged) {channel="mqtt:topic:googlelocation_NAME:Charging" }
String GPSLocation_NAME_Country_Code "Country Code" (Logged) {channel="mqtt:topic:googlelocation_NAME:Country_Code" }
DateTime GPSLocation_NAME_Timestamp "Timestamp" (Logged) {channel="mqtt:topic:googlelocation_NAME:Timestamp" }
String GPSLocation_NAME_Full_Name "Full Name" (Logged) {channel="mqtt:topic:googlelocation_NAME:Full_Name" }
String GPSLocation_NAME_Id_number "ID Number" (Logged) {channel="mqtt:topic:googlelocation_NAME:Id_number" }
Number GPSLocation_NAME_Latitude "Latitude" (Logged) {channel="mqtt:topic:googlelocation_NAME:Latitude" }
Number GPSLocation_NAME_Longitude "Longitude" (Logged) {channel="mqtt:topic:googlelocation_NAME:Longitude" }
String GPSLocation_NAME_Photo_URL "Photo URL" (Logged) {channel="mqtt:topic:googlelocation_NAME:Photo_URL" }
googletimestamp.js
(function(timestamp){
return timestamp.substring(0,10) + 'T' + timestamp.substring(11,23) + timestamp.substring(26,32)
})(input)
Step by step:
-
Install locationsharing lib and paho-mqtt on my OH server (
pip3 install locationsharinglib
andpip3 install paho-mqtt
. Python3 and pip3 required) -
Put the script somewhere useful. I put mine in OpenHAB’s scripts folder, because it seems appropriate and gets included in the automatic backups, but it really doesn’t matter where it is exactly.
-
Set up the cookies for locationsharinglib. Basically, log out of the google account you intend to use, log in again (make sure you’re on .com) and then go to maps.google.com. Once you’ve done this, export the cookies as text files (there are browser extensions that can do this) and place the cookie file in the same directory as the script. More details can be found here on how to do this.
-
Customize the python script. Put the cookie.txt in the same directory as the script, and put the name along with your email in the appropriate slots. Then, adjust the MQTT settings to whatever you want and put in an interval (in seconds) on how often the script should send updates.
-
Test it out! I use mosquitto, so listening to MQTT is as simple as
mosquitto_sub -v -t 'googlelocation/#'
-
Configure the script to start automatically when the computer starts. I did this via Systemd, and there are plenty of good tutorials on how to do this. Make sure to set
WorkingDirectory
properly. Using Systemd has lots of advantages, including automatically restarting the script if something doesnt work like the MQTT connection or similar. -
Configure those OpenHAB things, items, and scripts. See my examples above. The script simply converts from the format used by google to the OpenHAB acceptable DateTime format.
-
Enjoy!
Results
So far, it’s been running without any hiccups since I started it, and the simplicity of the python script means that once configured, it shouldn’t need to be updated. New users can simply share their location with the main google account, and it should seamlessly also read their locations to MQTT.
Potential issues might crop up if the cookie used to authenticate to google expires, or if google changes the way this unofficial ‘API’ works.