def get_readings(self): """Iterate through the reading records in the device.""" for record in self._get_multirecord(b'$result?'): cls = None if record and record[0] == _TYPE_GLUCOSE_READING: cls = common.GlucoseReading elif record and record[0] == _TYPE_KETONE_READING: cls = common.KetoneReading else: continue # Build a _reading object by parsing each of the entries in the raw # record values = [] for value in record: if value == "HI": value = float("inf") values.append(int(value)) raw_reading = _NeoReading._make(values[:len(_NeoReading._fields)]) timestamp = datetime.datetime(raw_reading.year + 2000, raw_reading.month, raw_reading.day, raw_reading.hour, raw_reading.minute) if record and record[0] == _TYPE_KETONE_READING: value = freestyle.convert_ketone_unit(raw_reading.value) else: value = raw_reading.value yield cls(timestamp, value)
def get_readings(self): """Iterate through the reading records in the device.""" for record in self._get_multirecord(b'$result?'): cls = None if record and record[0] == _TYPE_GLUCOSE_READING: cls = common.GlucoseReading elif record and record[0] == _TYPE_KETONE_READING: cls = common.KetoneReading else: continue # Build a _reading object by parsing each of the entries in the raw # record values = [] for value in record: if value == "HI": value = float("inf") values.append(int(value)) raw_reading = _NeoReading._make(values[:len(_NeoReading._fields)]) timestamp = datetime.datetime( raw_reading.year + 2000, raw_reading.month, raw_reading.day, raw_reading.hour, raw_reading.minute) if record and record[0] == _TYPE_KETONE_READING: value = freestyle.convert_ketone_unit(raw_reading.value) else: value = raw_reading.value yield cls(timestamp, value)
def get_readings(self) -> Generator[common.AnyReading, None, None]: """Iterate through the reading records in the device.""" for record in self._session.query_multirecord(b"$result?"): cls: Optional[Type[common.AnyReading]] = None if record and record[0] == _TYPE_GLUCOSE_READING: cls = common.GlucoseReading elif record and record[0] == _TYPE_KETONE_READING: cls = common.KetoneReading else: continue # Build a _NeoReading object by parsing each of the entries in the raw # record raw_reading = _NeoReading(record) timestamp = datetime.datetime( raw_reading.year + 2000, raw_reading.month, raw_reading.day, raw_reading.hour, raw_reading.minute, ) if record and record[0] == _TYPE_KETONE_READING: value = freestyle.convert_ketone_unit(raw_reading.value) else: value = raw_reading.value yield cls(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: return None elif parsed_record['type'] == 2: parsed_record.update(_parse_record(record, _ARRESULT_TYPE2_ENTRY_MAP)) elif parsed_record['type'] == 5: parsed_record.update( _parse_record(record, _ARRESULT_TIME_ADJUSTMENT_ENTRY_MAP)) return common.TimeAdjustment( _extract_timestamp(parsed_record), _extract_timestamp(parsed_record, 'old_'), extra_data={'device_id': parsed_record['device_id']}, ) else: return None # 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 = [] measure_method = None cls = None value = None if parsed_record['reading-type'] == 2: comment_parts.append('(Scan)') measure_method = common.MeasurementMethod.CGM cls = common.GlucoseReading value = parsed_record['value'] elif parsed_record['reading-type'] == 0: comment_parts.append('(Blood)') measure_method = common.MeasurementMethod.BLOOD_SAMPLE cls = common.GlucoseReading value = parsed_record['value'] elif parsed_record['reading-type'] == 1: comment_parts.append('(Ketone)') measure_method = common.MeasurementMethod.BLOOD_SAMPLE cls = common.KetoneReading # automatically convert the raw value in mmol/L value = freestyle.convert_ketone_unit(parsed_record['value']) else: # unknown 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 (%.1f)' % (parsed_record['double-long-acting-insulin'] / 2.)) else: comment_parts.append('Long-acting insulin') if parsed_record['rapid-acting-flag']: # provide default value, as this record does not always exist # (even if rapid-acting-flag is set) if parsed_record.get('double-rapid-acting-insulin', 0): comment_parts.append( 'Rapid-acting insulin (%.1f)' % (parsed_record['double-rapid-acting-insulin'] / 2.)) else: comment_parts.append('Rapid-acting insulin') return cls( _extract_timestamp(parsed_record), value, comment='; '.join(comment_parts), measure_method=measure_method, extra_data={'device_id': parsed_record['device_id']}, )
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: return None elif parsed_record['type'] == 2: parsed_record.update(_parse_record(record, _ARRESULT_TYPE2_ENTRY_MAP)) elif parsed_record['type'] == 5: parsed_record.update(_parse_record(record, _ARRESULT_TIME_ADJUSTMENT_ENTRY_MAP)) return common.TimeAdjustment( _extract_timestamp(parsed_record), _extract_timestamp(parsed_record, 'old_')) else: return None # 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 = [] measure_method = None cls = None value = None if parsed_record['reading-type'] == 2: comment_parts.append('(Scan)') measure_method = common.MeasurementMethod.CGM cls = common.GlucoseReading value = parsed_record['value'] elif parsed_record['reading-type'] == 0: comment_parts.append('(Blood)') measure_method = common.MeasurementMethod.BLOOD_SAMPLE cls = common.GlucoseReading value = parsed_record['value'] elif parsed_record['reading-type'] == 1: comment_parts.append('(Ketone)') measure_method = common.MeasurementMethod.BLOOD_SAMPLE cls = common.KetoneReading # automatically convert the raw value in mmol/L value = freestyle.convert_ketone_unit(parsed_record['value']) else: # unknown 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 (%.1f)' % (parsed_record['double-long-acting-insulin']/2.)) else: comment_parts.append('Long-acting insulin') if parsed_record['rapid-acting-flag']: # provide default value, as this record does not always exist # (even if rapid-acting-flag is set) if parsed_record.get('double-rapid-acting-insulin', 0): comment_parts.append( 'Rapid-acting insulin (%.1f)' % (parsed_record['double-rapid-acting-insulin']/2.)) else: comment_parts.append('Rapid-acting insulin') return cls( _extract_timestamp(parsed_record), value, comment='; '.join(comment_parts), measure_method=measure_method)
def _parse_arresult(record: Sequence[str]) -> Optional[common.AnyReading]: """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: return None elif parsed_record["type"] == 2: parsed_record.update(_parse_record(record, _ARRESULT_TYPE2_ENTRY_MAP)) elif parsed_record["type"] == 5: parsed_record.update( _parse_record(record, _ARRESULT_TIME_ADJUSTMENT_ENTRY_MAP)) return common.TimeAdjustment( _extract_timestamp(parsed_record), _extract_timestamp(parsed_record, "old_"), extra_data={"device_id": parsed_record["device_id"]}, ) else: return None # 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 = [] measure_method: Optional[common.MeasurementMethod] = None cls: Optional[Type[common.AnyReading]] = None value: Optional[float] = None if parsed_record["reading-type"] == 2: comment_parts.append("(Scan)") measure_method = common.MeasurementMethod.CGM cls = common.GlucoseReading value = parsed_record["value"] elif parsed_record["reading-type"] == 0: comment_parts.append("(Blood)") measure_method = common.MeasurementMethod.BLOOD_SAMPLE cls = common.GlucoseReading value = parsed_record["value"] elif parsed_record["reading-type"] == 1: comment_parts.append("(Ketone)") measure_method = common.MeasurementMethod.BLOOD_SAMPLE cls = common.KetoneReading # automatically convert the raw value in mmol/L raw_value = parsed_record["value"] if raw_value is None: raise ValueError(f"Invalid Ketone value: {parsed_record!r}") value = freestyle.convert_ketone_unit(raw_value) else: # unknown 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]) if parsed_record["sport-flag"]: comment_parts.append("Sport") if parsed_record["medication-flag"]: comment_parts.append("Medication") if parsed_record["food-flag"]: grams = parsed_record["food-carbs-grams"] if grams: comment_parts.append(f"Food ({grams} g)") else: comment_parts.append("Food") if parsed_record["long-acting-flag"]: insulin = parsed_record["double-long-acting-insulin"] / 2 if insulin: comment_parts.append(f"Long-acting insulin ({insulin:.1f})") else: comment_parts.append("Long-acting insulin") if parsed_record["rapid-acting-flag"]: # This record does not always exist, so calculate it only when present. if "double-rapid-acting-insulin" in parsed_record: rapid_insulin = parsed_record["double-rapid-acting-insulin"] / 2 comment_parts.append(f"Rapid-acting insulin ({rapid_insulin:.1f})") else: comment_parts.append("Rapid-acting insulin") reading = cls( _extract_timestamp(parsed_record), value, comment="; ".join(comment_parts), measure_method=measure_method, extra_data={"device_id": parsed_record["device_id"]}, ) return reading