summaryrefslogtreecommitdiffstats
path: root/glucometerutils/drivers/otultra2.py
diff options
context:
space:
mode:
Diffstat (limited to 'glucometerutils/drivers/otultra2.py')
-rw-r--r--glucometerutils/drivers/otultra2.py112
1 files changed, 57 insertions, 55 deletions
diff --git a/glucometerutils/drivers/otultra2.py b/glucometerutils/drivers/otultra2.py
index 39be859..5e90b87 100644
--- a/glucometerutils/drivers/otultra2.py
+++ b/glucometerutils/drivers/otultra2.py
@@ -16,40 +16,40 @@ Expected device path: /dev/ttyUSB0 or similar serial port device.
import datetime
import re
-from glucometerutils import common
-from glucometerutils import exceptions
+from glucometerutils import common, exceptions
from glucometerutils.support import driver_base, lifescan, serial
# The following two hashes are taken directly from LifeScan's documentation
_MEAL_CODES = {
- 'N': common.Meal.NONE,
- 'B': common.Meal.BEFORE,
- 'A': common.Meal.AFTER,
+ "N": common.Meal.NONE,
+ "B": common.Meal.BEFORE,
+ "A": common.Meal.AFTER,
}
_COMMENT_CODES = {
- '00': '', # would be 'No Comment'
- '01': 'Not Enough Food',
- '02': 'Too Much Food',
- '03': 'Mild Exercise',
- '04': 'Hard Exercise',
- '05': 'Medication',
- '06': 'Stress',
- '07': 'Illness',
- '08': 'Feel Hypo',
- '09': 'Menses',
- '10': 'Vacation',
- '11': 'Other',
+ "00": "", # would be 'No Comment'
+ "01": "Not Enough Food",
+ "02": "Too Much Food",
+ "03": "Mild Exercise",
+ "04": "Hard Exercise",
+ "05": "Medication",
+ "06": "Stress",
+ "07": "Illness",
+ "08": "Feel Hypo",
+ "09": "Menses",
+ "10": "Vacation",
+ "11": "Other",
}
-_DUMP_HEADER_RE = re.compile(
- r'P ([0-9]{3}),"[0-9A-Z]{9}","(?:MG/DL |MMOL/L)"')
+_DUMP_HEADER_RE = re.compile(r'P ([0-9]{3}),"[0-9A-Z]{9}","(?:MG/DL |MMOL/L)"')
_DUMP_LINE_RE = re.compile(
r'P (?P<datetime>"[A-Z]{3}","[0-9/]{8}","[0-9:]{8} "),'
r'"(?P<control>[C ]) (?P<value>[0-9]{3})(?P<parityerror>[\? ])",'
- r'"(?P<meal>[NBA])","(?P<comment>0[0-9]|1[01])", 00')
+ r'"(?P<meal>[NBA])","(?P<comment>0[0-9]|1[01])", 00'
+)
+
+_RESPONSE_MATCH = re.compile(r"^(.+) ([0-9A-F]{4})\r$")
-_RESPONSE_MATCH = re.compile(r'^(.+) ([0-9A-F]{4})\r$')
def _calculate_checksum(bytestring):
"""Calculate the checksum used by OneTouch Ultra and Ultra2 devices
@@ -66,10 +66,11 @@ def _calculate_checksum(bytestring):
checksum = 0
for byte in bytestring:
- checksum = (checksum + byte) & 0xffff
+ checksum = (checksum + byte) & 0xFFFF
return checksum
+
def _validate_and_strip_checksum(line):
"""Verify the simple 16-bit checksum and remove it from the line.
@@ -88,20 +89,19 @@ def _validate_and_strip_checksum(line):
try:
checksum_given = int(checksum_string, 16)
- checksum_calculated = _calculate_checksum(
- bytes(response, 'ascii'))
+ checksum_calculated = _calculate_checksum(bytes(response, "ascii"))
if checksum_given != checksum_calculated:
- raise exceptions.InvalidChecksum(checksum_given,
- checksum_calculated)
+ raise exceptions.InvalidChecksum(checksum_given, checksum_calculated)
except ValueError:
raise exceptions.InvalidChecksum(checksum_given, None)
return response
+
_DATETIME_RE = re.compile(
- r'^"[A-Z]{3}",'
- r'"([0-9]{2}/[0-9]{2}/[0-9]{2})","([0-9]{2}:[0-9]{2}:[0-9]{2}) "$')
+ r'^"[A-Z]{3}",' r'"([0-9]{2}/[0-9]{2}/[0-9]{2})","([0-9]{2}:[0-9]{2}:[0-9]{2}) "$'
+)
def _parse_datetime(response):
@@ -121,8 +121,8 @@ def _parse_datetime(response):
raise exceptions.InvalidResponse(response)
date, time = match.groups()
- month, day, year = map(int, date.split('/'))
- hour, minute, second = map(int, time.split(':'))
+ month, day, year = map(int, date.split("/"))
+ hour, minute, second = map(int, time.split(":"))
# Yes, OneTouch2's firmware is not Y2K safe.
return datetime.datetime(2000 + year, month, day, hour, minute, second)
@@ -130,7 +130,7 @@ def _parse_datetime(response):
class Device(serial.SerialDevice, driver_base.GlucometerDriver):
BAUDRATE = 9600
- DEFAULT_CABLE_ID = '067b:2303' # Generic PL2303 cable.
+ DEFAULT_CABLE_ID = "067b:2303" # Generic PL2303 cable.
def connect(self): # pylint: disable=no-self-use
return
@@ -144,7 +144,7 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
Args:
cmd: command and parameters to send (without newline)
"""
- cmdstring = bytes('\x11\r' + cmd + '\r', 'ascii')
+ cmdstring = bytes("\x11\r" + cmd + "\r", "ascii")
self.serial_.write(cmdstring)
self.serial_.flush()
@@ -160,7 +160,7 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
"""
self._send_command(cmd)
- line = self.serial_.readline().decode('ascii')
+ line = self.serial_.readline().decode("ascii")
return _validate_and_strip_checksum(line)
def get_meter_info(self):
@@ -170,11 +170,11 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
A common.MeterInfo object.
"""
return common.MeterInfo(
- 'OneTouch Ultra 2 glucometer',
+ "OneTouch Ultra 2 glucometer",
serial_number=self.get_serial_number(),
- version_info=(
- 'Software version: ' + self.get_version(),),
- native_unit=self.get_glucose_unit())
+ version_info=("Software version: " + self.get_version(),),
+ native_unit=self.get_glucose_unit(),
+ )
def get_version(self):
"""Returns an identifier of the firmware version of the glucometer.
@@ -183,9 +183,9 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
The software version returned by the glucometer, such as
"P02.00.00 30/08/06".
"""
- response = self._send_oneliner_command('DM?')
+ response = self._send_oneliner_command("DM?")
- if response[0] != '?':
+ if response[0] != "?":
raise exceptions.InvalidResponse(response)
return response[1:]
@@ -204,7 +204,7 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
InvalidSerialNumber: if the returned serial number does not match
the OneTouch2 device as per specs.
"""
- response = self._send_oneliner_command('DM@')
+ response = self._send_oneliner_command("DM@")
match = self._SERIAL_NUMBER_RE.match(response)
if not match:
@@ -214,7 +214,7 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
# 'Y' at the far right of the serial number is the indication of a
# OneTouch Ultra2 device, as per specs.
- if serial_number[-1] != 'Y':
+ if serial_number[-1] != "Y":
raise lifescan.InvalidSerialNumber(serial_number)
return serial_number
@@ -225,12 +225,13 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
Returns:
A datetime object built according to the returned response.
"""
- response = self._send_oneliner_command('DMF')
+ response = self._send_oneliner_command("DMF")
return _parse_datetime(response[2:])
def _set_device_datetime(self, date):
response = self._send_oneliner_command(
- 'DMT' + date.strftime('%m/%d/%y %H:%M:%S'))
+ "DMT" + date.strftime("%m/%d/%y %H:%M:%S")
+ )
return _parse_datetime(response[2:])
def zero_log(self):
@@ -239,8 +240,8 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
This function will clear the memory of the device deleting all the
readings in an irrecoverable way.
"""
- response = self._send_oneliner_command('DMZ')
- if response != 'Z':
+ response = self._send_oneliner_command("DMZ")
+ if response != "Z":
raise exceptions.InvalidResponse(response)
_GLUCOSE_UNIT_RE = re.compile(r'^SU\?,"(MG/DL |MMOL/L)"')
@@ -260,15 +261,15 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
unit used for display. This is not settable by the user in all modern
meters.
"""
- response = self._send_oneliner_command('DMSU?')
+ response = self._send_oneliner_command("DMSU?")
match = self._GLUCOSE_UNIT_RE.match(response)
unit = match.group(1)
- if unit == 'MG/DL ':
+ if unit == "MG/DL ":
return common.Unit.MG_DL
- if unit == 'MMOL/L':
+ if unit == "MMOL/L":
return common.Unit.MMOL_L
raise exceptions.InvalidGlucoseUnit(response)
@@ -287,10 +288,10 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
expected.
"""
- self._send_command('DMP')
+ self._send_command("DMP")
data = self.serial_.readlines()
- header = data.pop(0).decode('ascii')
+ header = data.pop(0).decode("ascii")
match = _DUMP_HEADER_RE.match(header)
if not match:
raise exceptions.InvalidResponse(header)
@@ -299,7 +300,7 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
assert count == len(data)
for line in data:
- line = _validate_and_strip_checksum(line.decode('ascii'))
+ line = _validate_and_strip_checksum(line.decode("ascii"))
match = _DUMP_LINE_RE.match(line)
if not match:
@@ -307,11 +308,12 @@ class Device(serial.SerialDevice, driver_base.GlucometerDriver):
line_data = match.groupdict()
- date = _parse_datetime(line_data['datetime'])
- meal = _MEAL_CODES[line_data['meal']]
- comment = _COMMENT_CODES[line_data['comment']]
+ date = _parse_datetime(line_data["datetime"])
+ meal = _MEAL_CODES[line_data["meal"]]
+ comment = _COMMENT_CODES[line_data["comment"]]
# OneTouch2 always returns the data in mg/dL even if the glucometer
# is set to mmol/L, so there is no conversion required.
yield common.GlucoseReading(
- date, float(line_data['value']), meal=meal, comment=comment)
+ date, float(line_data["value"]), meal=meal, comment=comment
+ )