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)
Beispiel #4
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']},
    )
Beispiel #5
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_'))
    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)
Beispiel #6
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