Merge pull request #3477 from bobrippling/feat/hwid-batt-power

hwid battery widget: show power-draw and hours remaining
pull/3499/head^2
Rob Pilling 2024-07-09 08:47:48 +01:00 committed by GitHub
commit 724f8423ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 208 additions and 0 deletions

View File

@ -0,0 +1 @@
0.01: Initial fork from hwid_a_battery_widget

11
apps/widbattpwr/README.md Normal file
View File

@ -0,0 +1,11 @@
# Battery Power Widget
Show the time remaining at the current power consumption, and battery percentage via shading of the text and a percentage bar.
Requires firmware 2v23 or above.
This is a copy of `hwid_a_battery_widget` (that being a copy of `wid_a_battery_widget`).
## Creator
[@bobrippling](https://github.com/bobrippling)

View File

@ -0,0 +1,19 @@
{
"id": "widbattpwr",
"name": "Battery power and percentage widget",
"shortName": "Batt Pwr",
"icon": "widget.png",
"version": "0.01",
"type": "widget",
"supports": ["BANGLEJS2"],
"readme": "README.md",
"description": "A battery widget showing percentage (via shading) and time remaining at current power consumption",
"tags": "widget,battery",
"provides_widgets": ["battery"],
"storage": [
{
"name": "widbattpwr.wid.js",
"url": "widget.js"
}
]
}

81
apps/widbattpwr/widget.js Normal file
View File

@ -0,0 +1,81 @@
(function () {
var intervalLow = 60000;
var intervalHigh = 2000;
var width = 30;
var height = 24;
var showPct = false;
var powerColour = function (pwr) {
return pwr >= 23000
? "#f00"
: pwr > 2000
? "#fc0"
: "#0f0";
};
var drawBar = function (x, y, batt) {
return g.fillRect(x + 1, y + height - 3, x + 1 + (width - 2) * batt / 100, y + height - 1);
};
var drawString = function (x, y, txt) {
return g.drawString(txt, x + 14, y + 10);
};
function draw() {
var x = this.x;
var y = this.y;
var batt = E.getBattery();
var pwr = E.getPowerUsage();
var usage = 0;
for (var key in pwr.device) {
if (!/^(LCD|LED)/.test(key))
usage += pwr.device[key];
}
var pwrColour = powerColour(usage);
g.reset()
.setBgColor(g.theme.bg)
.clearRect(x, y, x + width - 1, y + height - 1);
g.setColor(g.theme.fg);
drawBar(x, y, 100);
g.setColor(pwrColour);
drawBar(x, y, batt);
g.setFontAlign(0, 0);
g.setFont("Vector", 16);
{
var txt = void 0;
if (showPct) {
txt = "".concat(batt, "%");
}
else {
var hrs = 175000 * batt / (100 * usage);
var days = hrs / 24;
txt = days >= 1 ? "".concat(Math.round(Math.min(days, 99)), "d") : "".concat(Math.round(hrs), "h");
}
var txth = 14;
g.setColor(g.theme.fg);
g.setClipRect(x, y, x + width, y + txth);
drawString(x, y, txt);
g.setColor(pwrColour);
g.setClipRect(x, y + txth * (1 - batt / 100), x + width, y + txth);
drawString(x, y, txt);
}
}
var id = setInterval(function () {
var w = WIDGETS["battpwr"];
w.draw(w);
}, intervalLow);
Bangle.on("charging", function (charging) {
changeInterval(id, charging ? intervalHigh : intervalLow);
});
Bangle.on("touch", function (_btn, xy) {
if (WIDGETS["back"] || !xy)
return;
var oversize = 5;
var w = WIDGETS["battpwr"];
var x = xy.x, y = xy.y;
if (w.x - oversize <= x && x < w.x + width + oversize
&& w.y - oversize <= y && y < w.y + height + oversize) {
E.stopEventPropagation && E.stopEventPropagation();
showPct = true;
setTimeout(function () { return (showPct = false, w.draw(w)); }, 1000);
w.draw(w);
}
});
WIDGETS["battpwr"] = { area: "tr", width: width, draw: draw };
})();

BIN
apps/widbattpwr/widget.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 B

96
apps/widbattpwr/widget.ts Normal file
View File

@ -0,0 +1,96 @@
(() => {
const intervalLow = 60000;
const intervalHigh = 2000;
const width = 30;
const height = 24;
let showPct = false;
const powerColour = (pwr: number) =>
pwr >= 23000
? "#f00" // red, e.g. GPS ~20k
: pwr > 2000
? "#fc0" // yellow, e.g. CPU ~1k, HRM ~700
: "#0f0"; // green: ok
const drawBar = (x: number, y: number, batt: number) =>
g.fillRect(x+1, y+height-3, x+1+(width-2)*batt/100, y+height-1);
const drawString = (x: number, y: number, txt: string) =>
g.drawString(txt, x + 14, y + 10);
function draw(this: Widget) {
let x = this.x!;
let y = this.y!;
const batt = E.getBattery();
const pwr = E.getPowerUsage();
let usage = 0;
for(const key in pwr.device){
if(!/^(LCD|LED)/.test(key))
usage += pwr.device[key];
}
const pwrColour = powerColour(usage);
g.reset()
.setBgColor(g.theme.bg)
.clearRect(x, y, x + width - 1, y + height - 1);
g.setColor(g.theme.fg);
drawBar(x, y, 100);
g.setColor(pwrColour);
drawBar(x, y, batt);
g.setFontAlign(0, 0);
g.setFont("Vector", 16);
{
let txt;
if(showPct){
txt = `${batt}%`;
}else{
// 175mAh, scaled based on battery (batt/100), scaled down based on usage
const hrs = 175000 * batt / (100 * usage);
const days = hrs / 24;
txt = days >= 1 ? `${Math.round(Math.min(days, 99))}d` : `${Math.round(hrs)}h`;
}
// draw time remaining, then shade it based on batt %
const txth = 14;
g.setColor(g.theme.fg);
g.setClipRect(x, y, x + width, y + txth);
drawString(x, y, txt);
g.setColor(pwrColour);
g.setClipRect(x, y + txth * (1 - batt / 100), x + width, y + txth);
drawString(x, y, txt);
}
}
const id = setInterval(() => {
const w = WIDGETS["battpwr"]!;
w.draw(w);
}, intervalLow);
Bangle.on("charging", charging => {
changeInterval(id, charging ? intervalHigh : intervalLow);
});
Bangle.on("touch", (_btn, xy) => {
if(WIDGETS["back"] || !xy) return;
const oversize = 5;
const w = WIDGETS["battpwr"]!;
const { x, y } = xy;
if(w.x! - oversize <= x && x < w.x! + width + oversize
&& w.y! - oversize <= y && y < w.y! + height + oversize)
{
E.stopEventPropagation && E.stopEventPropagation();
showPct = true;
setTimeout(() => (showPct = false, w.draw(w)), 1000);
w.draw(w);
}
});
WIDGETS["battpwr"] = { area: "tr", width, draw };
})();