Android apps can receive every minute a glucose value from Juggluco.
The glucose broadcast sends every minute the latest “Stream” glucose value. To receive previous glucose values, history values or scans or entered amounts of insulin and carbohydrate etc, you can make use the web server in Juggluco.
Juggluco can imitate xDrip's glucose broadcast com.eveningoutpost.dexdrip.BgEstimate or send a new broadcast: glucodata.Minute.
Apps targeting Android 11 or higher will only receive this broadcast when they have added the following to their AndroidManifest:
<queries> <package android:name="tk.glucodata"/> </queries>
The application id of the app should also be selected in Juggluco's left menu->Settings, "xDrip broadcast" or "Glucodata broadcast".
See a Java example app or a Kotlin example app receiving the glucodata.Minute broadcast and writing the output to logcat.
To AndroidManifest.xml you add:
<application> [...] <receiver android:name="mijn.apps.showglucose.Receiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="glucodata.Minute"/> </intent-filter> </receiver> </application> <queries> <package android:name="tk.glucodata"/> </queries>
And you create the class derived from BroadcastReceiver, here called "mijn.apps.showglucose.Receiver", consisting of onReceive that reads the values out of a Bundle.
package mijn.apps.showglucose; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import java.text.DateFormat; import java.util.Date; public class Receiver extends BroadcastReceiver { private static final String ACTION = "glucodata.Minute"; private static final String ALARM = "glucodata.Minute.Alarm"; //Alarm indicator, see showalarm private static final String GLUCOSECUSTOM = "glucodata.Minute.glucose"; //Glucose in units of settings private static final String LOG_ID = "Receiver"; private static final String MGDL = "glucodata.Minute.mgdl"; //Glucose in mg/dL private static final String RATE = "glucodata.Minute.Rate"; // Rate of change, see label functions private static final String SERIAL = "glucodata.Minute.SerialNumber"; //Serial number of sensor private static final String TIME = "glucodata.Minute.Time"; //Time in msec static DateFormat dateformat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT); @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (!action.equals(ACTION)) { Log.e(LOG_ID, "action=" + action + " != " + ACTION); return; } Bundle extras = intent.getExtras(); String name = extras.getString(SERIAL); int mgdl = extras.getInt(MGDL); float glucose = extras.getFloat(GLUCOSECUSTOM); float rate = extras.getFloat(RATE); int alarm = extras.getInt(ALARM); long time = extras.getLong(TIME); showalarm(alarm); System.out.println(name + " glucose=" + glucose + "(mgdL=" + mgdl + ") rate=" + rate + " (libreLabel=" + librelabel(rate) + ", dexcomlabel="+getdexcomlabel(rate)+") time=" + dateformat.format(new Date(time))); } static String getxdriplabel(float rate ) { if (rate >= 3.5f) return "DoubleUp"; if (rate >= 2.0f) return "SingleUp"; if (rate >= 1.0f) return "FortyFiveUp"; if (rate > -1.0f) return "Flat"; if (rate > -2.0f) return "FortyFiveDown"; if (rate > -3.5f) return "SingleDown"; if(java.lang.Float.isNaN(rate)) return ""; return "DoubleDown"; } static String getdexcomlabel(float rate ) { if (rate >= 3.0f) return "DoubleUp"; if (rate >= 2.0f) return "SingleUp"; if (rate >= 1.0f) return "FortyFiveUp"; if (rate > -1.0f) return "Flat"; if (rate > -2.0f) return "FortyFiveDown"; if (rate > -3.0f) return "SingleDown"; if(java.lang.Float.isNaN(rate)) return ""; return "DoubleDown"; } static String librelabel(float rate) { if (rate <= -2.0f) { return "Falling Quickly".intern(); } if (rate <= -1.0f) { return "Falling".intern(); } if (rate <= 1.0f) { return "Steady".intern(); } if (rate <= 2.0f) { return "Rising".intern(); } if (Float.isNaN(rate)) { return "Undetermined".intern(); } return "Rising Quickly".intern(); }
/*
If alarm&8 is not zero, the alarm goes off. The alarm goes off only once and then waits the number of minutes set with “Minutes deactivated” before going off again.
During the deactivation, alarm&7 still shows whether the glucose value is too high or too low. Whether the glucose value is above the maximally measurable value or below the minimally measurable value is shown independent of whether the alarm is set or not.
*/
void showalarm(int alarm) { if ((alarm & 8) != 0) { System.out.print("Alarm "); } int withoutalarm = alarm & 7; switch (withoutalarm) { case 4: System.out.println("Hightest"); return; case 5: System.out.println("Lowest"); return; case 6: System.out.println("too high"); return; case 7: System.out.println("too low"); return; default: return; } } }