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.
In Juggluco and in Kerfstok, rate of change near zero (-0.8<rate<0.8) is displayed as zero, thus showing a horizontal arrow (Steady). This is done to prevent an upward arrow, when in reality the glucose value is falling and the other way around. This threshold is not applied to the rate of change in the exported values, the eXport/xDrip/Nightscout webserver in Juggluco and the glucose broadcasts.
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 of 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 getdexcomlabel(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 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(); } 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; } } }