Merge pull request #2490 from phrogg/widbgjs

widbgjs - Get your xDrip Blood Glucose values on the bangle
master
Gordon Williams 2023-01-12 10:15:52 +00:00 committed by GitHub
commit 6969c2051e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 249 additions and 0 deletions

1
apps/widbgjs/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: First release

29
apps/widbgjs/README.md Normal file
View File

@ -0,0 +1,29 @@
# Prerequisites
For this widget to work and to get data from the phone, you need:
- An Android phone
- with xDrip and the <a href="https://codeberg.org/phrogg/BG2BangleJSApp/" target="_BLANK">helper app</a> installed.
- the <a href="https://f-droid.org/en/packages/com.espruino.gadgetbridge.banglejs/" target="_BLANK">Gadgetbridge app (bangle version)</a> for the Android phone
- A BangleJS
- With this widget installed
# Widget
## How to use it
Make sure you have all the prerequisites from above.
The watch should automatically start displaying values, if there is an arrow visible behind the value, the value is within the not-expired-yet time range changeable in the settings standard is 15 minutes. (I will probably change this in the future, to strike through the text to make expired values clearer).
## Settings
In the settings, you can:
- Disable/hide the widget
- Change the unit from mmol/L to mg/dL
- Set a time at which old BG values expire
# Developer
Developed by Phil Roggenbuck (<a href="https://github.com/phrogg" target="_BLANK">phrogg</a>)
# Disclaimer
As well as xdrip you should not use this app to make medical decisions!

View File

@ -0,0 +1,22 @@
{
"id": "widbgjs",
"name": "Blood Glucose Widget (xdrip)",
"shortName":"BG Widget",
"icon": "screenshot.png",
"screenshots": [{"url":"screenshot.png"}],
"version":"0.01",
"type": "widget",
"supports": ["BANGLEJS", "BANGLEJS2"],
"readme": "README.md",
"allow_emulator":true,
"description": "Displays the current blood glucose received from xdrip and send over via a <a href=\"https://codeberg.org/phrogg/BG2BangleJSApp/\" target=\"_BLANK\">helper app</a> on the watch.",
"tags": "widget",
"storage": [
{"name":"widbgjs.wid.js","url":"widget.js"},
{"name":"widbgjs.settings.js","url":"settings.js"}
],
"data": [
{"name":"widbgjs.json"},
{"name":"widbgjs.settings.json"}
]
}

BIN
apps/widbgjs/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

54
apps/widbgjs/settings.js Normal file
View File

@ -0,0 +1,54 @@
(function (back) {
const SAVEFILE = "wpbgjs.settings.json";
// initialize with default settings...
let s = {
'unitIsMmol': true,
'expireThreshold': 600000,
'hide': false
};
// ...and overwrite them with any saved values
// This way saved values are preserved if a new version adds more settings
const storage = require('Storage');
const d = storage.readJSON(SAVEFILE, 1) || {};
const saved = d.settings || {};
for (const key in saved) {
s[key] = saved[key];
}
function save() {
d.settings = s;
storage.write(SAVEFILE, d);
WIDGETS['widbgjs'].draw();
}
E.showMenu({
'': { 'title': 'BG widget' },
'Unit': {
value: s.unitIsMmol,
format: () => (s.unitIsMmol ? 'mmol/L' : 'mg/dL'),
onchange: () => {
s.unitIsMmol = !s.unitIsMmol;
save();
},
},
'Exp. BG': {
value: s.expireThreshold,
min: 18000, step: 60000,
format: s => (s ? s / 60000 + ' min' : '0'),
onchange: (g) => {
s.expireThreshold = g;
save();
},
},
'Hide Widget': {
value: s.hide,
format: () => (s.hide ? 'Yes' : 'No'),
onchange: () => {
s.hide = !s.hide;
save();
},
},
'< Back': back,
});
});

143
apps/widbgjs/widget.js Normal file
View File

@ -0,0 +1,143 @@
//WIDGETS = {}; // <-- for development only
(() => {
// persistant vals
let storedData;
let settings;
function loadSettings() { // stolen from https://github.com/espruino/BangleApps/blob/master/apps/widpedom/widget.js
const d = require('Storage').readJSON("widbgjs.settings.json", 1) || {};
settings = Object.assign({
'unitIsMmol': true,
'expireThreshold': 600000,
'reloadInterval': 5 * 60000,
'hide': false
}, d || {});
return d;
}
function loadVals() {
try {
const d = require('Storage').readJSON("widbgjs.json", 1) || {};
storedData = Object.assign({
'bg': null,
'bgTimeStamp': null,
'bgDirection': null
}, d || {});
return d;
} catch(e) {
Bangle.removeFile("widbgjs.json");
}
return null;
}
function calculateRotation(bgDirection) {
var a = 90;
// get the arrow right (https://github.com/StephenBlackWasAlreadyTaken/NightWatch/blob/6de1d3775c6e447177c12f387f647628cc8e24ce/mobile/src/main/java/com/dexdrip/stephenblack/nightwatch/Bg.java)
switch (bgDirection) {
case ("DoubleDown"):
g.setColor("#f00");
a = 180;
break;
case ("SingleDown"):
a = 180;
break;
case ("DoubleUp"):
g.setColor("#f00");
a = 0;
break;
case ("SingleUp"):
a = 0;
break;
case ("FortyFiveUp"):
a = 45;
break;
case ("FortyFiveDown"):
a = 135;
break;
case ("Flat"):
a = 90;
break;
}
// turn the arrow thanks to (https://forum.espruino.com/conversations/344607/)
const p180 = Math.PI / 180;
// a is defined above
var r = 21;
var x = r * Math.sin(a * p180);
var y = r * Math.cos(a * p180);
return a * p180;
}
function getBG(bg) {
var tmp = null;
try {
if (storedData.bg !== null) {
tmp = bg;
if (settings.unitIsMmol) {
tmp /= 18;
tmp = tmp.toFixed(1);
}
}
} catch (e) { }
return tmp;
}
function isBgTooOld(bgTimeStamp) {
var currTimeInMilli = new Date().valueOf();
try {
if (bgTimeStamp === null) {
return true;
}
if (currTimeInMilli - settings.expireThreshold <= bgTimeStamp) {
return false;
}
} catch (e) { }
return true;
}
function draw() {
loadSettings();
try {
if (settings.hide) return;
} catch (e) { }
loadVals();
outpt = getBG(storedData.bg);
if (outpt === null) { // this means no value has been received yet
outpt = "BG";
bgTimeStamp = "0";
}
// prepare to write on the screen
g.reset().clearRect(this.x, this.y, this.x + this.width, this.y + 23); // erase background
g.setFont('Vector', 22);
g.setColor(g.theme.fg);
// check if the value is too old
if (!isBgTooOld(storedData.bgTimeStamp)) {
g.drawImage(atob("FBQBAGAADwAB+AA/wAduAGZgAGAABgAAYAAGAABgAAYAAGAABgAAYAAGAABgAAYAAGAABgA="), this.x + 60, this.y + 9, { rotate: calculateRotation(storedData.bgDirection) });
}
g.setColor(g.theme.fg).drawString(outpt, this.x + 5, this.y);
}
setInterval(function () {
WIDGETS["widbgjs"].draw(WIDGETS["widbgjs"]);
}, 5 * 60000); // update every 5 minutes (%* 60000
// add your widget
WIDGETS["widbgjs"] = {
area: "tl",
width: 72,
draw: draw
};
})();
//Bangle.drawWidgets(); // <-- for development only