diff options
Diffstat (limited to 'glucometerutils/drivers/otultra2.py')
-rw-r--r-- | glucometerutils/drivers/otultra2.py | 112 |
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 + ) |