Beispiel #1
0
    def get_readings(self):
        for record in self._get_records_reader():
            if record[_RESULT_CSV_KEY] is None:
                continue

            yield common.Reading(self._extract_datetime(record),
                                 common.convert_glucose_unit(
                                     float(record[_RESULT_CSV_KEY]),
                                     _UNIT_MAP[record[_UNIT_CSV_KEY]]),
                                 meal=self._extract_meal(record))
Beispiel #2
0
    def get_readings(self):
        count_response = self._get_reading(_INVALID_RECORD)

        record_count, = _STRUCT_RECORDID.unpack_from(count_response.data, 2)

        for record_id in range(record_count):
            record_response = self._get_reading(record_id)

            timestamp = _convert_timestamp(record_response.data[2:6])
            value, = _STRUCT_TIMESTAMP.unpack_from(record_response.data, 6)

            yield common.Reading(timestamp, float(value))
Beispiel #3
0
    def get_readings(self):
        count = self.wait_and_ready()

        for _ in range(count):
            self.send_packet(_FETCH_PACKET)
            rpkt = self.read_packet()

            r = parse_reading(rpkt)
            meal = _MEAL_FLAG[r.meal_flag]

            yield common.Reading(
                datetime.datetime(
                    2000 + r.year, r.month, r.day, r.hour, r.minute),
                r.value, meal=meal)
Beispiel #4
0
    def get_readings(self):
        """Iterate through the reading records in the device."""
        for record in self._get_multirecord(b'$result?'):
            if not record or record[0] != _TYPE_GLUCOSE_READING:
                continue

            # Build a reading object by parsing each of the entries in the CSV
            # as integers.
            raw_reading = _InsulinxReading._make([int(v) for v in record])

            timestamp = datetime.datetime(raw_reading.year + 2000,
                                          raw_reading.month, raw_reading.day,
                                          raw_reading.hour, raw_reading.minute)

            yield common.Reading(timestamp, raw_reading.value)
  def _get_reading(self, record_number):
    request = (_READ_RECORD_REQUEST_PREFIX +
               _STRUCT_RECORDID.pack(record_number) +
               _READ_RECORD_REQUEST_SUFFIX)
    response = self._send_message(request, 3)
    if response[0:2] != b'\x04\06':
      raise lifescan.MalformedCommand(
        'invalid response, expected 04 06, received %02x %02x' % (
          response[0], response[1]))

    (unused_const1, unused_const2, unused_counter, unused_const3,
     unused_counter2, timestamp, value, unused_flags, unused_const4,
     unused_const5) = _STRUCT_RECORD.unpack(response)

    return common.Reading(_convert_timestamp(timestamp), float(value))
Beispiel #6
0
    def get_readings(self):
        """Iterates over the reading values stored in the glucometer.

    Args:
      unit: The glucose unit to use for the output.

    Yields:
      A tuple (date, value) of the readings in the glucometer. The value is a
      floating point in the unit specified; if no unit is specified, the default
      unit in the glucometer will be used.

    Raises:
      exceptions.InvalidResponse: if the response does not match what expected.
    """
        self._send_command('DMP')
        data = self.serial_.readlines()

        header = data.pop(0).decode('ascii')
        match = _DUMP_HEADER_RE.match(header)
        if not match:
            raise exceptions.InvalidResponse(header)

        count = int(match.group(1))
        assert count == len(data)

        for line in data:
            line = _validate_and_strip_checksum(line.decode('ascii'))

            match = _DUMP_LINE_RE.match(line)
            if not match:
                raise exceptions.InvalidResponse(line)

            line_data = match.groupdict()

            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.Reading(date,
                                 float(line_data['value']),
                                 meal=meal,
                                 comment=comment)
Beispiel #7
0
    def get_readings(self):

        # First of all get the usually longer list of sensor readings, and
        # convert them to Readings objects.
        for record in self._get_multirecord(b'$history?'):
            parsed_record = _parse_record(record, _HISTORY_ENTRY_MAP)

            if not parsed_record or parsed_record['errors'] != 0:
                # The reading is considered invalid, so ignore it.
                continue

            yield common.Reading(_extract_timestamp(parsed_record),
                                 parsed_record['value'],
                                 comment='(Sensor)')

        # Then get the results of explicit scans and blood tests (and other
        # events).
        for record in self._get_multirecord(b'$arresult?'):
            reading = _parse_arresult(record)
            if reading:
                yield reading
Beispiel #8
0
    def get_readings(self):
        """Iterates over the reading values stored in the glucometer.

    Args:
      unit: The glucose unit to use for the output.

    Yields:
      A tuple (date, value) of the readings in the glucometer. The value is a
      floating point in the unit specified; if no unit is specified, the default
      unit in the glucometer will be used.

    Raises:
      exceptions.InvalidResponse: if the response does not match what expected.
    """
        data = self._send_command('xmem')

        # The first line is empty, the second is the serial number, the third the
        # version, the fourth the current time, and the fifth the record count.. The
        # last line has a checksum and the end.
        count = int(data[4])
        if count != (len(data) - 6):
            raise exceptions.InvalidResponse('\n'.join(data))

        # Extract the checksum from the last line.
        checksum_match = _CHECKSUM_RE.match(data[-1])
        if not checksum_match:
            raise exceptions.InvalidResponse('\n'.join(data))

        expected_checksum = int(checksum_match.group('checksum'), 16)
        # exclude the last line in the checksum calculation, as that's the checksum
        # itself. The final \r\n is added separately.
        calculated_checksum = sum(ord(c)
                                  for c in '\r\n'.join(data[:-1])) + 0xd + 0xa

        if expected_checksum != calculated_checksum:
            raise exceptions.InvalidChecksum(expected_checksum,
                                             calculated_checksum)

        for line in data[5:-1]:
            match = _READING_RE.match(line)
            if not match:
                raise exceptions.InvalidResponse(line)

            if match.group('type') != 'G':
                print('Non-glucose readings are not supported, ignoring.',
                      file=sys.stderr)
                continue

            if match.group('reading') == 'HI ':
                value = float("inf")
            else:
                value = float(match.group('reading'))

            day = int(match.group('day'))
            month = _MONTH_MATCHES[match.group('month')]
            year = int(match.group('year'))

            hour, minute = map(int, match.group('time').split(':'))

            timestamp = datetime.datetime(year, month, day, hour, minute)

            # The reading, if present, is always in mg/dL even if the glucometer is
            # set to mmol/L.
            yield common.Reading(timestamp, value)
Beispiel #9
0
def _parse_arresult(record):
    """Takes an array of string fields as input and parses it into a Reading."""

    parsed_record = _parse_record(record, _BASE_ENTRY_MAP)

    # There are other record types, but we don't currently need to expose these.
    if not parsed_record or parsed_record['type'] != 2:
        return None

    parsed_record.update(_parse_record(record, _ARRESULT_TYPE2_ENTRY_MAP))

    # Check right away if we have rapid insulin
    if parsed_record['rapid-acting-flag']:
        parsed_record.update(
            _parse_record(record, _ARRESULT_RAPID_INSULIN_ENTRY_MAP))

    if parsed_record['errors']:
        return None

    comment_parts = []

    if parsed_record['reading-type'] == 2:
        comment_parts.append('(Scan)')
    elif parsed_record['reading-type'] == 0:
        comment_parts.append('(Blood)')
    else:
        # ketone reading
        return None

    custom_comments = record[29:35]
    for comment_index in range(6):
        if parsed_record['custom-comments-bitfield'] & (1 << comment_index):
            comment_parts.append(custom_comments[comment_index][1:-1])

    if parsed_record['sport-flag']:
        comment_parts.append('Sport')

    if parsed_record['medication-flag']:
        comment_parts.append('Medication')

    if parsed_record['food-flag']:
        if parsed_record['food-carbs-grams']:
            comment_parts.append('Food (%d g)' %
                                 parsed_record['food-carbs-grams'])
        else:
            comment_parts.append('Food')

    if parsed_record['long-acting-flag']:
        if parsed_record['double-long-acting-insulin']:
            comment_parts.append(
                'Long-acting insulin (%d)' %
                (parsed_record['double-long-acting-insulin'] / 2))
        else:
            comment_parts.append('Long-acting insulin')

    if parsed_record['rapid-acting-flag']:
        if parsed_record['double-rapid-acting-insulin']:
            comment_parts.append(
                'Rapid-acting insulin (%d)' %
                (parsed_record['double-rapid-acting-insulin'] / 2))
        else:
            comment_parts.append('Rapid-acting insulin')

    return common.Reading(_extract_timestamp(parsed_record),
                          parsed_record['value'],
                          comment='; '.join(comment_parts))