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))
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))
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)
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))
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)
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
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)
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))