mirror of
https://codeberg.org/ET-Kiel/tk102gpx.git
synced 2026-05-01 13:44:23 +02:00
Compare commits
3 commits
5f5834bc32
...
33e95043fc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33e95043fc | ||
| 4e56fbd3f4 | |||
| 383ffbfb69 |
3 changed files with 174 additions and 38 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
||||||
cron.log
|
cron.log
|
||||||
tk102-*.gpx
|
tk102-*.gpx
|
||||||
tk102-*.log
|
tk102-*.log
|
||||||
|
tk102-*.txt
|
||||||
|
|
||||||
|
|
|
||||||
10
Makefile
10
Makefile
|
|
@ -6,5 +6,11 @@ all: $(patsubst %, %.gpx, $(FILES))
|
||||||
%.gpx: %.log
|
%.gpx: %.log
|
||||||
./tk102gpx.py $< > $@
|
./tk102gpx.py $< > $@
|
||||||
|
|
||||||
capture:
|
nc%: tk102-%.log
|
||||||
(while true; do nc -lp 10201; done) | tee -a tk102-1.log | cat -v
|
(while true; do nc -lp 1020$* -w 999; done) | tee -a $< | cat -v
|
||||||
|
|
||||||
|
tail%: tk102-%.log
|
||||||
|
./tk102gpx.py -t1w -CFf $< | tee tk102-$*.txt
|
||||||
|
|
||||||
|
%.txt: t%.log
|
||||||
|
./tk102gpx.py -CF $< > $@
|
||||||
|
|
|
||||||
209
tk102gpx.py
209
tk102gpx.py
|
|
@ -1,9 +1,58 @@
|
||||||
#! /usr/bin/python3
|
#! /usr/bin/python3
|
||||||
|
|
||||||
import sys, re
|
import sys, re, time
|
||||||
import gpxpy
|
import gpxpy
|
||||||
import gpxpy.gpx
|
import gpxpy.gpx
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from getopt import getopt
|
||||||
|
|
||||||
|
options, files = getopt(sys.argv[1:],
|
||||||
|
"qvft:s:RDCXF",
|
||||||
|
["quiet", "verbose", "follow", "time=", "serial=",
|
||||||
|
"raw", "data", "cooked", "gpx", "fieldnames"])
|
||||||
|
|
||||||
|
follow = False
|
||||||
|
serial = b"0"
|
||||||
|
verbose = 1
|
||||||
|
raw = 0
|
||||||
|
fieldnames = False
|
||||||
|
|
||||||
|
print(options, file=sys.stderr)
|
||||||
|
|
||||||
|
for o,v in options:
|
||||||
|
o = " "+o
|
||||||
|
if o in " -q --quiet":
|
||||||
|
verbose = 0
|
||||||
|
if o in " -v --verbose":
|
||||||
|
verbose += 1
|
||||||
|
if o in " -f --follow":
|
||||||
|
follow = True
|
||||||
|
if o in " -D --data":
|
||||||
|
raw = 1
|
||||||
|
if o in " -C --cooked":
|
||||||
|
raw = 2
|
||||||
|
if o in " -R --raw":
|
||||||
|
raw = 3
|
||||||
|
if o in " -X --gpx":
|
||||||
|
raw = 0
|
||||||
|
if o in " -F --fieldnames":
|
||||||
|
fieldnames = True
|
||||||
|
if o in " -s --serial":
|
||||||
|
serial = v.encode()
|
||||||
|
if o in " -t --time":
|
||||||
|
if v[-1]=="m":
|
||||||
|
t = float(v[:-1])*60
|
||||||
|
elif v[-1]=="h":
|
||||||
|
t = float(v[:-1])*3600
|
||||||
|
elif v[-1]=="d":
|
||||||
|
t = float(v[:-1])*86400
|
||||||
|
elif v[-1]=="w":
|
||||||
|
t = float(v[:-1])*86400*7
|
||||||
|
else:
|
||||||
|
t = float(v)
|
||||||
|
serial = time.strftime("%y%m%d%H%M", time.gmtime(time.time()-t)).encode()
|
||||||
|
if verbose:
|
||||||
|
print(f"--serial={serial}", file=sys.stderr)
|
||||||
|
|
||||||
tk_re = re.compile(b"".join((
|
tk_re = re.compile(b"".join((
|
||||||
b"(?P<SERIAL>[0-9]+)?,",
|
b"(?P<SERIAL>[0-9]+)?,",
|
||||||
|
|
@ -21,7 +70,7 @@ tk_re = re.compile(b"".join((
|
||||||
b"(?P<VAR>[^,]+)?,",
|
b"(?P<VAR>[^,]+)?,",
|
||||||
b"(?P<WHAT>[^,]*,)?",
|
b"(?P<WHAT>[^,]*,)?",
|
||||||
b"A\*(?P<GPCKS>[0-9A-F][0-9A-F]),",
|
b"A\*(?P<GPCKS>[0-9A-F][0-9A-F]),",
|
||||||
b"(?P<F>[A-Z])?,",
|
b"(?P<BAT>[FL])?,",
|
||||||
b"imei:(?P<IMEI>[0-9]+),",
|
b"imei:(?P<IMEI>[0-9]+),",
|
||||||
b"(?P<LEN>[0-9]{3})",
|
b"(?P<LEN>[0-9]{3})",
|
||||||
b"(?P<BCKS>..)"
|
b"(?P<BCKS>..)"
|
||||||
|
|
@ -36,50 +85,132 @@ def gprmc2deg(d,dd):
|
||||||
|
|
||||||
class TKGPX(gpxpy.gpx.GPX):
|
class TKGPX(gpxpy.gpx.GPX):
|
||||||
|
|
||||||
def __init__(self, inp):
|
def tk_newtrack(self, files):
|
||||||
|
if files:
|
||||||
super().__init__()
|
fn = files[0]
|
||||||
track = gpxpy.gpx.GPXTrack()
|
files[:1] = []
|
||||||
|
inp = open(fn, "rb")
|
||||||
|
else:
|
||||||
|
fn = None
|
||||||
|
inp = sys.stdin.buffer
|
||||||
|
track = gpxpy.gpx.GPXTrack(name=fn)
|
||||||
self.tracks.append(track)
|
self.tracks.append(track)
|
||||||
segment = gpxpy.gpx.GPXTrackSegment()
|
segment = gpxpy.gpx.GPXTrackSegment()
|
||||||
track.segments.append(segment)
|
track.segments.append(segment)
|
||||||
|
return inp, segment
|
||||||
|
|
||||||
|
def __init__(self, files):
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
inp, segment = self.tk_newtrack(files)
|
||||||
|
|
||||||
|
slept = False
|
||||||
data = inp.read(0x100000)
|
data = inp.read(0x100000)
|
||||||
while data:
|
while data or follow or files:
|
||||||
if len(data)<256:
|
|
||||||
data += inp.read(0x100000)
|
|
||||||
m = tk_re.search(data)
|
m = tk_re.search(data)
|
||||||
if m is None or m.end()<1:
|
while not m:
|
||||||
break
|
ndata = inp.read(0x100000)
|
||||||
if m.start():
|
while not ndata and files:
|
||||||
|
inp.close()
|
||||||
|
imp, segment = self.tk_newtrack(files)
|
||||||
|
ndata = inp.read(0x100000)
|
||||||
|
if not ndata:
|
||||||
|
break
|
||||||
|
data += ndata
|
||||||
|
if m is None:
|
||||||
|
if not follow:
|
||||||
|
break
|
||||||
|
sys.stdout.flush()
|
||||||
|
try:
|
||||||
|
if verbose >= 2:
|
||||||
|
slept = True
|
||||||
|
sys.stderr.write(".")
|
||||||
|
sys.stderr.flush()
|
||||||
|
time.sleep(60)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
if slept:
|
||||||
|
sys.stderr.write("\n")
|
||||||
|
slept = False
|
||||||
|
|
||||||
|
if m.start() and verbose >= 2:
|
||||||
print(f"discarded: {repr(data[:m.start()])}", file=sys.stderr)
|
print(f"discarded: {repr(data[:m.start()])}", file=sys.stderr)
|
||||||
data = data[m.end():]
|
data = data[m.end():]
|
||||||
d = m.groupdict()
|
rd = m.groupdict()
|
||||||
print(int(d["LEN"]), m.end()-m.start()-int(d["LEN"]), repr(m.group()), file=sys.stderr)
|
|
||||||
print(repr(d), file=sys.stderr)
|
if not rd["LAT"] or not rd["LON"] or rd["SERIAL"] < serial:
|
||||||
if not d["LAT"] or not d["LON"]:
|
if verbose >= 3:
|
||||||
break
|
print(f"DROPPED: {repr(rd)}", file=sys.stderr)
|
||||||
pd = {
|
continue
|
||||||
"latitude": gprmc2deg(d["LAT"], d["NS"]),
|
|
||||||
"longitude": gprmc2deg(d["LON"], d["EW"]),
|
if verbose >= 3:
|
||||||
}
|
print(repr(rd), file=sys.stderr)
|
||||||
if d["TIME"] and d["DATE"]:
|
|
||||||
pd["time"] = datetime(
|
if verbose>0 and rd["BAT"] != b"F":
|
||||||
int(d["DATE"][0:2])+2000,
|
print(f"Battery is {repr(rd['BAT'])} at {rd['SERIAL']}", file=sys.stderr)
|
||||||
int(d["DATE"][2:4]),
|
|
||||||
int(d["DATE"][4:6]),
|
pd = {
|
||||||
int(d["TIME"][0:2]),
|
"latitude": gprmc2deg(rd["LAT"], rd["NS"]),
|
||||||
int(d["TIME"][2:4]),
|
"longitude": gprmc2deg(rd["LON"], rd["EW"]),
|
||||||
int(d["TIME"][4:6])
|
}
|
||||||
)
|
if rd["TIME"] and rd["DATE"]:
|
||||||
if d["SOG"]:
|
pd["time"] = datetime(
|
||||||
pd["speed"] = float(d["SOG"]) # knots
|
int(rd["DATE"][4:6])+2000,
|
||||||
|
int(rd["DATE"][2:4]),
|
||||||
|
int(rd["DATE"][0:2]),
|
||||||
|
int(rd["TIME"][0:2]),
|
||||||
|
int(rd["TIME"][2:4]),
|
||||||
|
int(rd["TIME"][4:6])
|
||||||
|
)
|
||||||
|
if rd["SOG"]:
|
||||||
|
pd["speed"] = float(rd["SOG"]) # knots
|
||||||
|
|
||||||
|
if verbose == 2:
|
||||||
|
print(repr(pd), file=sys.stderr)
|
||||||
|
|
||||||
|
if raw==1:
|
||||||
|
if fieldnames:
|
||||||
|
print(", ".join([f"{k}={pd[k]}" for k in pd]))
|
||||||
|
else:
|
||||||
|
print(" ".join([f"{pd[k]}" for k in pd]))
|
||||||
|
|
||||||
|
if raw==2:
|
||||||
|
cd = {}
|
||||||
|
cd.update(strorbytes(rd, 'BAT'))
|
||||||
|
cd.update(strorbytes(rd, 'SERIAL'))
|
||||||
|
cd.update(strorbytes(rd, 'PHONE'))
|
||||||
|
cd['time'] = pd['time'].isoformat()+'Z'
|
||||||
|
cd['lat'] = f"{rd['LAT'][:2].decode()}°{rd['LAT'][2:].decode()}'{rd['NS'].decode()}"
|
||||||
|
cd['lon'] = f"{rd['LON'][:3].decode()}°{rd['LAT'][3:].decode()}'{rd['EW'].decode()}"
|
||||||
|
cd.update(strorbytes(rd, 'SOG'))
|
||||||
|
cd.update(strorbytes(rd, 'COG'))
|
||||||
|
if fieldnames:
|
||||||
|
print(", ".join([f"{k}={cd[k]}" for k in cd]))
|
||||||
|
else:
|
||||||
|
print(" ".join([cd[k] for k in cd]))
|
||||||
|
|
||||||
|
if raw==3:
|
||||||
|
if fieldnames:
|
||||||
|
print(", ".join([f"{k}={repr(rd[k])[2:-1]}" for k in rd if rd[k]]))
|
||||||
|
else:
|
||||||
|
print(" ".join([f"{repr(rd[k])[2:-1]}" for k in rd if rd[k]]))
|
||||||
|
|
||||||
print(repr(pd), file=sys.stderr)
|
|
||||||
|
|
||||||
point = gpxpy.gpx.GPXTrackPoint(**pd)
|
point = gpxpy.gpx.GPXTrackPoint(**pd)
|
||||||
segment.points.append(point)
|
segment.points.append(point)
|
||||||
|
|
||||||
|
if follow and not raw and verbose < 2:
|
||||||
|
print(repr(point), file=sys.stderr)
|
||||||
|
|
||||||
|
def strorbytes(rd, f):
|
||||||
|
if not f in rd:
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
|
return {f: rd[f].decode()}
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return {f: repr(rd[f])[2:-1]}
|
||||||
|
|
||||||
# gpxpy.gpx.GPXTrackPoint(
|
# gpxpy.gpx.GPXTrackPoint(
|
||||||
# latitude: Optional[float] = None,
|
# latitude: Optional[float] = None,
|
||||||
# longitude: Optional[float] = None,
|
# longitude: Optional[float] = None,
|
||||||
|
|
@ -94,8 +225,6 @@ class TKGPX(gpxpy.gpx.GPX):
|
||||||
# name: Optional[str] = None,
|
# name: Optional[str] = None,
|
||||||
# ) -> None
|
# ) -> None
|
||||||
|
|
||||||
inp = sys.stdin.buffer
|
X = TKGPX(files)
|
||||||
if len(sys.argv) > 1:
|
if not raw:
|
||||||
inp = open(sys.argv[1], "rb")
|
print(X.to_xml())
|
||||||
|
|
||||||
print(TKGPX(inp).to_xml())
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue