#!/usr/bin/env python3 # -*- coding: utf-8 -*- import datetime import glob import json import math import os import re import sqlite3 ANSI_UP_DEL = u"\u001b[F\u001b[K" class C2GImport: def __init__(self): self.state = {} self.in_use = set() self.carids = {} self.dbfile = "car2go.db3" self.conn = sqlite3.connect(self.dbfile) self.conn.row_factory = sqlite3.Row self.c = self.conn.cursor() self.c.execute("PRAGMA foreign_keys=on;") self.run() def run(self): self.load_cars() self.load_data() self.c.execute("SELECT MAX(stamp) FROM car_state;"); max_date_row = self.c.fetchone() if max_date_row[0] is not None: max_date = max_date_row[0] max_date_dt = datetime.datetime.fromtimestamp(max_date, tz=datetime.timezone(datetime.timedelta(hours=1))) print("Skipping already collected data until {}.".format(repr(max_date_dt))) else: max_date_dt = datetime.datetime.min.replace(tzinfo=datetime.timezone(datetime.timedelta(hours=1))) ctr = 0 file_list = sorted(glob.glob(os.path.join("data/", "*.json"))) file_count = len(file_list) for f in file_list: stamp = re.search(r'(\d{4}-\d\d-\d\d_\d{6})', f) stamp_str = stamp.group(1) stamp_dt = datetime.datetime.strptime(stamp_str + "+0100", "%Y-%m-%d_%H%M%S%z") if stamp_dt <= max_date_dt: continue ctr += 1 self.scanfile(f, stamp_str, stamp_dt, ctr, file_count) if ctr%50==0: self.conn.commit() self.conn.commit() self.c.execute("VACUUM;") self.conn.close() def load_cars(self): print("Loading known cars from database.") self.c.execute("SELECT carId, plate FROM cars;") for row in self.c.fetchall(): self.carids[row[1]] = row[0] def load_data(self): print("Load known states from database.") self.c.execute("SELECT c.plate, c.vin, cs.occupied, cs.address, cs.latitude, cs.longitude, cs.fuel, c.engineType, c.smartPhoneRequired, cs.interior_bad, cs.exterior_bad FROM car_state cs LEFT JOIN cars c ON cs.carId=c.carId;") for row in self.c: car_id = row[0] dataset = { "name": car_id, "vin": row[1], "occupied": True if row[2]==1 else False, "address": row[3], "coordinates": [row[5], row[4], 0], "fuel": row[6], "engineType": row[7], "smartPhoneRequired": True if row[8]==1 else False, "interior": "GOOD" if not row[9] else row[8], "exterior": "GOOD" if not row[10] else row[9], } self.state[car_id] = dataset if dataset["occupied"]: self.in_use.add(car_id) else: self.in_use.discard(car_id) def scanfile(self, filename, stamp_str, stamp_dt, file_count, files_total): print("File: {} ({}/{})".format(filename, file_count, files_total), end="") jf = open(filename, "r") doc = json.load(jf) jf.close() root = doc["placemarks"] print(" ({} cars)".format(len(root)), end="") self.parse_cars(stamp_dt, root) if file_count