Beispiel #1
0
 def _get_reading(self, record_id):
     response = self._send_request(3, _READ_RECORD_REQUEST,
                                   {'record_id': record_id},
                                   _READ_RECORD_RESPONSE)
     return common.GlucoseReading(response.timestamp,
                                  float(response.value),
                                  meal=response.meal)
Beispiel #2
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.GlucoseReading(
                _extract_timestamp(parsed_record),
                parsed_record['value'],
                comment='(Sensor)',
                measure_method=common.MeasurementMethod.CGM,
                extra_data={'device_id': parsed_record['device_id']},
            )

        # 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 #3
0
    def get_readings(self) -> Generator[common.AnyReading, None, None]:
        # First of all get the usually longer list of sensor readings, and
        # convert them to Readings objects.
        for record in self._session.query_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.GlucoseReading(
                _extract_timestamp(parsed_record),
                parsed_record["value"],
                comment="(Sensor)",
                measure_method=common.MeasurementMethod.CGM,
                extra_data={"device_id": parsed_record["device_id"]},
            )

        # Then get the results of explicit scans and blood tests (and other
        # events).
        for record in self._session.query_multirecord(b"$arresult?"):
            logging.debug(f"Retrieved arresult: {record!r}")
            reading = _parse_arresult(record)
            if reading:
                yield reading
Beispiel #4
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.
    """
        for line in self.device_results_:
            value = line['value']
            day = line['day']
            month = line['month']
            year = line['year']
            hour = line['hour']
            minute = line['minute']
            timestamp = line['timestamp']
            # fixme
            # The reading, if present, is always in mg/dL even if the glucometer is
            # set to mmol/L.
            yield common.GlucoseReading(timestamp, value)
  def get_readings(self):
    for record in self._get_records_reader():
      if record[_RESULT_CSV_KEY] is None:
        continue

      yield common.GlucoseReading(
        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 #6
0
 def test_minimal(self):
     reading = common.GlucoseReading(TEST_DATETIME, 100)
     self.assertEqual(
         reading.as_csv(common.Unit.MG_DL),
         '"2018-01-01 00:30:45","100.00","","blood sample",""',
     )
     self.assertEqual(
         len(list(csv.reader([reading.as_csv(common.Unit.MG_DL)]))[0]),
         CSV_FIELD_COUNT,
     )
Beispiel #7
0
 def get_readings(self):
     """
     Get reading dump from download data mode(all readings stored)
     This meter supports only blood samples
     """
     for parsed_record in self._get_multirecord():
         yield common.GlucoseReading(
             _extract_timestamp(parsed_record),
             int(parsed_record['value']),
             comment=parsed_record['markers'],
             measure_method=common.MeasurementMethod.BLOOD_SAMPLE)
Beispiel #8
0
    def _get_reading(self, record_id):
        response = self._send_request(_READ_RECORD_REQUEST,
                                      {'record_id': record_id},
                                      _READING_RESPONSE)

        if response.control_test:
            logging.debug('control solution test, ignoring.')
            return None

        return common.GlucoseReading(response.timestamp,
                                     float(response.value),
                                     meal=response.meal)
Beispiel #9
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.GlucoseReading(timestamp, float(value))
Beispiel #10
0
    def _get_reading(self, record_id):
        _, reading_date_message = self._send_command(_GET_READING_DATETIME,
                                                     _select_record(record_id))
        reading_date = _parse_datetime(reading_date_message)

        _, reading_value_message = self._send_command(
            _GET_READING_VALUE, _select_record(record_id))
        reading_value = _READING_VALUE_STRUCT.parse(reading_value_message)

        return common.GlucoseReading(reading_date,
                                     reading_value.value,
                                     meal=reading_value.meal)
    def get_readings(self):
        count = self.wait_and_ready()

        for _ in range(count):
            self.send_message(_FETCH_MESSAGE)
            message = self.read_message()

            r = _READING.parse(message)
            logging.debug('received reading: %r', r)

            yield common.GlucoseReading(datetime.datetime(
                2000 + r.year, r.month, r.day, r.hour, r.minute),
                                        r.value,
                                        meal=r.meal)
Beispiel #12
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.GlucoseReading(
                datetime.datetime(
                    2000 + r.year, r.month, r.day, r.hour, r.minute),
                r.value, meal=meal)
Beispiel #13
0
    def get_readings(self) -> Generator[common.AnyReading, None, None]:
        for record in self._get_records_reader():
            if record[_RESULT_CSV_KEY] is None:
                continue

            yield common.GlucoseReading(
                self._extract_datetime(record),
                common.convert_glucose_unit(
                    float(record[_RESULT_CSV_KEY]),
                    _UNIT_MAP[record[_UNIT_CSV_KEY]],
                    common.Unit.MG_DL,
                ),
                meal=self._extract_meal(record),
            )
    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.GlucoseReading(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, meal_flag, unused_const4,
         unused_flags, unused_const5,
         unused_const6) = _STRUCT_RECORD.unpack(response)

        return common.GlucoseReading(_convert_timestamp(timestamp),
                                     float(value),
                                     meal=_MEAL_CODES[meal_flag])
Beispiel #16
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.GlucoseReading(date,
                                        float(line_data['value']),
                                        meal=meal,
                                        comment=comment)
Beispiel #17
0
    def get_readings(self) -> Generator[common.AnyReading, None, None]:
        """Iterates over the reading values stored in the glucometer.

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

        Yields:
          A GlucoseReading object representing the read value.

        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.GlucoseReading(date,
                                        float(line_data["value"]),
                                        meal=meal,
                                        comment=comment)
Beispiel #18
0
    def get_readings(self) -> Generator[common.AnyReading, None, None]:
        for reading in self._get_raw_readings():
            if reading.reading_type != "Glu":
                logging.warning(
                    f"Unsupported reading type {reading.reading_type!r}. Please file an issue at https://github.com/glucometers-tech/glucometerutils/issues"
                )
                continue

            mgdl_value = common.convert_glucose_unit(
                reading.value,
                from_unit=reading.unit,
                to_unit=common.Unit.MG_DL,
            )

            yield common.GlucoseReading(
                reading.timestamp,
                mgdl_value,
                meal=reading.meal,
                comment=reading.comment,
            )
Beispiel #19
0
    def get_readings(self) -> Generator[common.AnyReading, None, None]:
        count = self.wait_and_ready()

        for _ in range(count):
            self.send_message(_FETCH_MESSAGE)
            message = self.read_message()

            reading = _READING.parse(message)
            logging.debug("received reading: %r", reading)

            yield common.GlucoseReading(
                datetime.datetime(
                    2000 + reading.year,
                    reading.month,
                    reading.day,
                    reading.hour,
                    reading.minute,
                ),
                reading.value,
                meal=reading.meal,
            )
Beispiel #20
0
    def _get_reading(self, record_id: int) -> common.GlucoseReading:
        response = self._send_request(_READ_RECORD_REQUEST,
                                      {"record_id": record_id},
                                      _READING_RESPONSE)

        return common.GlucoseReading(response.timestamp, float(response.value))
 def test_csv(self, kwargs_dict, expected_csv):
     reading = common.GlucoseReading(self.TEST_DATETIME, 100, **kwargs_dict)
     self.assertEqual(reading.as_csv(common.Unit.MG_DL), expected_csv)
 def test_value(self, unit, expected_value):
     reading = common.GlucoseReading(self.TEST_DATETIME, 100)
     self.assertAlmostEqual(reading.get_value_as(unit),
                            expected_value,
                            places=2)
 def test_minimal(self):
     reading = common.GlucoseReading(self.TEST_DATETIME, 100)
     self.assertEqual(
         reading.as_csv(common.Unit.MG_DL),
         '"2018-01-01 00:30:45","100.00","","blood sample",""')
Beispiel #24
0
    def get_readings(self) -> Generator[common.AnyReading, None, None]:
        """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":
                logging.warning("Non-glucose readings are not supported, ignoring.")
                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.GlucoseReading(timestamp, value)
Beispiel #25
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':
                logging.warning(
                    'Non-glucose readings are not supported, ignoring.')
                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.GlucoseReading(timestamp, value)