Example #1
0
 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,
     )
Example #2
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:
        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']},
    )
Example #3
0
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