Make time series measurements with a Sartorius scale.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

150 lines
4.6 KiB

import argparse
import re
from collections import namedtuple
from pathlib import Path
TIME_UNIT_FACTORS = {
"s": 1,
"m": 60,
"h": 60 * 60,
}
ParsedDuration = namedtuple("ParsedDuration", ["value", "unit", "seconds"])
Settings = namedtuple(
"Settings", ["duration", "interval", "directory", "port", "measurements"]
)
def parse_duration(raw_value, default_unit="m"):
"""' parses a duration like 10sec, 5min or 2h
:params raw_value: string value to parse
:params default_unit: default unit to use, if no (known) unit is present
:returns: ParsedTime named tuple or None
"""
match = re.match(r"(?P<value>\d+)(?P<unit>.*)", raw_value)
if not match:
return None
value = int(match["value"])
unit = _normalize_time_unit(match["unit"], default_unit=default_unit)
factor = TIME_UNIT_FACTORS[unit]
return ParsedDuration(value, unit, value * factor)
def parse_cli_arguments():
""" parses command line interface arguments """
parser = argparse.ArgumentParser(
description="Make time series measurements with a Sartorius scale.",
epilog=(
"Times can be specified as 10s, 10m, or 10h"
"for seconds, minutes or hours respectively."
"A relative directory path starts at the Desktop."
),
)
parser.add_argument("port", nargs="?", default="COM4", metavar="COMPORT")
parser.add_argument("-d", "--duration", nargs="?", default="30m")
parser.add_argument("-i", "--interval", nargs="?", default="10s")
parser.add_argument("-o", "--output", nargs="?", metavar="DIRECTORY")
raw_arguments = parser.parse_args()
return _normalize_cli_arguments(raw_arguments)
def parse_gui_arguments():
from gooey import GooeyParser
""" parses command line interface arguments """
desktop_path = Path.home() / "Desktop"
parser = GooeyParser(
description="Make time series measurements with a Sartorius scale.",
epilog=(
"Times can be specified as 10s, 10m, or 10h"
"for seconds, minutes or hours respectively."
"A relative directory path starts at the Desktop."
),
)
parser.add_argument(
"port",
nargs="?",
default="COM4",
metavar="COMPORT",
help="Serial Port that connects the Scale, defaults to 'COM4'",
)
parser.add_argument(
"-d",
"--duration",
nargs="?",
default="30m",
help="Measurement duration, e.g. 10s, 30m, 2h",
)
parser.add_argument(
"-i",
"--interval",
nargs="?",
default="10s",
help="Measurement interval, e.g. 5s, 1m, 1h",
)
parser.add_argument(
"-o",
"--output",
nargs="?",
metavar="DIRECTORY",
widget="DirChooser",
help="Select Output Directory, defaults to 'Desktop'",
gooey_options={"default_path": str(desktop_path)},
)
raw_arguments = parser.parse_args()
return _normalize_cli_arguments(raw_arguments)
# helper functions
def _normalize_time_unit(raw_unit, default_unit):
""" checks if a known time unit is present, else uses the default unit """
known_units = "hms"
found = [unit for unit in known_units if unit in raw_unit.lower()]
unit = found[0] if found else default_unit
return unit
def _normalize_cli_arguments(raw_arguments):
""" transforms cli arguments into a suitable form """
# time related stuff
duration = parse_duration(raw_arguments.duration, default_unit="m")
interval = parse_duration(raw_arguments.interval, default_unit="s")
# directory stuff
dir_path = _check_output_directory_path(raw_arguments.output)
measurements = 1 + (duration.seconds // interval.seconds)
return Settings(
duration, interval, dir_path, raw_arguments.port, measurements
)
def _check_output_directory_path(raw_path):
""" returns the absolue path of the output directory
s
The desktop path (~/Desktop) is considered the default directory. If a
relative path is provided, it is considered relative to the desktop.
"""
# the desktop path is the default output directory
out_path = desktop_path = Path.home() / "Desktop"
# if a relative path is provided, make it relative to the desktop
if raw_path:
out_path = Path(raw_path)
if not out_path.is_absolute():
out_path = desktop_path / out_path
out_path = out_path.resolve()
# if the provided path is something strange like an existing file,
# use the default path (Desktop)
if out_path.exists() and not out_path.is_dir():
out_path = desktop_path
return out_path