Пример #1
0
def test_get_dated_entries(setup_and_teardown):
    """
    Get multiple dated entries from corresponding dated reports.
    """

    datetimes = [
        datetime.datetime(1970, 1, 1, 0, 0, 0),
        datetime.datetime(1970, 1, 2, 0, 0, 0),
        datetime.datetime(1970, 1, 3, 0, 0, 0)
    ]

    formattedDatetimes = [lib.formatTime(d) for d in datetimes]

    dates = [d.date() for d in datetimes]

    values = [6.2, 6.0, 5.8]

    entries = dict(zip(datetimes, values))

    formattedEntries = dict(zip(formattedDatetimes, values))

    branch = ["A", "B"]

    # Add dated entries to corresponding reports (the latter will be created
    # if needed)
    reporter.setDatedEntries(DatedReport, branch, entries, path.TESTS)

    # Try and find entries in given dated reports
    # Search for entries strictly: none should be missing!
    storedEntries = reporter.getDatedEntries(DatedReport, dates, branch,
                                             path.TESTS, True)

    assert storedEntries == formattedEntries
Пример #2
0
def test_load(setup_and_teardown):
    """
    Create a profile and load its data.
    """

    profile = [(getTime("23:30:00", "1970.01.01"), 6.2),
               (getTime("00:00:00", "1970.01.02"), 6),
               (getTime("00:30:00", "1970.01.02"), 5.8),
               (getTime("01:00:00", "1970.01.02"), 5.6)]

    # Create dated entries
    reporter.setDatedEntries(test_reporter.DatedReport, [], dict(profile),
                             path.TESTS)

    # Create profile with no loading method implemented
    p = Profile()

    # Try loading
    with pytest.raises(NotImplementedError):
        p.load()

    # Create a past profile (for its existing load method) and define its time
    # references (exclude first and last datetimes)
    p = PastProfile()
    p.define(profile[1][0], profile[-1][0])

    # Load its data using previously generated test dated reports
    p.load()

    # One day before start of profile should have been added to its days
    assert p.data == dict([(lib.formatTime(d), y) for (d, y) in profile])
Пример #3
0
    def tuneBestFrequency(self, pump):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            TUNEBESTFREQUENCY
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Check if frequency optimizing required.
        """

        # Get current formatted time
        now = datetime.datetime.now()

        # Get last frequency optimization
        entry = self.report.get(["Frequency"])

        # Entry exists
        if entry:

            # Destructure frequency entry
            [f, t] = entry

            # Convert time to datetime object
            t = lib.formatTime(t)

        # No frequency stored or stick not tuned today
        if entry is None or now.day != t.day:

            # Scan for best frequency
            f = self.scanFrequencies(pump)

        # Tune radio
        self.tune(f)
Пример #4
0
    def run(self, now, hours = 24):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            RUN
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Store current time
        self.now = now

        # Compute past time
        past = now - datetime.timedelta(hours = hours)

        # Build it for last 24 hours
        self.net.build(past, self.now, suspend.Suspend(), resume.Resume(),
                                       basal.Basal(), TB.TB())

        # Format net profile
        self.net = dict(zip([lib.formatTime(T) for T in self.net.T],
                            [round(y, 2) for y in self.net.y]))

        # Get data
        self.get()

        # Fill reports
        self.fill()

        # Store reports to exports directory
        for report in self.reports.values():

            # Do it
            report.store(Reporter.exp.str)
Пример #5
0
def setDatedEntries(reportType, branch, entries, src = path.REPORTS):

    """
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        SETDATEDENTRIES
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Store a set of dated entries in their corresponding dated reports.
    """

    # Test report type
    if not issubclass(reportType, DatedReport):
        raise TypeError("Cannot add dated values to non dated report.")

    # Test values
    if not all([type(e) is datetime.datetime for e in entries]):
        raise TypeError("Cannot add non dated values to dated report.")

    # Initialize needed reports
    reports = {}

    # Get all concerned dates
    dates = lib.uniqify([e.date() for e in entries])

    # Each date corresponds to a report
    for date in dates:
        reports[date] = getReportByType(reportType, date, src,
            strict = False)

    # Add values to reports
    for key, value in entries.items():
        reports[key.date()].set(value, branch + [lib.formatTime(key)], True)

    # Store reports
    storeReportsByType(reportType, dates)
Пример #6
0
    def get(self, name, branch, key=None, date=None):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            GET
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Load report
        report = self.getReport(name, date, None, False)

        # Get section
        section = self.getSection(report, branch)

        # If key was provided
        if key is not None:

            # If key is a date
            if date is not None:

                # Format key
                key = lib.formatTime(key)

            # Get corresponding value
            entry = self.getEntry(section, key)

            # Return it
            return entry

        # Otherwise
        else:

            # Return section
            return section
Пример #7
0
    def start(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            START
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Define starting time
        self.t0 = datetime.datetime.now()

        # Give user info
        Logger.info("Started loop.")

        # Start CGM
        self.cgm.start()

        # Start pump
        self.pump.start()

        # LED on
        self.pump.stick.commands["LED On"].run()

        # Update last loop time
        Reporter.add(self.report, ["Status"],
                     {"Time": lib.formatTime(self.t0)}, True)

        # Update loop iterations
        Reporter.increment(self.report, ["Status"], "N")
Пример #8
0
    def start(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            START
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Give user info
        Logger.info("Started loop.")

        # Define starting time
        self.t0 = datetime.datetime.now()

        # Update last loop time
        Reporter.add(self.report, ["Status"],
                     {"Time": lib.formatTime(self.t0)}, True)

        # Update loop iterations
        Reporter.increment(self.report, ["Status"], "N")

        # Start CGM
        self.cgm.start()

        # Start pump
        self.pump.start()
Пример #9
0
    def run(self, now, hours = 24):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            RUN
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Store current time
        self.now = now

        # Compute past time
        self.past = now - datetime.timedelta(hours = hours)

        # Build it for last 24 hours
        self.net.build(self.past, self.now, basal.Basal(),
                                            TB.TB(),
                                            suspend.Suspend(),
                                            resume.Resume())

        # Format net profile
        self.net = dict(zip([lib.formatTime(T) for T in self.net.T],
                            [round(y, 2) for y in self.net.y]))

        # Get data
        self.get()

        # Fill reports
        self.fill()

        # Export reports
        for report in self.reports.values():

            # Do it
            report.store(Reporter.exp.str)
Пример #10
0
    def read(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            READ
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Execute command
        self.commands["ReadSystemTime"].execute()

        # Compute time delta since epoch
        delta = datetime.timedelta(seconds = lib.unpack(
            self.commands["ReadSystemTime"].response["Payload"], "<"))

        # Assign response
        self.systemTime = self.epoch + delta

        # Give user info
        Logger.info("System time: " + lib.formatTime(self.systemTime))

        # Execute command
        self.commands["ReadMode"].execute()

        # Assign response
        self.mode = self.modes[lib.unpack(
            self.commands["ReadMode"].response["Payload"], "<")]

        # Give user info
        Logger.info("Clock mode: " + self.mode)

        # Store clock mode
        self.store()
Пример #11
0
def computeIOBs(t, T, Net, IDC):
    """
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        COMPUTEIOBS
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        This function computes the IOB at a given time.
    """

    # Initialize IOBs
    IOBs = []

    # Compute IOB for each BG
    for i in range(len(T)):

        # Copy net insulin profile
        net_ = copy.deepcopy(Net)

        # Cut it for current IOB computation
        start = T[i] - datetime.timedelta(hours=IDC.DIA)
        end = T[i]
        net_.cut(start, end)
        net_.normalize()

        # Compute corresponding IOB, store, and show it
        IOB = calculator.computeIOB(net_, IDC)
        IOBs += [IOB]
        print "IOB(" + lib.formatTime(end) + ") = " + fmt.IOB(IOB)

    return IOBs
Пример #12
0
    def start(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            START
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            The loop is only considered started after the devices have been
            initialized and are ready to receive orders.
        """

        # Info
        Logger.info("Started loop.")

        # Define starting time
        self.t0 = datetime.datetime.now()

        # Get current day
        today = self.t0.date()

        # Get report
        self.report = reporter.getReportByType(reporter.LoopReport,
                                               today,
                                               strict=False)

        # Update loop stats
        self.report.set(lib.formatTime(self.t0), ["Loop", "Last Time"], True)
        self.report.increment(["Loop", "Start"])
        self.report.store()
Пример #13
0
    def get(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            GET
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Info
        Logger.debug("Reading recent data...")

        # Define dates
        today = self.now.date()
        yesterday = today - datetime.timedelta(days=1)
        then = self.now - datetime.timedelta(hours=24)

        # Build net insulin profile for last 24 hours
        _net = net.Net()
        _net.build(then, self.now, False)

        # Format and store its data
        self.data["net"] = dict(
            zip([lib.formatTime(T) for T in _net.T],
                [round(y, 2) for y in _net.y]))

        # Get pump data
        self.data["pump"] = reporter.getPumpReport().get()

        # Get recent BGs
        self.data["bgs"] = reporter.getDatedEntries(reporter.BGReport,
                                                    [yesterday, today], [])

        # Get recent boluses
        self.data["boluses"] = reporter.getDatedEntries(
            reporter.TreatmentsReport, [yesterday, today], ["Boluses"])

        # Get recent IOBs
        self.data["iobs"] = reporter.getDatedEntries(reporter.TreatmentsReport,
                                                     [yesterday, today],
                                                     ["IOB"])

        # Get recent history
        self.data["history"] = reporter.getDatedEntries(
            reporter.HistoryReport, [yesterday, today], [])

        # Get recent sensor statuses (last session)
        # With n = 1, only today's history report would be considered, thus + 1
        self.data["statuses"] = reporter.getRecentDatedEntries(
            reporter.HistoryReport, self.now, ["CGM", "Sensor Statuses"],
            MAX_SENSOR_AGE + 1)

        # Get recent calibrations
        self.data["calibrations"] = reporter.getDatedEntries(
            reporter.HistoryReport, [yesterday, today],
            ["CGM", "Calibrations"])

        # Get recent errors
        self.data["errors"] = reporter.getDatedEntries(reporter.ErrorsReport,
                                                       [today], [])
Пример #14
0
    def read(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            READ
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Read last time pump's radio transmitter was powered up
        self.value = lib.formatTime(Reporter.get("pump.json", [], "Power"))
Пример #15
0
    def __str__(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            STR
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        return ("Sensor status: " + str(self.status) + " (" +
                lib.formatTime(self.displayTime) + ")")
Пример #16
0
    def __str__(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            STR
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        return ("BG calibration value: " + str(self.value) + " mmol/L (" +
                lib.formatTime(self.enteredTime) + ")")
Пример #17
0
    def __str__(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            STR
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        return ("Event: " + str(self.type) + ", " + str(self.subType) + ": " +
                str(self.value) + " (" + lib.formatTime(self.enteredTime) +
                ")")
Пример #18
0
    def read(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            READ
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Read last time pump's radio transmitter was powered up
        self.value = lib.formatTime(Reporter.get("pump.json", [], "Power"))
Пример #19
0
    def read(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            READ
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Read last time pump's radio transmitter was powered up
        self.value = lib.formatTime(self.report.get(["Power"]))
Пример #20
0
    def show(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            SHOW
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Show profile components.
        """

        # Define profile dictionary
        profiles = {"Standard t-axis": [self.T, self.y],
                    "Normalized t-axis": [self.t, self.y],
                    "Derivative": [self.t[:-1], self.dydt]}

        # Loop on each profile component
        for p in profiles:

            # Get axes
            axes = profiles[p]

            # Read number of entries
            nx = len(axes[0])
            ny = len(axes[1])

            # If profile exists
            if nx > 0 and nx == ny:

                # Give user info
                Logger.debug(p)

                # Show profile
                for i in range(nx):

                    # Get time
                    t = axes[0][i]

                    # Format time if necessary
                    if type(t) is not float:

                        # Format it
                        t = lib.formatTime(t)

                    # Get value
                    y = axes[1][i]

                    # Format value if necessary
                    if type(y) is float or type(y) is np.float64:

                        # Format it
                        y = round(y, 2)

                    # Give user info
                    Logger.debug(str(y) + " - (" + str(t) + ")")
Пример #21
0
    def show(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            SHOW
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Show profile components.
        """

        # Define profile dictionary
        profile = {"Standard t-axis": [self.T, self.y],
                   "Normalized t-axis": [self.t, self.y],
                   "Derivative": [self.t, self.dydt]}

        # Loop on each profile component
        for p in profile:

            # Get axes
            axes = profile[p]

            # If component exists
            if axes[0] and axes[1]:

                # Give user info
                Logger.debug(p)

                # Read number of entries
                n = len(axes[1])

                # Show profile
                for i in range(n):

                    # Get time
                    t = axes[0][i]

                    # Format time if necessary
                    if type(t) is not float:

                        # Format it
                        t = lib.formatTime(t)

                    # Get value
                    y = axes[1][i]

                    # Format value if necessary
                    if type(y) is float or type(y) is np.float64:

                        # Format it
                        y = round(y, 2)

                    # Give user info
                    Logger.debug(str(y) + " - (" + str(t) + ")")
Пример #22
0
    def __str__(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            STR
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        value = self.value

        if type(value) is float:
            value = fmt.BG(value)

        return ("BG: " + str(value) + " " + str(self.trend) + " (" +
                lib.formatTime(self.displayTime) + ")")
Пример #23
0
    def decouple(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECOUPLE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Decouple profile data into components: convert string time values to
            datetime objects and get corresponding y-axis value.
        """

        # Info
        Logger.debug("Decoupling components of: " + repr(self))

        # Decouple data, convert string times to datetimes, and sort them in
        # chronological order
        [self.T, self.y] = lib.unzip([(lib.formatTime(T), y)
                                      for (T, y) in sorted(self.data.items())])
Пример #24
0
def computeExpectedBGDeltas(t, T, Net, IDC, ISFs):
    """
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        COMPUTEEXPECTEDBGDELTAS
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        This function computes an array of expected BG variations, given an IDC
        and a net insulin profile.
    """

    # Initialize expected BG deltas
    expectedDeltaBGs = []

    # Compute expected BG deltas
    for i in range(len(T) - 1):

        # Copy net insulin profile
        net_ = copy.deepcopy(Net)

        # Cut it for current IOB computation
        start = T[i] - datetime.timedelta(hours=IDC.DIA)
        end = T[i]
        net_.cut(start, end)
        net_.normalize()

        # Compute corresponding IOB
        IOB0 = calculator.computeIOB(net_, IDC)

        # Move net insulin profile into the past by the time that passes until
        # next BG value
        dt = t[i + 1] - t[i]
        net_.shift(-dt)

        # Compute new IOB, and the difference with the last one
        IOB1 = calculator.computeIOB(net_, IDC)
        dIOB = IOB1 - IOB0

        # Get current ISF and compute dBG using dIOB
        # NOTE: there might be some error slipping in here if ISF changes
        # between the two IOBs
        ISF = ISFs.f(t[i])
        dBG = dIOB * ISF

        # Store and show expected BG delta
        expectedDeltaBGs += [dBG]
        print "dBG(" + lib.formatTime(start) + ") = " + fmt.BG(dBG)

    return expectedDeltaBGs
Пример #25
0
def test_get_recent(setup_and_teardown):
    """
    Get entries in recent reports.
    """

    now = datetime.datetime.now()

    datetimes = [
        datetime.datetime(1975, 1, 1, 0, 0, 0),
        datetime.datetime(1980, 2, 2, 0, 0, 0),
        datetime.datetime(1985, 3, 3, 0, 0, 0)
    ]

    values = [6.2, 6.0, 5.8]

    entries = dict(zip(datetimes, values))

    branch = ["A", "B"]

    # Create reports
    reporter.setDatedEntries(DatedReport, branch, entries, path.TESTS)

    # Look for values in last 3 days (strict search)
    emptyResults = reporter.getRecentDatedEntries(DatedReport,
                                                  now,
                                                  branch,
                                                  3,
                                                  src=path.TESTS,
                                                  strict=True)

    # Results should be empty
    assert len(emptyResults) == 0

    # Look for values in 3 most recent available reports
    results = reporter.getRecentDatedEntries(DatedReport,
                                             now,
                                             branch,
                                             3,
                                             src=path.TESTS,
                                             strict=False)

    # There should be as many entries in merged results, as there were reports
    # instanciated. The values should also fit.
    assert (len(results) == len(datetimes) and all(
        [results[lib.formatTime(d)] == entries[d] for d in datetimes]))
Пример #26
0
    def storeBestFrequency(self, f):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            STOREBESTFREQUENCY
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Store best frequency to communicate with pump.
        """

        # Info
        Logger.debug("Adding pump's best RF to: " + repr(self.report))

        # Get current formatted time
        now = lib.formatTime(datetime.datetime.now())

        # Add entry to report and store it
        self.report.set([f, now], ["Frequency"], True)
        self.report.store()
Пример #27
0
    def show(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            SHOW
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Count number of entries found
        n = len(self.t) or len(self.values)

        # Get name of record
        record = self.__class__.__name__

        # Give user info
        Logger.info("Found " + str(n) + " '" + record + "':")

        # Inject None for missing record times and/or values
        for i in range(n):

            # Get current time
            try:

                # Store it
                t = self.t[i]

            except:

                # Store it
                t = None

            # Get current value
            try:

                # Store it
                value = self.values[i]

            except:

                # Store it
                value = None

            # Print current record
            Logger.info(str(value) + " (" + lib.formatTime(t) + ")")
Пример #28
0
    def snooze(self, TB):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            SNOOZE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        Snooze enactment of high TBs for a while after eating.
        """

        # Get last carbs
        lastCarbs = Reporter.getRecent(self.now, "treatments.json", ["Carbs"],
                                       1)

        # Destructure TB
        [rate, units, duration] = TB

        # Define snooze duration (h)
        snooze = 0.5 * self.DIA

        # Snooze criteria (no high temping after eating)
        if lastCarbs:

            # Get last meal time and format it to datetime object
            lastTime = lib.formatTime(max(lastCarbs))

            # Compute elapsed time since (h)
            d = (self.now - lastTime).total_seconds() / 3600.0

            # If snooze necessary
            if d < snooze:

                # Compute remaining time (m)
                T = int(round((snooze - d) * 60))

                # Give user info
                Logger.warning("Bolus snooze (" + str(snooze) + " h). If no " +
                               "more bolus issued, looping will restart in " +
                               str(T) + " m.")

                # Snooze
                return True

        # Do not snooze
        return False
Пример #29
0
    def decode(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECODE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Initialize decoding
        super(self.__class__, self).decode()

        # Decode sensor status
        status = self.statuses[self.bytes[-1][12]]

        # Store it
        self.values.append(status)

        # Give user info
        Logger.info("Sensor status: " + str(status) + " " + "(" +
                    lib.formatTime(self.t[-1]) + ")")
Пример #30
0
    def show(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            SHOW
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Count number of entries found
        n = len(self.t) or len(self.values)

        # Get name of record
        record = self.__class__.__name__

        # Info
        Logger.info("Found " + str(n) + " '" + record + "':")

        # Inject None for missing record times and/or values
        for i in range(n):

            # Get current time
            try:

                # Store it
                t = self.t[i]

            except:

                # Store it
                t = None

            # Get current value
            try:

                # Store it
                value = self.values[i]

            except:

                # Store it
                value = None

            # Print current record
            Logger.info(str(value) + " (" + lib.formatTime(t) + ")")
Пример #31
0
    def decode(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECODE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Initialize decoding
        super(self.__class__, self).decode()

        # Decode BG
        BG = round(lib.unpack(self.bytes[-1][8:10], "<") / 18.0, 1)

        # Store it
        self.values.append(BG)

        # Give user info
        Logger.info("BG: " + str(BG) + " " + self.cgm.units.value + " " + "(" +
                    lib.formatTime(self.t[-1]) + ")")
Пример #32
0
def snooze(now, duration = 2):

    """
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        SNOOZE
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Snooze enactment of TBs for a while after eating.
        TODO: take carb dynamics into consideration!
    """

    # Compute dates
    today = now.date()
    yesterday = today - datetime.timedelta(days = 1)

    # Get last carbs (no need to go further than the past 2 days)
    lastCarbs = reporter.getDatedEntries(reporter.TreatmentsReport,
        [yesterday, today], ["Carbs"])

    # Snooze criteria (no temping after eating)
    if lastCarbs:

        # Get last meal time
        lastTime = lib.formatTime(max(lastCarbs))

        # Compute elapsed time since last meal
        dt = (now - lastTime).total_seconds() / 3600.0

        # If snooze necessary
        if dt < duration:

            # Compute remaining time (m)
            t = int(round((duration - dt) * 60))

            # Info
            Logger.warning("Bolus snooze (" + str(duration) + " h). If no " +
                           "more bolus issued, high temping will resume in " +
                           str(t) + " m.")

            # Snooze
            return True

    # Do not snooze
    return False
Пример #33
0
    def decouple(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECOUPLE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Decouple profile data into components.
        """

        # Give user info
        Logger.debug("Decoupling components...")

        # Decouple components
        for t in sorted(self.data):

            # Get time and convert it to datetime object if possible
            self.T.append(lib.formatTime(t))

            # Get value
            self.y.append(self.data[t])
Пример #34
0
    def decode(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECODE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Initialize decoding
        super(self.__class__, self).decode()

        # Decode BG
        BG = round(lib.unpack(self.bytes[-1][8:10], "<") / 18.0, 1)

        # Store it
        self.values.append(BG)

        # Give user info
        Logger.info("BG: " + str(BG) + " " + self.cgm.units.value + " " +
                    "(" + lib.formatTime(self.t[-1]) + ")")
Пример #35
0
    def decode(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECODE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Initialize decoding
        super(self.__class__, self).decode()

        # Decode sensor status
        status = self.statuses[self.bytes[-1][12]]

        # Store it
        self.values.append(status)

        # Give user info
        Logger.info("Sensor status: " + str(status) + " " +
                    "(" + lib.formatTime(self.t[-1]) + ")")
Пример #36
0
def test_decouple():
    """
    Create a profile, give it data and decouple it into time and value axes.
    """

    # Create an unsorted profile
    profile = [(getTime("00:30:00", "1970.01.02"), 5.8),
               (getTime("23:30:00", "1970.01.01"), 6.2),
               (getTime("00:00:00", "1970.01.02"), 6),
               (getTime("01:00:00", "1970.01.02"), 5.6)]

    # Create profile
    p = Profile()
    p.data = dict([(lib.formatTime(d), y) for (d, y) in profile])

    # Decouple its data
    p.decouple()

    # Check profile axes (they should be time ordered)
    assert [p.T, p.y] == lib.unzip(sorted(profile))
Пример #37
0
    def decode(self):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECODE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Initialize decoding
        super(self.__class__, self).decode()

        # Decode BG
        BG = lib.unpack(self.bytes[-1][8:10], "<") & 1023

        # Decode trend
        trend = self.trends[self.bytes[-1][10] & 15]

        # Deal with special values
        if BG in self.special:

            # Decode special BG
            BG = self.special[BG]

            # Give user info
            Logger.info("Special value: " + BG)

        # Deal with normal values
        else:

            # Convert BG units if desired
            if self.convert:

                # Convert them
                BG = round(BG / 18.0, 1)

            # Give user info
            Logger.info("BG: " + str(BG) + " " + str(trend) + " " +
                        "(" + lib.formatTime(self.t[-1]) + ")")

        # Store them
        self.values.append({"BG": BG, "Trend": trend})
Пример #38
0
    def decode(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            DECODE
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Initialize decoding
        super(self.__class__, self).decode()

        # Decode BG
        BG = lib.unpack(self.bytes[-1][8:10], "<") & 1023

        # Decode trend
        trend = self.trends[self.bytes[-1][10] & 15]

        # Deal with special values
        if BG in self.special:

            # Decode special BG
            BG = self.special[BG]

            # Give user info
            Logger.info("Special value: " + BG)

        # Deal with normal values
        else:

            # Convert BG units if desired
            if self.convert:

                # Convert them
                BG = round(BG / 18.0, 1)

            # Give user info
            Logger.info("BG: " + str(BG) + " " + str(trend) + " " + "(" +
                        lib.formatTime(self.t[-1]) + ")")

        # Store them
        self.values.append({"BG": BG, "Trend": trend})
Пример #39
0
    def show(self):
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            SHOW
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Print various versions of profile.
        """

        # Define axes dictionary
        versions = {
            "Standard t-axis": zip(self.T, self.y),
            "Normalized t-axis": zip(self.t, self.y),
            "Derivative": zip(self.t[:-1], self.dydt)
        }

        # Loop on each profile component
        for version, entries in versions.items():

            # If not empty
            if entries:
                Logger.info(repr(self) + " - " + version)

                # Show entries
                for entry in entries:

                    # Get time and value
                    t = entry[0]
                    y = entry[1]

                    # Format time if necessary
                    if type(t) is not float:
                        t = lib.formatTime(t)

                    # Format value if necessary
                    if type(y) is float or type(y) is np.float64:
                        y = round(y, 2)

                    # Info
                    Logger.info(str(y) + " (" + str(t) + ")")
Пример #40
0
def snooze(now, duration = 2):

    """
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        SNOOZE
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Snooze enactment of TBs for a while after eating.
        FIXME: take carbs dynamics into consideration!
    """

    # Get last carbs
    lastCarbs = Reporter.getRecent(now, "treatments.json", ["Carbs"], 1)

    # Snooze criteria (no temping after eating)
    if lastCarbs:

        # Get last meal time
        lastTime = lib.formatTime(max(lastCarbs))

        # Compute elapsed time since last meal
        dt = (now - lastTime).total_seconds() / 3600.0

        # If snooze necessary
        if dt < duration:

            # Compute remaining time (m)
            t = int(round((duration - dt) * 60))

            # Give user info
            Logger.warning("Bolus snooze (" + str(duration) + " h). If no " +
                           "more bolus issued, high temping will resume in " +
                           str(t) + " m.")

            # Snooze
            return True

    # Do not snooze
    return False
Пример #41
0
    def f(self, t):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            F
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Compute profile's value (y) for a given time (t).
        """

        # Initialize index
        index = None

        # Datetime axis
        if type(t) is datetime.datetime:

            # Define axis
            axis = self.T

        # Normalized axis
        else:

            # Define axis
            axis = self.t

        # Get number of steps in profile
        n = len(axis) - 1

        # Make sure axes fit
        if n != len(self.y) - 1:

            # Exit
            raise errors.ProfileAxesLengthMismatch()

        # Compute profile value
        for i in range(n):

            # Index identification criteria
            if axis[i] <= t < axis[i + 1]:

                # Store index
                index = i

                # Exit
                break

        # Index identification criteria (end time)
        if t == axis[-1]:

            # Store index
            index = -1

        # Check if result could be found
        if index is None:

            # Error
            raise errors.BadFunctionCall(lib.formatTime(t))

        # Compute corresponding value
        y = self.y[index]

        # Return result
        return y
Пример #42
0
    def autosens(self, now, t = 24):

        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            AUTOSENS
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """

        # Define past reference time
        past = now - datetime.timedelta(hours = t)

        # Define DIA as a datetime timedelta object
        dia = datetime.timedelta(hours = self.DIA)

        # Instanciate profiles
        profiles = {"IDC": IDC.WalshIDC(self.DIA),
                    "Suspend": None,
                    "Resume": None,
                    "Basal": None,
                    "TB": None,
                    "Bolus": None,
                    "Net": None,
                    "ISF": ISF.ISF(),
                    "PastBG": BG.PastBG()}

        # Build past BG profile
        profiles["PastBG"].build(past, now)
        
        # Build past ISF profile
        profiles["ISF"].build(past, now)

        # Reference to BG time axis
        T = profiles["PastBG"].T

        # Initialize IOB arrays
        IOBs = []

        # Get number of BGs
        n = len(T)

        # Compute IOB for each BG
        for i in range(n):

            # Reset necessary profiles
            profiles["Suspend"] = suspend.Suspend()
            profiles["Resume"] = resume.Resume()
            profiles["Basal"] = basal.Basal()
            profiles["TB"] = TB.TB()
            profiles["Bolus"] = bolus.Bolus()
            profiles["Net"] = net.Net()

            # Build net insulin profile
            profiles["Net"].build(T[i] - dia, T[i], profiles["Suspend"],
                                                    profiles["Resume"],
                                                    profiles["Basal"], 
                                                    profiles["TB"],
                                                    profiles["Bolus"])

            # Do it
            IOBs.append(calc.computeIOB(profiles["Net"], profiles["IDC"]))

            # Show IOB
            print "IOB(" + lib.formatTime(T[i]) + ") = " + fmt.IOB(IOBs[-1])