summaryrefslogtreecommitdiffstats
path: root/glucometerutils/drivers/fslibre.py
blob: c213ccdb70ae2a46ee70fa9f7e9a36b9c8c1efbd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# -*- coding: utf-8 -*-
"""Driver for FreeStyle Libre CGM devices."""

__author__ = 'Diego Elio Pettenò'
__email__ = 'flameeyes@flameeyes.eu'
__copyright__ = 'Copyright © 2017, Diego Elio Pettenò'
__license__ = 'MIT'

import datetime

from glucometerutils import common
from glucometerutils.support import freestyle

# Fields of the records returned by $history?
# Tuple of pairs of idx and field name
_HISTORY_ENTRY_MAP = (
    (2, 'month'),
    (3, 'day'),
    (4, 'year'),  # 2-digits
    (5, 'hour'),
    (6, 'minute'),
    (7, 'second'),
    (13, 'value'),
    (15, 'errors'),
)


class Device(freestyle.FreeStyleHidDevice):
    """Glucometer driver for FreeStyle Libre devices."""

    def get_meter_info(self):
        """Return the device information in structured form."""
        return common.MeterInfo(
            'FreeStyle Libre',
            serial_number=self.get_serial_number(),
            version_info=(
                'Software version: ' + self._get_version(),),
            native_unit=self.get_glucose_unit())

    def get_serial_number(self):
        """Overridden function as the command is not compatible."""
        return self._send_text_command(b'$sn?').rstrip('\r\n')

    def get_glucose_unit(self):
        """Returns the glucose unit of the device."""
        # TODO(Flameeyes): figure out how to identify the actual unit on the
        # device.
        return common.UNIT_MGDL

    def get_readings(self):
        for record in self._get_multirecord(b'$history?'):
            if not record:
                continue

            parsed_record = {
                key: int(record[idx])
                for idx, key in _HISTORY_ENTRY_MAP
            }

            if parsed_record['errors'] != 0:
                # The reading is considered invalid, so ignore it.
                continue

            timestamp = datetime.datetime(
                parsed_record['year'] + 2000,
                parsed_record['month'],
                parsed_record['day'],
                parsed_record['hour'],
                parsed_record['minute'],
                parsed_record['second'])

            yield common.Reading(timestamp, parsed_record['value'],
                                 comment='(Sensor)')