def test_minimal(self): reading = common.TimeAdjustment(TEST_DATETIME, TEST_OLD_DATETIME) self.assertEqual( reading.as_csv(common.Unit.MG_DL), '"2018-01-01 00:30:45","","","time","2016-02-02 01:31:46"', ) self.assertEqual( len(list(csv.reader([reading.as_csv(common.Unit.MG_DL)]))[0]), CSV_FIELD_COUNT, )
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: 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