Merge pull request #2490 from phrogg/widbgjs
widbgjs - Get your xDrip Blood Glucose values on the banglemaster
commit
6969c2051e
|
|
@ -0,0 +1 @@
|
|||
0.01: First release
|
||||
|
|
@ -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!
|
||||
|
||||
|
|
@ -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"}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue