Safety System Library API

Authors: Pau Herrero (Imperial College London) and Dan Brown (Oxford Brookes University)

Contents

1 Introduction

The purpose of this document is to describe the setup procedure for the PEPPER Safety System API and details on the implementation.

1.1 The PEPPER Safety System

Delivering insulin in type 1 diabetes is a challenging, and potentially risky, activity; hence the importance of including safety measures as part of any insulin dosing or recommender system. This documents presents an application program interface (API) implemented in Java for Android of a modular safety system which is part of an intelligent insulin dose recommender platform developed within the EU-funded PEPPER project.

The PEPPER Safety System comprises four modules: the first module consists of predictive glucose threshold crossing alerts and standard glucose threshold crossing alarms (Module 1). The second module is designed for insulin pump users and automatically suspends basal insulin delivery when predicted glucose levels are low (Module 2). A third module recommends an individualized carbohydrate to harmlessly return glucose to safe levels (Module 3). Finally, the fourth module, referred to as dynamic bolus insulin constraint, restricts the amount of insulin that can be safely recommended to the user (Module 4). Figure 1.1 shows a block diagram of the safety system and its corresponding inputs and outputs. Further details of these four modules are given in the following sections. Finally, in addition the functionalities provided by the aforementioned modules, the Safety System also provides information about the glucose rate of change, insulin-on-board, and carbohydrates-on-board.

Image block_diagram
Figure 1.1: Block diagram of the safety system with the four modules, and corresponding inputs and outputs

1.1.1 Module 1: Predictive Glucose Alerts and Alarms Module

The glucose alerts and alarms module consists of two predictive alerts using a glucose forecasting algorithm [1] to notify the user before reaching predefined high and low glucose thresholds. In addition, standard glucose alarms notify the user when thresholds measured by the continuous glucose monitor (CGM) are exceeded. Finally, if the user does not address a hypoglycaemia alarm before a predefined time interval, an SMS message containing the type of alarm (i.e. hypoglycemia or hyperglycemia) and the time it was triggered, is sent to a designated carer. The system keeps sending messages until the alarm is manually snoozed on the handheld unit. Details about the algorithms behind the predictive glucose alerts and alarms can be found in [2].

1.1.2 Module 2: Predictive Low-glucose Basal Insulin Suspend Module

The predictive low glucose basal insulin suspension module aims at minimising the incidence and severity of hypoglycemia by suspending, or partially suspending, basal insulin delivery when predicted glucose levels are low. Basal insulin delivery is partially suspended if the forecasted glucose value falls below a predefined threshold (Threshold 1). Insulin delivery is fully suspended when glucose falls below a second predefined threshold (Threshold 2). Details about the algorithms behind the predictive low-glucose basal insulin suspend module can be found in [2].

1.1.3 Module 3: Adaptive Carbohydrate Recommender

If neither glucose alerts/alarms module nor the predictive low glucose basal insulin suspension module are enough to prevent hypoglycemia, the adaptive carbohydrate recommender module recommends a rescue dose of oral carbohydrates with the aim of reverting hypoglycaemia and minimizing rebound hyperglycemia. Details about the algorithms behind the carbohydrate recommender can be found in [2].

1.1.4 Module 4: Dynamic Bolus Insulin Constraint

The Dynamic Bolus Insulin Constraint module aims to eliminate potentially dangerous insulin boluses being recommended to the user, which could induce severe hypo- or hyperglycaemia. This is done by computing a lower and upper bound determining the minimum and maximum allowed insulin recommendation. Details about the algorithms behind the dynamic insulin constraint module can be found in [2].

2 PEPPER Safety System Library Setup

This chapter details the setup of the PEPPER Safety System library.

2.1 Importing the PEPPERSafetySystem.jar

Setup of the library involves only importing the PEPPERSafetySystem.jar into the Android project. In this section we provide two options: First, manually edit the application's module build.gradle; Second, using the Android Studio interface to import a JAR as a dependency.

2.1.1 Option 1: build.gradle

  1. Place the PEPPERSafetySystem.jar in the libs folder of the project, or a direction of your preference.
  2. You now have two options:
    • Option 1: Ensure that the directory and its JARs are compiled by checking/adding the following dependency in the application module’s build.gradle (example for the libs directory):
      
      compile fileTree(include: [’*.jar’], dir: ’libs’)
      
      

      For example:

      
      dependencies { compile fileTree(include: [’*.jar’], dir: ’libs’)
      // other dependencies omitted
      }
      
      
    • Option 2: Add an explicit dependency for the PEPPERSafetySystem.jar to the application module’s build.gradle (example for the libs directory):
      
      compile files(’libs/PEPPERSafetySystem.jar’)
      
      

      For example:

      
      dependencies { compile files(’libs/PEPPERSafetySystem.jar’)
      // other dependencies omitted
      }
      
      
  3. After the build.gradle has been sync’d, the library should not be imported.

2.1.2 Option 2: Android Studio Graphical User Interface

  1. Place the PEPPERSafetySystem.jar in the libs folder of the project.
  2. Navigate to File > Project Structure
  3. Select your module from the Modules list in the left side pane of the Project Structure interface.
  4. Navigate to the Dependency tab.
  5. Click the add icon (+ symbol) and select File dependency.
  6. Navigate to the PEPPERSafetySystem.jar and click OK.
  7. Click OK to close the Project Structure window.
  8. The library should now be imported.

3 Using the PEPPER Safety System Library

This chapter details the important details on how to use the PEPPER Safety System library.

  1. Initialisation of the Safety System (Section 3.1)
  2. CGM update (Section 3.2)
  3. Insulin recommendation handling (Section 3.3)
  4. Pump Interaction (Section 3.2.2)
  5. Manual carbohydrates entry (Section 3.4)
  6. Manual insulin entry (Section 3.5)
  7. Safety JSON export (Section 3.7)
  8. Display of Safety System values to the graphical user interface (Section 3.6):
    1. Carbohydrates on board (Section 3.6.1)
    2. Insulin on board (Section 3.6.2)
    3. Blood glucose trend (Section 3.6.3)

3.1 Initialisation of the Safety System

Initialisation of the Safety System requires the creation (Section 3.1.1) of the SafetySystemObject object and invoking the initialisation method, as described in Section 3.1.3.

Section 3.1.4 presents a creation and initialisation template for developers to refer to.

3.1.1 Creating and accessing the SafetySystem object

Creation of the SafetySystem object must be done using the static factory method:


SafetySystem safetySystem = SafetySystemFactory.getInstance(context);

The safety system adopts the singleton pattern to provide a global state accessible from the application without the need to maintain a reference. This design decision can be justified through the fact that there should only ever be one instance of the safety system operating at any one time.

Accessing and creating the SafetySystem object:


SafetySystem safetySystem = SafetySystemFactory.getInstance(context);

3.1.2 Setting the SafetySystem's System Time Invoker

As some operations internal the Safety System require accessing the current system time, it is important that the SafetySystemTimeManager's SystemTimeInvoker is set to mirror that it is used by the rest of the application.

The SafetySystemTimeManager only needs to be invoked once prior to initialisation of the SafetySystem object. This will persist throughout the life of the application.

SystemTimeInvoker is a single method interface which defines the following method:


Date getSystemTime()

By default the SystemTimeInvoker returns new Date().

To change this behaviour, a different SystemTimeInvoker can be created and set in the Safety System's SafetySystemTimeManager object.

For example:


/*
 * Implement the SystemTimeInvoker interface.
 */
SystemTimeInvoker customTimeInvoker = new SystemTimeInvoker() {
    @Override
    public Date getSystemTime() {
        return new Date(Custom.getCustomSystemTime()); // change me as required
    }
}

/*
 * Set the SafetySystemTimeManager's SystemTimeInvoker to the custom implementation.
 */
SafetySystemTimeManager.getInstance().setSystemTimeInvoker(customTimeInvoker);

3.1.3 Initialising the SafetySystem object

It is important that prior to performing any operations on the Safety System that it has been initialised by passing it the patient object JSON. If this is not the case, the SafetySystem object will throw an IllegalSafetyStateException for almost all operations.

This initialisation process only needs to occur once, ideally when the application is launched.

Note:

As a fail-safe mechanism, the Safety System will store the last patient object JSON in an internal database. Should any interaction with the Safety System occur prior to the initialisation as documented in this section, the Safety System will automatically initialise itself using the most recent patient object stored in this database. This feature was included to allow the system to recover after a crash or system reboot without Internet connectivity.

As a result, if the safety system has been initialised at some point, then an IllegalSafetySystemStateException should never be raised.

Initialisation of the Safety System occurs by invoking the following method:


void SafetySystem.initSafetySystem(JSONObject patientObj)

This method requires a well-formed patient object JSON. Explicitly of the type JSONObject. If a String of the JSON is only available, then the constructor of JSONObject allows a JSON String to be passed for this purpose. If the JSONObject is not well-formed a JSONException will occur, this is a checked Exception which must be handled. Additionally, if there is an issue reading the IcrSafety, TimeIcrSafety, IsfSafety or TimeIsfSafety fields a IllegalArgumentException will be thrown, this is unchecked.

Explicitly, the following attributes are expected in the patient object JSON:

Note: the term 'parsable' is used below, meaning that the contained value must be parsable as the expressed type even if the value itself is a String. For example, 'parsable double' means that the String value "2.0" is a valid value.

If the Safety System object has been initialised successfully the following method should return true:


boolean SafetySystem.isInitialised()

3.1.4 SafetySystem Creation and Initialisation Template/Example

This section presents a complete template for creating and initialisation of the SafetySystem object.


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.eu.pepper.safetysystem.*;

public class ExampleActivity extends AppCompatActivity {

    /**
     * Class member field to store the safety system object.
     */
    private SafetySystem mSafetySystem;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        /*
         * Create/access the safety system object using the static factory method in the
         * SafetySystemFactory class.
         *
         * Important: This does not initialise the safety system.
         *
         * The safety system operates as a singleton, so once created only one instance will
         * ever exist and is accessible at any time using the static factory method:
         * SafetySystemFactory.getInstance(Context)
         */
        mSafetySystem = SafetySystemFactory.getInstance(getApplicationContext());
        
        /*
         * By default, the safety system gets the current system time by creating a
         * new instance of Java Date. This can be changed by changing the SystemTimeInvoker
         * used by the Safety System.
         *
         * Note: This will persist throughout the life of the application.
         *
         * Important: This should be done prior to initialisation of the Safety System.
         */
         SystemTimeInvoker timeInvoker = new SystemTimeInvoker() {
             @Override
             public Date getSystemTime() {
                 return new Date(Custom.getSystemTime()); // change me
             }
         };
         SafetySystemTimeManager.getInstance().setSystemTimeInvoker(timeInvoker);
    
        /*
         * The safety system will not be initialised until the initSafetySystem method is invoked.
         * Nearly all operations on the Safety System will throw an IllegalSafetySystemStateException
         * if this initialisation is not completed or successful.
         *
         * To initialise the safety system, the Patient JSONObject must be passed to the
         * initSafetySystem(JSONObject) method.
         */
         JSONObject patientObj = Patient.getPatientObj(); // change me
         try {
             mSafetySystem.initSafetySystem(patientObj);
         } catch (JSONException e) {
             // The JSONObject is not well formed, likely a missing or misspelt field.
         }
        /*
         * The safety system is now initialised and ready for use.
         */
    }
}

3.2 Using the Glucose Alerts/Alarms, Low-glucose Suspend, and Carbohydrate Recommender Modules

This section documents how to interface with the PEPPER Safety System modules 1, 2, and 3.

Note: This process should be undertaken whenever a blood glucose reading is obtained from the CGM.

The following steps and checks should be performed on the SafetySystem object to successfully integrate these features:

  1. Obtain blood glucose reading from the CGM
  2. Invoke the method void SafetySystem.update(Date, double), where the Date object is the system time of the operation and the double value is the blood glucose reading from the CGM in mg/dL
  3. Perform the following checks and relevant actions:
    1. MODULE 1: Check for a predictive predictive Glucose Alert using the method:
      
      SafetySystem.hasGlucoseAlert()
      
      

      If there is a predictive Glucose Alert, notify the user.

      The Glucose Alert can be retrieved using the method:

      
      SafetyGlucoseAlert SafetySystem.getGlucoseAlert()
      
      

      Refer to Section 3.2.1 for more information.

    2. Check for a Glucose Alarm using the method:
      
      SafetySystem.hasGlucoseAlarm()
      
      

      If there is a Glucose Alarm, notify the user.

      The GlucoseAlarm can be retrieved using the method:

      
      SafetyGlucoseAlarm SafetySystem.getGlucoseAlarm()
      
      

      Refer to Section 3.2.1 for more information.

    3. Check for a Carer Alarm using the method:
      
      SafetySystem.hasCarerAlarm()
      
      

      If there is a Carer Alarm, send the alarm to the web service.

      The CarerAlarm can be retrieved using the method:

      
      SafetyCarerAlarm SafetySystem.getCarerAlarm()
      
      
    4. MODULE 2: Check the pump suspension state using the method (pump only):
      
      SafetyLowGlucoseSuspend SafetySystem.getLowGlucoseSuspend()
      
      
      1. If the result == SafetyLowGlucoseSuspend.TOTAL_SUSPENSION then suspend the pump.
      2. If the result == SafetyLowGlucoseSuspend.PARTIAL_SUSPENSION then partially suspend the pump.
      3. If the result == SafetyLowGlucoseSuspend.NO_SUSPENSION then restore / keep the pump in full operation.
    5. MODULE 3: Check for a Carbohydrate Recommendation using the method:
      
      SafetySystem.hasCarbRecommendation()
      
      

      If there is a Carbohydrate Recommendation, notify the user.

      The Carbohydrate Recommendation can be retrieved using the methods:

      String SafetySystem.getCarbRecommendationAsString() - formatted String
      double SafetySystem.getCarbRecommendation() - raw double

      Refer to Section 3.2.3 for more information.

3.2.1 User Interaction with Glucose Alerts and Alarms (Module 1)

When any of the following alarms or alerts occur the user should be represented with a notification describing the alert or alarm (all expressed as enumerate types):

Note: CarerAlarm is not listed, as this has no user interaction, instead the CarerAlarm is reported to the web service.

For all SafetyGlucoseAlert and SafetyGlucoseAlert the user should be presented with a notification dialog with a single option to snooze the alert and alarm.

All of the above are snoozed by invoking the same method:


void snoozeAlarm(Date date)

where the Date is the system date and time at the point the alarm or alert was snoozed.

The Safety System has an internal clock, which if a glucose alarm is not snoozed is not resolved within a certain time interval (currently 30 minutes) will trigger a CarerAlarm. Snoozing the alarm or alert will reset the internal timer.

3.2.2 User Interaction with Predictive Low-glucose Suspension (Module 2)

This section documents the interactions with the Safety System with regards to insulin pump suspension system.

3.2.2.1 Overriding Pump Suspension

The safety system supports the ability to override pump suspension, i.e. if the pump is currently suspended in some way (total or partial) the safety system can be told to not suspend for 60 minutes.

To override pump suspension the following method should be invoked on the SafetySystem object:


SafetySystem.resumePumpOverride()

3.2.2.2 Stopping a Pump Bolus

There may be occasions when the user chooses to stop the insulin pump. In this event the safety system needs to be informed that such an event has occurred otherwise the internal models (notably insulin on board) will not reflect the current situation correctly.

To notify the safety system that a pump bolus has been stopped early the following method should be invoked: SafetySystem.recalculateInsulin(double insulinAdministered) where insulinAdministered is the actual insulin administered by the pump prior to stopped.

3.2.3 User Interaction with Carbohydrate Recommender (Module 3)

Should the Safety System trigger a Carbohydrate Recommendation, the user should be presented with the recommendation as a notification.

The carbohydrate recommendation can be retrieved using the following methods:

String SafetySystem.getCarbRecommendationAsString() - returns a formatted String
double SafetySystem.getCarbRecommendation() - returns a double value.

The notification dialog should offer the user two options:

3.2.4 Example of Interfacing with modules 1, 2, and 3


void cgmUpdate(Date cgmReadingDateTime, double cgmReadingBgValue) {
    /*
     * Get the safety object. This must have been initialised.
     */
    SafetySystem safetySystem = SafetySystemFactory.getInstance(getApplicationContext());
    
    /*
     * Update the Safety System with the CGM reading.
     */
    safetySystem.update(cgmReadingDateTime, cgmReadingBgValue);
    
    /*
     * Check for alerts / alarms / etc.
     */
     
    /*
     * Check if a glucose alert has been flagged by the safety system.
     */
    if (safetySystem.hasGlucoseAlert()) {
        SafetyGlucoseAlert glucoseAlert = safetySystem.getGlucoseAlert();
        /*
         * Display notification to the user.
         */
    }
    
    /*
     * Check if a glucose alarm has been flagged by the safety system.
     */
    if (safetySystem.hasGlucoseAlarm()) {
        SafetyGlucoseAlarm glucoseAlarm = safetySystem.getGlucoseAlarm();
        /*
         * Display notification to the user.
         */
    }
    
    /*
     * Check if a carer alarm has been flagged by the safety system.
     */
    if (safetySystem.hasCarerAlarm()) {
        SafetyCarerAlarm carerAlarm = safetySystem.getCarerAlarm();
        /*
         * Send the carerAlarm to the web service.
         */
    }
    
    /*
     * Get pump suspension state.
     * Note: Pump Only
     */
    SafetyLowGlucoseSuspend pumpSuspendState = safetySystem.getLowGlucoseSuspend();
    
    /*
     * Handle the pump suspension state.
     */
    switch (pumpSuspendState) {
        case TOTAL_SUSPENSION:
            /*
             * Stop the pump.
             * call SafetySystem.resumePumpOverride() to resume pump
             */
            break;
        case PARTIAL_SUSPENSION:
            /*
             * Partially suspend the pump.
             */
             break;
        case NO_SUSPENSION:
            /*
             * Do nothing / resume the pump if it was previously suspended.
             */
    }
    
    /*
     * Check if a carbohydrate recommendation has been flagged by the safety system.
     */
    if (safetySystem.hasCarbRecommendation()) {
        String carbRecommendaton = safetySystem.getCarbRecommendationAsString();
        /*
         * Display the carbohydate recommendation to user with the option to accept/decline.
         */
    }
    
}

3.3 Dynamic Insulin Constraint Module

This section documents the workflow of the Safety System in conjunction with an insulin recommender system.

The Safety System requires two operations to be perform when a insulin recommendation is obtained:

  1. Constrain the recommended insulin bolus
  2. Commit the insulin recommendation to the Safety System (if accepted/rejected)

The full procedure is as follows:

  1. The user requests a bolus recommendation via the graphical user interface
  2. The user inputs are used to create the PEPPER case object (JSON)
  3. The insulin recommender produces a bolus recommendation which is stored in the PEPPER case object (JSON)
  4. The PEPPER case object (JSON) is passed to the double SafetySystem.constrainBolus(JSONObject) method. This method manipulates the PEPPER case object JSON to store the constrained bolus (attribute: bolussafety), and also returns the constrained bolus recommendation.
  5. The user then accepts/rejects/cancels the recommendation:

    If the user accepts the recommendation:

    1. The PEPPER case object (JSON) is updated so that the attribute bolususer is populated with the same value as bolussafety.
    2. the PEPPER case object (JSON) is passed to the method:
      
      void SafetySystem.addRecommendation(JSONObject)
      
      
      This will update the state of the safety system.
    3. End of Safety System ←→ Insulin Recommender interaction.

    If the user rejects the recommendation:

    1. The user inputs the actual bolus administered.
    2. The PEPPER object case (JSON) is updated so that the attribute bolususer is populated with the user's actual bolus input.
    3. the PEPPER case object (JSON) is passed to the method:
      
      void SafetySystem.addRecommendation(JSONObject)
      
      
      This will update the state of the safety system.
    4. End of Safety System ←→ Insulin Recommender interaction.

    If the user cancels the recommendation:

    1. End of Safety System ←→ Insulin Recommender interaction.

3.3.1 Constrain the insulin bolus recommendation

For item one, constrain the recommend bolus dose, the system must pass the populated PEPPER case object (JSON) to the safety system after a recommendation has been produced.

Note: This must occur before the dose is displayed to the user.

To constrain an insulin bolus recommendation the following method should be invoked on the SafetySystem object:


double SafetySystem.constrainBolus(JSONObject caseJson)

Invoking this method will internally update the PEPPER case object (JSON), setting the attribute bolussafety to the constrained bolus dose. This value is limited to 4 decimal point precision.

The contrainBolus method is reliant upon the following attributes being present and correct in the PEPPER case (JSON object):

3.3.2 Commit the insulin recommendation to the Safety System

If a insulin recommendation is accepted or rejected by the user, the PEPPER case object (JSON) should be committed to the Safety System to ensure its state is updated.

Prior to committing the PEPPER case object (JSON) to the Safety System, the PEPPER case object (JSON) must be updated as follows:

If the insulin recommendation is accepted:

Update the PEPPER case object (JSON) so that the attribute bolususer is set to the same value as bolussafety.

For example:


void updateBolusUserWithBolusSafety(JSONObject pepperCase){
    JSONObject attributesJSON = pepperCase.getJSONObject("attributes");
    String bolusSafety = attributesJSON.getString("bolussafety");
    attributesJSON.put("bolususer", bolusSafety);
}

If the insulin recommendation is rejected:

Update the PEPPER case object (JSON) so that the attribute bolususer is set to bolus dose administered, as input by the user from the graphical user interface.

For example:


void updateBolusUser(JSONObject pepperCase, String userBolusInput){
    JSONObject attributesJSON = pepperCase.getJSONObject("attributes");
    attributesJSON.put("bolususer", userBolusInput);

If the insulin recommendation is cancelled:

Do nothing with the safety system.

Note:

For consistency with the rest of the system, it may be valid to add manual carbohydrates to the Safety System in case of cancellation. Refer to Section 3.4.

3.3.3 Example of Interfacing Dynamic Insulin Constraint module

After recommendation is obtained:


void constrainCbrRecommendation(JSONObject pepperCase) {
    /*
     * Get the safety object. This must have been initialised.
     */
    SafetySystem safetySystem = PEPPERSafetyFactory.getInstance(getApplicationContext());

    try {
        /*
         * Constrain the bolus recommendation:
         */
        double constrainedBolus = safetySystem.constrainBolus(pepperCase);
        
        /*
         * Display the constrained bolus recommendation to the user.
         */
    } catch (JSONException e) {
        /*
         * The PEPPER case JSON is malformed.
         */
    }
}

Handle user accept/reject/cancel response


/*
 * If the insulin recommendation is accepted.
 */
void acceptCbrRecommendation(JSONObject pepperCase) {
    /*
     * The user accepted the recommendation, so update "bolususer" to the "bolussafety" value.
     */
    String bolusSafety = pepperCase.getJSONObject("attributes").getString("bolussafety");
    updateBolusUser(pepperCase, caseAttributes.get("bolussafety")); // see below

    /*
     * Commit the recommendation to the Safety System to update its state.
     */
    SafetySystemFactory.getInstance(getApplicationContext()).addRecommendation(pepperCase);
}

/*
 * If the insulin recommendation is rejected.
 */
void rejectCbrRecommendation(JSONObject pepperCase, String userBolus) {
    /*
     * The user rejects the recommendation, so update "bolususer" to the users input.
     */
    String bolusSafety = pepperCase.getJSONObject("attributes").getString("bolussafety");
    updateBolusUser(pepperCase, caseAttributes.get("bolussafety")); // see below

    /*
     * Commit the recommendation to the safety system to update its state.
     */
    SafetySystemFactory.getInstance(getApplicationContext()).addRecommendation(pepperCase);
}

/*
 * If the insulin recommendation is cancelled.
 */
void cancelCbrRecommendation() {
    /*
     * Do nothing to the Safety System or add the carbohydrates manually
     * using SafetySystem.addCarbs(Date dateTime, double carbs)
     */
}

/*
 * Update the "bolususer" attribute of the PEPPER case (JSON object)
 */
void updateBolusUser(JSONObject pepperCase, String userBolus) {
    try {
        /*
         * Update the bolus user attribute in the PEPPER case (JSON object)
         */
        pepperCase.getJSONObject("attributes").put("bolususer", userBolus);
        
    } catch (JSONException e) {        
        /*
         * The PEPPER case JSON is malformed.
         */
    }
}

/*
 * Commit the insulin recommendation to the Safety System if it is accepted or rejected.
 */
void commitCbrRecommendationToSafetySystem(JSONObject pepperCase) {
    /*
     * Commit the insulin recommendation to the Safety System to update its state.
     */
    SafetySystemFactory.getInstance(getApplicationContext()).addRecommendation(pepperCase);
}

3.4 Manual Carbohydrates Input

This section documents the interactions with the Safety System that should occur when a manual carbohydrates input occurs.

The operation requires invocation of the method:


void SafetySystem.addCarbs(Date date, double carbs)

with the date and time of the manual carbohydrates input as a Java Date object and the carbohydrates input as a double value.

Manual carbohydrates template


void manualCarbs(Date carbInputDate, double carbs) {
    /*
     * Get the Safety System object. Note: this must be initialised.
     */
    SafetySystem safetySystem = SafetySystemFactory.getInstance(getApplicationContext());

    /*
     * Invoke the addCarbs(Date, double) method.
     */
    safetySystem.addCarbs(carbInputDate, carbs);
}

3.5 Manual Insulin Input

This section documents the interactions with the Safety System that should occur when a manual insulin input occurs.

The operation requires invocation of the method:


void SafetySystem.addInsulin(Date date, double insulin)

with the date and time of the manual insulin input as a Java Date object and the insulin input as a double value.

Manual insulin template


void manualInsulin(Date insulinInputDate, double insulin) {
    /*
     * Get the Safety System object. Note: this must be initialised.
     */
    SafetySystem safetySystem = SafetySystemFactory.getInstance(getApplicationContext());

    /*
     * Invoke the addInsulin(Date, double) method.
     */
    safetySystem.addInsulin(insulinInputDate, insulin);
}

3.6 Getting additional Safety System information

This section documents how to access information calculated by the Safety System which can be displayed to the user on the graphical user interface. This information is: Carbohydrates on Board, Insulin on Board, and the Blood Glucose Trend.

3.6.1 Carbohydrates on Board

The most recent carbohydrates on board calculation can be obtained from the Safety System by invoking the following methods:

To return the raw double carbohydrates on board value:


double SafetySystem.getCarbsOnBoard()

To return a formatted carbohydrates on board value as a String:


String SafetySystem.getCarbsOnBoardAsString()

Note:

The SafetySystem must be correctly initialised otherwise an IllegalSafetySystemStateException will be thrown by these methods.

3.6.2 Insulin on Board

The most recent insulin on board calculation can be obtained from the Safety System by invoking the following methods:

To return the raw double insulin on board value:


double SafetySystem.getInsulinOnBoard()

To return a formatted insulin on board value as a String:


String SafetySystem.getInsulinOnBoardAsString()

Note:

The SafetySystem must be correctly initialised otherwise an IllegalSafetySystemStateException will be thrown by these methods.

3.6.3 Glucose Trend

The most recent blood glucose trend (rate of change) calculation can be obtained from the Safety System by invoking the following method:


SafetyGlucoseTrend SafetySystem.getGlucoseTrend()

SafetyGlucoseTrend is an enumerate type which is used to indicate the glucose trend arrow to be presented to the graphical user interface. The enumerate type to graphical arrow representation is shown in Table 3.1.

Note:

The SafetySystem must be correctly initialised otherwise an IllegalSafetySystemStateException will be thrown by this method.

Table 3.1: SafetyGlucoseTrend enumerate constant ←→ graphical arrow representation
Enumerate constant Trend arrow
STEADY
SLOW_RISE
RISE
RAPID_RISE ↑↑
SLOW_FALL
FALL
RAPID_FALL ↓↓

3.7 Safety JSON Export (Safety Object)

The Safety System uses a SQLite database to locally store data in the event of a system crash. However, the Safety Object should be exported and sent to the web services (e.g. every 24 hours).

A JSONObject for exporting can be created by invoking the following method:


JSONObject SafetySystem.createJsonExport()

Note:

The SafetySystem must be correctly initialised otherwise an IllegalSafetySystemStateException will be thrown by these methods.

The JSON format for this object is given bellow:


{
        "PatientId":"", // Unique patient identifier
        "DateTime":"",  // Date and time the safety object was exported, format example: Thu Jun 22 08:53:04 GMT+00:00 2017


        "CGM":  // CGM and regularly updated information
        {
                "Time":"[]",    // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Measurement":"[]",     // comma separated list of CGM sample
                "Derivative":"[]",      //  comma separated list of glucose derivative (tred or rate of change) values
                "Forecasted":"[]",      //  comma separated list of forecasted glucose values
                "IOB":"[]",     // comma separated list of insulin on board values
                "COB":"[]"      // comma separated list of carbs on board values
        },

        "GlucoseAlerts": // Glucose alerts (MODULE 1)
        { 
                "Time":"[]",    // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Type":"[]",    // comma separated list of categorical values (None/Hypoglycaemia/Hyperglycaemia)
                "Snooze":""     // comma separated list of categorical values of true/false || VALUES CURRENTLY NOT RECORDED
        },

        "GlucoseAlarms": // Glucose alarms  (MODULE 1)
        { 
                "Time":"[]",    // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Type":"[]",    // comma separated list of categorical values None/Hypoglycaemia/Hyperglycaemia)
                "Snooze":""     // comma separated list of true / false || VALUES CURRENTLY NOT RECORDED
        },
    
  "AlarmCarers":        // Carer alarms  (MODULE 1)
        { 
                "Time":"[]",    // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Type":"[]"     // comma separated list of type categorical values (hypo,hyper,fault)
        }

        "SafetyLowGlucoseSuspend":      // Low glucose suspension  (MODULE 2)
        {
                "Time":"[]",    // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Suspension":"[]", // comma separated list of categorical values 0=non-suspended; 1=partial suspension; 2=total suspension
                "Cancel":""     // comma separated list of true / false || VALUES CURRENTLY NOT RECORDED
        },

        "CarbRecommender":      // Recommended CHO rescue doses  (MODULE 3)
        {
                "Time":"[]",    // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Dose":"[]",    // comma separated list of CHO recommendation dose values
                "Time_Accept":"[]",     // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Accept":"[]"   // comma separated list of true / false
        },

    "Constraint":       // Bolus constraints  (MODULE 4)
        {
                "Time":"[]",    // comma separated list of date values format example: Thu Jun 22 08:53:04 GMT+00:00 2017
                "Bolus":"[]"    // comma separated list of constrained bolus values
        },

4 Enumerate Types in the PEPPER Safety System Library

This section documents the enumerate types contained within the PEPPERSafetySystem library. The purpose of these enumerate types is to provide meaningful name to values representing as integers within the Safety System JSON object.

4.1 SafetyGlucoseAlert

Enumerate SafetyGlucoseAlarm used for safety system glucose alerts. A SafetyGlucoseAlert has a lower threshold than SafetyGlucoseAlarm.

Table 4.1: SafetyGlucoseAlert enumerate type
Enumerate constant JSON value Description
NO_ALERT 0 No alert
HYPO_ALERT 1 Hypo alert
HYPER_ALERT 2 Hyper alert

Related methods:

4.2 SafetyGlucoseAlarm

Enumerate SafetyGlucoseAlarm used for safety system glucose alarms. A SafetyGlucoseAlarm should take precedence over a SafetyGlucoseAlert (Sec. 4.1), however neither should occur simultaneously.

Table 4.2: SafetyGlucoseAlarm enumerate type
Enumerate constant JSON value Description
NO_ALARM 0 No alarm
HYPO_ALARM 1 Hypo alarm
HYPER_ALARM 2 Hyper alarm

Related methods:

4.3 SafetyCarerAlarm

Enumerate SafetyCarerAlarm used for Safety System carer alarms.

Table 4.3: SafetyCarerAlarm enumerate type
Enumerate constant JSON value Description
NO_ALARM 0 No alarm
HYPO_ALARM 1 Hypo alarm
HYPER_ALARM 2 Hyper alarm
FAULT_ALARM 3 Fault alarm

Related methods:

4.4 SafetyLowGlucoseSuspend

Enumerate SafetyLowGlucoseSuspend is used to determine pump suspension state.

This is only required in the pump version.

Table 4.4: SafetyLowGlucoseSuspend enumerate type
Enumerate constant JSON value Description
NO_SUSPENSION 0 No suspension, operate as normal
PARTIAL_SUSPENSION 1 Partial pump suspension
TOTAL_SUSPENSION 2 Stop the pump
CANCEL_SUSPENSION 3 Indicates the pump has been stopped
RESUME_PUMP 4 Indicates the pump has been resumed

Note: The two enumerates CANCEL_SUSPENSION and RESUME_PUMP are only ever found in the safety system's exported JSON for analysis and should not be used otherwise.

Related methods:

4.5 SafetyExercise

Enumerate SafetyExercise used for Safety System exercise states. Currently the public interface does not require use of this enumerate and is purely used internally at present.

Table 4.5: SafetyExercise enumerate type
Enumerate constant JSON value Description
NO_EXERCISE 0 No excercises
EXERCISE 1 Moderate exercise

Related methods: n/a

4.6 SafetyGlucoseTrend

Enumerate SafetyGlucoseTrend used to determine the glucose rate of change for displaying a corresponding arrow to the user via the graphical user interface.

Internally the glucose trend is not used, this is purely a public exposure resulting from the glucose derivative.

Table 4.6: SafetyGlucoseTrend enumerate type
Enumerate constant JSON value Description Trend arrow
STEADY n/a Steady glucose level
SLOW_RISE n/a Slow glucose level increase
RISE n/a Moderatie glucose level increase
RAPID_RISE n/a Rapid glucose level increase ↑↑
SLOW_FALL n/a Slow glucose level decrease
FALL n/a Moderate glucose level decrease
RAPID_FALL n/a Rapid glucose level decrease ↓↓

Related methods:

4.7 SafetyMealType

Enumerate SafetyMealType used for Safety System meal type states. Currently the public interface does not require use of this enumerate and is purely used internally at present.

Table 4.7: SafetyMealType enumerate type
Enumerate constant JSON value Description
AVERAGE 0 Average (default) meal type
FAST 1 Fast absorption meal type
MEDIUM 2 Medium absorption meal type
SLOW 3 Slow absorption meal type
NO_MEAL n/a No meal type, should not be used

Related methods: n/a

5 Other Functionalities

For all other functionality, the reader should refer to the Javadoc.

The Javadoc for public methods and fields can be found here: http://sots.brookes.ac.uk/~p0044538/SafetySystem/javadoc/

Some other notable methods include:

Bibliography

  1. C. Liu, J. Vehí, P. Avari, M. Reddy, N. Oliver, P. Georgiou, and P. Herrero, “Long-term glucose forecasting using a physiological model and deconvolution of the continuous glucose monitoring signal,” Sensors, vol. 19, no. 19, p. 4338, 2019.
  2. C. Liu, P. Avari, Y. Leal, M. Wos, K. Sivasithamparam, P. Georgiou, M. Reddy, J. M. Fernández-Real, C. Martin, M. Fernáandez-Balsells et al., “A modular safety system for an insulin dose recommender: A feasibility study,” Journal of diabetes science and technology, p. 1932296819851135, 2019.