Skip to content

Commit 7b898b9

Browse files
committed
update example
1 parent 5523441 commit 7b898b9

File tree

1 file changed

+101
-39
lines changed

1 file changed

+101
-39
lines changed

examples/ubx_spatialite.py

Lines changed: 101 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
ubx_spatialite.py
33
44
Example script illustrating how to create a sqlite3
5-
database with the spatialite extension enabled and load
6-
geometry (lat/lon/height) data from a binary UBX NAV-PVT
7-
data log into it using pyubx2.
5+
database (gnss.sqlite) with the spatialite extension
6+
enabled and load geometry (lat/lon/hmsl) data from a
7+
binary GNSS data log into it using pyubx2. Log must
8+
contain UBX NAV-PVT and/or NMEA GGA messages.
9+
10+
Usage:
11+
12+
python3 ubx_spatialite.py infile="gnssdata.log" dbpath="/home/myuser/Downloads" table="gnssdata"
813
914
***********************************************************
1015
NB: Although sqlite3 is a native Python 3 module,
@@ -25,13 +30,12 @@
2530
and check for the entry 'load_extension on'.
2631
***********************************************************
2732
28-
gpsdata example table has the following fields:
33+
gnssdata example table has the following fields:
2934
pk integer
3035
geom POINTZ
3136
source text
32-
time integer
37+
tow integer
3338
fixtype integer
34-
difftype integer
3539
dop decimal
3640
hacc decimal
3741
@@ -43,17 +47,14 @@
4347
"""
4448

4549
import sqlite3 # NOTE caveat above
50+
from datetime import datetime
4651
from os import environ, path
52+
from sys import argv
4753

48-
from pyubx2 import ERR_LOG, UBX_PROTOCOL, UBXReader
54+
from pyubx2 import ERR_LOG, NMEA_PROTOCOL, UBX_PROTOCOL, UBXReader
4955

50-
# path to input file containing binary UBX NAV-PVT data
51-
INFILE = "/Users/steve/Library/CloudStorage/Dropbox/Development/workspace_vscode/pyubx2/references/logs/pygpsdata-ubxcartrip.log"
52-
53-
# path to spatialite database
56+
LEAPS = 18 # tow leapseconds adjustment
5457
DB = "gnss.sqlite"
55-
DBPATH = path.join("/Users/steve/Downloads/qgis", DB)
56-
TABLE = "gpsdata"
5758

5859
# path to mod_spatialite module, if required
5960
# SLPATH = "C:/Program Files/QGIS 3.44.1/bin"
@@ -62,28 +63,54 @@
6263
SQLBEGIN = "BEGIN TRANSACTION;"
6364
SQLCOMMIT = "COMMIT;"
6465

65-
# CREATE SQL statement with 3D POINT
66+
# CREATE SQL statement with 3D POINT (lon, lat, hmsl)
6667
SQLC1 = (
6768
SQLBEGIN
6869
+ (
6970
"DROP TABLE IF EXISTS {table};"
7071
"CREATE TABLE {table} (id INTEGER PRIMARY KEY, source TEXT, "
71-
"time INTEGER, fixtype INTEGER, difftype INTEGER, dop DECIMAL, hacc DECIMAL);"
72-
"SELECT AddGeometryColumn('gpsdata', 'geom', 4326, 'POINT', 'XYZ');"
73-
"SELECT CreateSpatialIndex('gpsdata', 'geom');"
72+
"tow INTEGER, fixtype INTEGER, dop DECIMAL, hacc DECIMAL);"
73+
"SELECT AddGeometryColumn('{table}', 'geom', 4326, 'POINT', 'XYZ');"
74+
"SELECT CreateSpatialIndex('{table}', 'geom');"
7475
)
7576
+ SQLCOMMIT
7677
)
7778

78-
# INSERT SQL statement with 3D POINT (lon, lat, height)
79+
# INSERT SQL statement with 3D POINT
7980
SQLI3D = (
80-
"INSERT INTO {table} (source, time, fixtype, difftype, dop, hacc, geom) "
81-
"VALUES ('{source}', {time}, {fixtype}, {difftype}, {dop}, {hacc}, "
81+
"INSERT INTO {table} (source, tow, fixtype, dop, hacc, geom) "
82+
"VALUES ('{source}', {tow}, {fixtype}, {dop}, {hacc}, "
8283
"GeomFromText('POINTZ({lon} {lat} {height})', 4326));"
8384
)
8485

8586

86-
def create_database(con, cur):
87+
def fix2quality(parsed):
88+
"""
89+
Convert NAV-PVT fixType to GGA quality
90+
"""
91+
92+
if parsed.carrSoln == 1: # float
93+
return 5
94+
if parsed.carrSoln == 2: # fixed
95+
return 4
96+
if parsed.fixType in (2, 4): # 2D or DR
97+
return 1
98+
if parsed.fixType == 3: # 3D
99+
return 2
100+
return 0
101+
102+
103+
def tim2tow(tim):
104+
"""
105+
Convert GGA time to TOW.
106+
"""
107+
108+
dat = datetime.combine(datetime.now().date(), tim)
109+
wd = (dat.weekday() - 6) % 7
110+
return (wd * 86400) + dat.hour * 3600 + dat.minute * 60 + dat.second + LEAPS
111+
112+
113+
def create_database(con, cur, table):
87114
"""
88115
Create spatial database.
89116
"""
@@ -97,51 +124,86 @@ def create_database(con, cur):
97124
"Your Python installation does not currently support sqlite3 extensions"
98125
) from err
99126
print("Loading mod_spatialite extension")
100-
con.load_extension("mod_spatialite")
127+
try:
128+
con.load_extension("mod_spatialite")
129+
except sqlite3.OperationalError as err:
130+
raise sqlite3.OperationalError(
131+
"Unable to locate sqlite3 mod_spatialite extension - check PATH"
132+
) from err
101133
print("Initialising spatial metadata (may take a few seconds)")
102134
con.execute("SELECT InitSpatialMetaData();")
103135
# create database table
104-
print(f"Creating {TABLE} table")
105-
cur.executescript(SQLC1.format(table=TABLE))
136+
print(f"Creating {table} table")
137+
cur.executescript(SQLC1.format(table=table))
106138

107139

108-
def load_data(cur):
140+
def load_data(cur, infile, table):
109141
"""
110142
Load data into database.
111143
"""
112144

113145
# iterate through UBX data log
114-
print(f"Loading data into {TABLE} from UBX data log")
146+
print(f"Loading data into {table} from GNSS data log")
115147
i = 0
116148
cur.execute(SQLBEGIN)
117-
with open(INFILE, "rb") as stream:
118-
ubr = UBXReader(stream, protfilter=UBX_PROTOCOL, quitonerror=ERR_LOG)
149+
with open(infile, "rb") as stream:
150+
ubr = UBXReader(
151+
stream, protfilter=UBX_PROTOCOL | NMEA_PROTOCOL, quitonerror=ERR_LOG
152+
)
119153
for _, parsed in ubr:
120-
if parsed.identity == "NAV-PVT":
154+
if "NAV-PVT" in parsed.identity:
121155
sql = SQLI3D.format(
122-
table=TABLE,
156+
table=table,
123157
source=parsed.identity,
124-
time=parsed.iTOW,
125-
fixtype=parsed.fixType,
126-
difftype=parsed.carrSoln,
158+
tow=int(parsed.iTOW / 1000), # seconds
159+
fixtype=fix2quality(parsed),
127160
dop=parsed.pDOP,
128161
hacc=parsed.hAcc,
129162
lon=parsed.lon,
130163
lat=parsed.lat,
131164
height=parsed.hMSL / 1000, # meters
132165
)
166+
# print(sql)
167+
cur.execute(sql)
168+
i += 1
169+
elif "GGA" in parsed.identity:
170+
sql = SQLI3D.format(
171+
table=table,
172+
source=parsed.identity,
173+
tow=tim2tow(parsed.time), # seconds
174+
fixtype=parsed.quality,
175+
dop=parsed.HDOP,
176+
hacc=0,
177+
lon=parsed.lon,
178+
lat=parsed.lat,
179+
height=parsed.alt, # meters
180+
)
181+
# print(sql)
133182
cur.execute(sql)
134183
i += 1
135184
cur.execute(SQLCOMMIT)
136-
print(f"{i} records loaded into {TABLE}")
185+
print(f"{i} records loaded into {table}")
137186

138187

139-
if __name__ == "__main__":
188+
def main(**kwargs):
189+
"""
190+
Main routine.
191+
"""
192+
193+
infile = kwargs.get("infile", "gnssdata.log")
194+
dbpath = kwargs.get("dbpath", ".")
195+
db = path.join(dbpath, "gnss.sqlite")
196+
table = kwargs.get("table", "gnssdata")
140197

141198
# create & connect to the database
142-
print(f"Connecting to database {DBPATH}")
143-
with sqlite3.connect(DBPATH) as connection:
199+
print(f"Connecting to database {db}")
200+
with sqlite3.connect(db) as connection:
144201
cursor = connection.cursor()
145-
create_database(connection, cursor)
146-
load_data(cursor)
202+
create_database(connection, cursor, table)
203+
load_data(cursor, infile, table)
147204
print("Complete")
205+
206+
207+
if __name__ == "__main__":
208+
209+
main(**dict(arg.split("=") for arg in argv[1:]))

0 commit comments

Comments
 (0)