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
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])
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)
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)
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)
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
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")
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()
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)
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()
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
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()
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], [])
def read(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Read last time pump's radio transmitter was powered up self.value = lib.formatTime(Reporter.get("pump.json", [], "Power"))
def __str__(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ return ("Sensor status: " + str(self.status) + " (" + lib.formatTime(self.displayTime) + ")")
def __str__(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ return ("BG calibration value: " + str(self.value) + " mmol/L (" + lib.formatTime(self.enteredTime) + ")")
def __str__(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ return ("Event: " + str(self.type) + ", " + str(self.subType) + ": " + str(self.value) + " (" + lib.formatTime(self.enteredTime) + ")")
def read(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Read last time pump's radio transmitter was powered up self.value = lib.formatTime(Reporter.get("pump.json", [], "Power"))
def read(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Read last time pump's radio transmitter was powered up self.value = lib.formatTime(self.report.get(["Power"]))
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) + ")")
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) + ")")
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) + ")")
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())])
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
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]))
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()
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) + ")")
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
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]) + ")")
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) + ")")
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]) + ")")
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
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])
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]) + ")")
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]) + ")")
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))
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})
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})
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) + ")")
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
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
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])