Skip to content

Instantly share code, notes, and snippets.

@AlexRiina
Last active July 25, 2021 06:24
Show Gist options
  • Save AlexRiina/cbf0e863e7bba12cf6a0 to your computer and use it in GitHub Desktop.
Save AlexRiina/cbf0e863e7bba12cf6a0 to your computer and use it in GitHub Desktop.
Export FreeStyle Lite data from serial USB cable to CSV
""" Extract FreeStyle Lite data from serial USB cable to CSV.
Defaults for Linux or MacOS systems """
import argparse
import glob
import os
import re
import serial
from csv import writer
from datetime import datetime, date
def export_csv(tty_path, out):
csv = writer(out)
csv.writerow(('datetime', 'bg'))
def read_tty():
# readlines() can take a while. debug partial reads
# with tty.readlines(100).
tty = serial.Serial(tty_path, baudrate=19200, timeout=5)
tty.write(b"mem") # ask device to recite memory
for line in tty.readlines():
yield line.decode('ascii')
def parse_datetime(line):
# two expressions since June isn't %b but %B
# 099 Nov 04 2015 01:09 00 0x00
# 180 June 01 2016 00:43 00 0x00
date_str = re.sub(' +', ' ', line[5:23])
try:
return datetime.strptime(date_str, "%b %d %Y %H:%M")
except ValueError:
return datetime.strptime(date_str, "%B %d %Y %H:%M")
line = None
for line in read_tty():
# lines look like
# 099 Nov 04 2015 01:09 00 0x00
# 180 June 01 2016 00:43 00 0x00
try:
dt = parse_datetime(line)
except ValueError:
# beginning and ending lines aren't relevant
print("skipping", repr(line))
else:
bg = int(line[0:3], 10)
csv.writerow((dt, bg))
if line is None:
raise IOError("Nothing read from glucometer. "
"Ensure that device is connected properly")
def guess_tty(arg):
""" Guess active ttyUSB """
if os.name == 'posix':
path = '/dev/ttyUSB*'
usb_serial = glob.glob(path)
if not usb_serial:
raise argparse.ArgumentError(arg,
"No {} matches found. Ensure your device is connected "
"or look for other places that your ttyUSB device may be."
.format(path))
if len(usb_serial) > 1:
raise argparse.ArgumentError(arg,
"Multiple paths matching {} were found. "
"Specify --tty from {}".format(path, '\n'.join(usb_serial)))
else:
return usb_serial[0]
else:
raise argparse.ArgumentError(arg,
"Could not guess where tty device would be")
if __name__ == '__main__':
a = argparse.ArgumentParser(description=__doc__)
tty_arg = a.add_argument("--tty",
help="Full path to cable. Defaults to guessing /dev/ttyUSB*")
default_csv = "bgs-{}.csv".format(date.today().isoformat())
a.add_argument("-o", "--out",
default=default_csv,
metavar="CSV",
help="Csv out path. Defaults to {}".format(default_csv),
type=argparse.FileType('w'))
args = a.parse_args()
# using `or` instead of default to allow it to raise errors
# when not specified but be overwriteable
export_csv(args.tty or guess_tty(tty_arg), args.out)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment