## original script by smmr0 as found in the deprecated owncloud/tools repo ## updated to make tid value configurable ## updated to work with new takeout json format #!/usr/bin/env python3 from datetime import datetime import time import argparse import json from paho.mqtt import client, publish import re class ProtocolAction(argparse.Action): def __call__(self, parser, namespace, value, option_string=None): setattr(namespace, self.dest, getattr(client, value)) ## Custom type for tid argument to allow only 2 letters def tid_type(arg_value, pat=re.compile(r"^[A-Za-z]{2}$")): if not pat.match(arg_value): raise argparse.ArgumentTypeError("invalid value, must be 2 letters (e.g. 'aa')") return arg_value parser = argparse.ArgumentParser(description='Import Google Location History into OwnTracks') parser.add_argument('-H', '--host', default='localhost', help='MQTT host (localhost)') parser.add_argument('-p', '--port', type=int, default=1883, help='MQTT port (1883)') parser.add_argument('--protocol', action=ProtocolAction, default=client.MQTTv31, help='MQTT protocol (MQTTv31)') parser.add_argument('--cacerts', help='Path to files containing trusted CA certificates') parser.add_argument('--cert', help='Path to file containing TLS client certificate') parser.add_argument('--key', help='Path to file containing TLS client private key') parser.add_argument('--tls-version', help='TLS protocol version') parser.add_argument('--ciphers', help='List of TLS ciphers') parser.add_argument('-u', '--username', help='MQTT username') parser.add_argument('-P', '--password', help='MQTT password') parser.add_argument('-i', '--clientid', help='MQTT client-ID') parser.add_argument('-t', '--topic', required=True, help='MQTT topic (e.g. owntracks//)') parser.add_argument('--tid', required=True, type=tid_type, help="Two letter Tracker ID you want these associated to (e.g. 'aa')") parser.add_argument('filename', help='Path to file containing JSON-formatted data from Google Location History exported by Google Takeout') args = parser.parse_args() messages = [] with open(args.filename) as lh: lh_data = json.load(lh) for location in lh_data['locations']: location_keys = location.keys() payload = { '_type': 'location' } payload['tid'] = args.tid if 'timestamp' in location_keys: #some of the google timestamps did not include milliseconds. time_format = "%Y-%m-%dT%H:%M:%S.%fZ" if '.' in location['timestamp'] else "%Y-%m-%dT%H:%M:%SZ" payload['tst'] = int(time.mktime(datetime.strptime(location['timestamp'], time_format).timetuple())) if 'latitudeE7' in location_keys: payload['lat'] = location['latitudeE7'] / 10000000 if 'longitudeE7' in location_keys: payload['lon'] = location['longitudeE7'] / 10000000 if 'accuracy' in location_keys: payload['acc'] = location['accuracy'] if 'altitude' in location_keys: payload['alt'] = location['altitude'] messages.append( { 'topic': args.topic, 'payload': json.dumps(payload), 'qos': 2 } ) del lh_data if args.username != None: auth={ 'username': args.username, 'password': args.password } else: auth = None if args.cacerts != None: tls = { 'ca_certs': args.cacerts, 'certfile': args.cert, 'keyfile': args.key, 'tls_version': args.tls_version, 'ciphers': args.ciphers } else: tls = None publish.multiple( messages, hostname=args.host, port=args.port, client_id=args.clientid, auth=auth, tls=tls )