Merge remote-tracking branch 'upstream/master'

# Conflicts:
#	apps/batterybooster/ChangeLog
#	apps/cutelauncher/ChangeLog
#	apps/onewordclock/ChangeLog
master
Martin Zwigl 2025-02-25 21:19:41 +01:00
commit 84751f3360
15 changed files with 210 additions and 175 deletions

View File

@ -0,0 +1 @@
0.01: New app introduced to the app loader!

View File

@ -2,7 +2,7 @@
"id": "batterybooster",
"name": "Battery Booster",
"icon": "app.png",
"version": "0.1",
"version": "0.01",
"description": "A bootloader app which adds scripts to boost battery life of your Bangle.js 2",
"type": "bootloader",
"tags": "tools,system",
@ -16,4 +16,4 @@
"url": "boot.js"
}
]
}
}

View File

@ -0,0 +1 @@
0.01: New app introduced to the app loader!

View File

@ -2,7 +2,7 @@
"id": "cutelauncher",
"name": "Cute Launcher",
"shortName": "Cute Launcher",
"version": "0.32",
"version": "0.01",
"description": "A simple launcher app for Bangle.js 2 that makes use of the full touchscreen",
"icon": "app.png",
"type": "launch",
@ -35,4 +35,4 @@
"name": "cutelauncher.settings.json"
}
]
}
}

View File

@ -0,0 +1 @@
0.01: New app introduced to the app loader!

View File

@ -2,7 +2,7 @@
"id": "onewordclock",
"name": "One Word Clock",
"shortName": "One Word",
"version": "0.97",
"version": "0.01",
"description": "A unique clock that displays a single evocative word for each hour of the day",
"icon": "app.png",
"screenshots": [
@ -35,4 +35,4 @@
"name": "onewordclock.settings.json"
}
]
}
}

View File

@ -10,3 +10,4 @@
0.09: Add default HRM value, default altitude value
0.10: Add fastloading
0.11: Add option for ISO 8601 date format
0.12: Add day of week line

View File

@ -1,15 +1,15 @@
# Terminal clock
A clock displayed as a terminal cli.
It can display :
A clock displayed as a terminal CLI.
It can display:
- time
- date
- altitude
- hrm
- heart rate
- motion
- steps
"Power saving" setting control the HR and pressure (altitude) sensors.
If "Off" they will always be on.
If "On" the sensors will be turned on every "Power on interval" minutes for 45 secondes
"Power saving" setting control the HR and pressure (altitude) sensors.
If "Off" they will always be on.
If "On" the sensors will be turned on every "Power on interval" minutes for 45 seconds.

View File

@ -11,7 +11,7 @@
let font6x8At2Size = 18;
let font6x8FirstTextSize = 4;
let font6x8DefaultTextSize = 2;
if (process.env.HWVERSION == 1){
if (process.env.HWVERSION == 1) {
paddingY = 3;
font6x8At4Size = 48;
font6x8At2Size = 27;
@ -32,29 +32,32 @@
this.unlock_precision = 1;
if (this.HRMinConfidence === undefined) this.HRMinConfidence = 50;
if (this.PowerOnInterval === undefined) this.PowerOnInterval = 15;
if (this.powerSave===undefined) this.powerSave = this.powerSaving; // migrate old setting
if (this.powerSave===undefined) this.powerSave = true;
if (this.powerSave === undefined) this.powerSave = this.powerSaving; // migrate old setting
if (this.powerSave === undefined) this.powerSave = true;
["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(k => {
if (this[k]===undefined){
if(k == "L2") this[k] = "Date";
else if(k == "L3") {
["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach((k) => {
if (this[k] === undefined) {
if (k == "L2") this[k] = "Date";
else if (k == "L3") {
this[k] = "HR";
this.showHRM = true;
}else if(k == "L4") this[k] = "Motion";
else if(k == "L5") this[k] = "Steps";
else if(k == "L6") this[k] = ">";
else this[k] = "Empty";
}
else if (this[k]==="HR") this.showHRM = true;
else if (this[k]==="Alt") this.showAltitude = true && process.env.HWVERSION == 2;
} else if (k == "L4") this[k] = "Motion";
else if (k == "L5") this[k] = "Steps";
else if (k == "L6") this[k] = ">";
else this[k] = "Empty";
} else if (this[k] === "HR") this.showHRM = true;
else if (this[k] === "Alt")
this.showAltitude = true && process.env.HWVERSION == 2;
});
// set the services (HRM, pressure sensor, etc....)
if(!this.powerSave){
if (!this.powerSave) {
turnOnServices();
} else{
this.turnOnInterval = setInterval(turnOnServices, this.PowerOnInterval*60000); // every PowerOnInterval min
} else {
this.turnOnInterval = setInterval(
turnOnServices,
this.PowerOnInterval * 60000,
); // every PowerOnInterval min
}
// start the clock unlocked
unlock();
@ -67,102 +70,117 @@
drawTime(date, curPos);
curPos++;
["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(line => {
if (this[line]==='Date') drawDate(date, curPos);
else if (this[line]==='HR') drawHRM(curPos);
else if (this[line]==='Motion') drawMotion(curPos);
else if (this[line]==='Alt') drawAltitude(curPos);
else if (this[line]==='Steps') drawStepCount(curPos);
else if (this[line]==='>') drawInput(curPos);
["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach((line) => {
if (this[line] === "Date") drawDate(date, this.isoDate, curPos);
else if (this[line] === "DOW") drawDOW(date, curPos);
else if (this[line] === "HR") drawHRM(curPos);
else if (this[line] === "Motion") drawMotion(curPos);
else if (this[line] === "Alt") drawAltitude(curPos);
else if (this[line] === "Steps") drawStepCount(curPos);
else if (this[line] === ">") drawInput(curPos);
curPos++;
});
},
remove: function() {
if (this.turnOnInterval){
remove: function () {
if (this.turnOnInterval) {
clearInterval(this.turnOnInterval);
delete this.turnOnInterval;
}
if (this.turnOffServiceTimeout){
clearTimeout(this.turnOffServiceTimeout)
delete this.turnOffServiceTimeout
if (this.turnOffServiceTimeout) {
clearTimeout(this.turnOffServiceTimeout);
delete this.turnOffServiceTimeout;
}
turnOffServices();
if (this.onLock) Bangle.removeListener('lock', this.onLock);
if (this.onHRM) Bangle.removeListener('HRM', this.onHRM);
if (this.onPressure) Bangle.removeListener('pressure', this.onPressure);
}
if (this.onLock) Bangle.removeListener("lock", this.onLock);
if (this.onHRM) Bangle.removeListener("HRM", this.onHRM);
if (this.onPressure) Bangle.removeListener("pressure", this.onPressure);
},
});
/* ----------------------------
/* ----------------------------
Draw related of specific lines
-------------------------------- */
let drawLine = function(line, pos){
if(pos == 1)
let drawLine = function (line, pos) {
if (pos == 1) {
g.setFont("6x8", font6x8FirstTextSize);
else
} else {
g.setFont("6x8", font6x8DefaultTextSize);
}
let yPos = Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos-1) +
font6x8At2Size * Math.max(0, pos-2);
let yPos =
Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos - 1) +
font6x8At2Size * Math.max(0, pos - 2);
g.drawString(line, 5, yPos, true);
};
let drawTime = function(now, pos){
let drawTime = function (now, pos) {
let h = now.getHours();
let m = now.getMinutes();
let time = ">" + (""+h).substr(-2) + ":" + ("0"+m).substr(-2);
let time = ">" + ("" + h).substr(-2) + ":" + ("0" + m).substr(-2);
drawLine(time, pos);
};
let drawDate = function(now, pos) {
let drawDate = function (now, pos) {
let date;
if (clock.isoDate) {
let year = now.getFullYear();
let month = now.getMonth() + 1; // Months are 0-11
let month = now.getMonth() + 1; // Months are 0-11
let day = now.getDate();
date = ">" + year + "-" + month + "-" + day;
} else {
let dow = locale.dow(now, 1);
date = locale.date(now, 1).substr(0,6) + locale.date(now, 1).substr(-2);
date = locale.date(now, 1).substr(0, 6); // day and month e.g. 01/02/ from 01/02/2003
date += locale.date(now, 1).substr(-2); // short year e.g. 03 from 01/02/2003
date = ">" + dow + " " + date;
}
drawLine(date, pos);
};
let drawInput = function(pos){
let drawInput = function (pos) {
drawLine(">", pos);
};
let drawStepCount = function(pos){
let drawDOW = function (now, pos) {
drawLine(">" + locale.dow(now, 0), pos);
};
let drawStepCount = function (pos) {
let health = Bangle.getHealthStatus("day");
let steps_formated = ">Steps: " + health.steps;
drawLine(steps_formated, pos);
};
let drawHRM = function(pos){
if(heartRate != 0)
let drawHRM = function (pos) {
if (heartRate != 0) {
drawLine(">HR: " + parseInt(heartRate), pos);
else
} else {
drawLine(
">HR: " + parseInt(Math.round(Bangle.getHealthStatus().bpm||Bangle.getHealthStatus("last").bpm)),
pos);
">HR: " +
parseInt(
Math.round(
Bangle.getHealthStatus().bpm ||
Bangle.getHealthStatus("last").bpm,
),
),
pos,
);
}
};
let drawAltitude = function(pos){
if(altitude > 0)
let drawAltitude = function (pos) {
if (altitude > 0) {
drawLine(">Alt: " + altitude.toFixed(1) + "m", pos);
else
} else {
drawLine(">Alt: unknown", pos);
}
};
let drawMotion = function(pos){
let health = Bangle.getHealthStatus('last');
let drawMotion = function (pos) {
let health = Bangle.getHealthStatus("last");
let steps_formated = ">Motion: " + parseInt(health.movement);
drawLine(steps_formated, pos);
};
@ -171,72 +189,70 @@
Services functions (HRM, pressure, etc...)
-------------------------------------------------- */
let turnOnServices = function(){
if(clock.showHRM){
let turnOnServices = function () {
if (clock.showHRM) {
Bangle.setHRMPower(true, "terminalclock");
}
if(clock.showAltitude){
if (clock.showAltitude) {
Bangle.setBarometerPower(true, "terminalclock");
}
if(clock.powerSave){
if(clock.turnOffServiceTimeout) clearTimeout(clock.turnOffServiceTimeout);
if (clock.powerSave) {
if (clock.turnOffServiceTimeout)
clearTimeout(clock.turnOffServiceTimeout);
clock.turnOffServiceTimeout = setTimeout(function () {
turnOffServices();
}, 45000);
}
};
let turnOffServices = function(){
if(clock.showHRM){
let turnOffServices = function () {
if (clock.showHRM) {
Bangle.setHRMPower(false, "terminalclock");
}
if(clock.showAltitude){
if (clock.showAltitude) {
Bangle.setBarometerPower(false, "terminalclock");
}
};
// set the lock and unlock actions
clock.onLock = lock_event => {
clock.onLock = (lock_event) => {
if (lock_event) lock();
else unlock();
};
Bangle.on("lock", clock.onLock);
clock.onHRM = hrmInfo => {
if(hrmInfo.confidence >= clock.HRMinConfidence)
heartRate = hrmInfo.bpm;
clock.onHRM = (hrmInfo) => {
if (hrmInfo.confidence >= clock.HRMinConfidence) heartRate = hrmInfo.bpm;
};
Bangle.on('HRM', clock.onHRM);
Bangle.on("HRM", clock.onHRM);
const MEDIANLENGTH = 20; // technical
let avr = [], median; // technical
clock.onPressure = pressureInfo => {
while (avr.length>MEDIANLENGTH) avr.pop();
let avr = [],
median; // technical
clock.onPressure = (pressureInfo) => {
while (avr.length > MEDIANLENGTH) avr.pop();
avr.unshift(pressureInfo.altitude);
median = avr.slice().sort();
if (median.length>10) {
let mid = median.length>>1;
altitude = E.sum(median.slice(mid-4,mid+5)) / 9;
}
else
altitude = pressureInfo.altitude;
if (median.length > 10) {
let mid = median.length >> 1;
altitude = E.sum(median.slice(mid - 4, mid + 5)) / 9;
} else altitude = pressureInfo.altitude;
};
Bangle.on('pressure', clock.onPressure);
Bangle.on("pressure", clock.onPressure);
/* -------------------------------------------------
Clock related functions but not in the ClockFace module
---------------------------------------------------- */
let unlock = function(){
if(clock.powerSave){
let unlock = function () {
if (clock.powerSave) {
turnOnServices();
}
clock.precision = clock.unlock_precision;
clock.tick();
};
let lock = function(){
let lock = function () {
clock.precision = clock.lock_precision;
clock.tick();
};

View File

@ -1,25 +1,23 @@
{
{
"id": "terminalclock",
"name": "Terminal Clock",
"shortName":"Terminal Clock",
"description": "A terminal cli like clock displaying multiple sensor data",
"version":"0.11",
"shortName": "Terminal Clock",
"description": "A terminal CLI like clock displaying configurable, multiple sensor data",
"version": "0.12",
"icon": "app.png",
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS", "BANGLEJS2"],
"supports": [
"BANGLEJS",
"BANGLEJS2"
],
"allow_emulator": false,
"readme": "README.md",
"storage": [
{"name": "terminalclock.app.js","url": "app.js"},
{"name": "terminalclock.settings.js","url": "settings.js"},
{"name": "terminalclock.img","url": "app-icon.js","evaluate": true}
{ "name": "terminalclock.app.js", "url": "app.js" },
{ "name": "terminalclock.settings.js", "url": "settings.js" },
{ "name": "terminalclock.img", "url": "app-icon.js", "evaluate": true }
],
"data": [
{"name": "terminalclock.json"}
],
"screenshots": [
{"url": "screenshot1.png"},
{"url": "screenshot2.png"}
]
"data": [{ "name": "terminalclock.json" }],
"screenshots": [{ "url": "screenshot1.png" }, { "url": "screenshot2.png" }]
}

View File

@ -1,23 +1,27 @@
(function(back) {
(function (back) {
var FILE = "terminalclock.json";
// Load settings
var settings = Object.assign({
// TerminalClock specific
isoDate: false,
HRMinConfidence: 50,
PowerOnInterval: 15,
L2: 'Date',
L3: 'HR',
L4: 'Motion',
L5: 'Steps',
L6: '>',
L7: 'Empty',
L8: 'Empty',
L9: 'Empty',
}, require('Storage').readJSON(FILE, true) || {});
var settings = Object.assign(
{
// TerminalClock specific
isoDate: false,
HRMinConfidence: 50,
PowerOnInterval: 15,
L2: "Date",
L3: "HR",
L4: "Motion",
L5: "Steps",
L6: ">",
L7: "Empty",
L8: "Empty",
L9: "Empty",
},
require("Storage").readJSON(FILE, true) || {},
);
// ClockFace lib: migrate "don't load widgets" to "hide widgets"
if (!("hideWidgets" in settings)) {
if (("loadWidgets" in settings) && !settings.loadWidgets) settings.hideWidgets = 1;
if ("loadWidgets" in settings && !settings.loadWidgets)
settings.hideWidgets = 1;
else settings.hideWidgets = 0;
}
delete settings.loadWidgets;
@ -29,20 +33,30 @@
delete settings.powerSaving;
function writeSettings() {
require('Storage').writeJSON(FILE, settings);
require("Storage").writeJSON(FILE, settings);
}
if(process.env.HWVERSION == 2) {
var lineType = ['Date', 'HR', 'Motion', 'Alt', 'Steps', '>', 'Empty'];
} else{
var lineType = ['Date', 'HR', 'Motion', 'Steps', '>', 'Empty'];
if (process.env.HWVERSION == 2) {
var lineType = [
"Date",
"DOW",
"HR",
"Motion",
"Alt",
"Steps",
">",
"Empty",
];
} else {
var lineType = ["Date", "DOW", "HR", "Motion", "Steps", ">", "Empty"];
}
function getLineChooser(lineID){
function getLineChooser(lineID) {
return {
value: lineType.indexOf(settings[lineID]),
min: 0, max: lineType.length-1,
format: v => lineType[v],
onchange: v => {
min: 0,
max: lineType.length - 1,
format: (v) => lineType[v],
onchange: (v) => {
settings[lineID] = lineType[v];
writeSettings();
},
@ -50,35 +64,38 @@
}
var lineMenu = {
'< Back': function() { E.showMenu(getMainMenu());},
'Line 2': getLineChooser('L2'),
'Line 3': getLineChooser('L3'),
'Line 4': getLineChooser('L4'),
'Line 5': getLineChooser('L5'),
'Line 6': getLineChooser('L6'),
'Line 7': getLineChooser('L7'),
'Line 8': getLineChooser('L8'),
'Line 9': getLineChooser('L9'),
"< Back": function () {
E.showMenu(getMainMenu());
},
"Line 2": getLineChooser("L2"),
"Line 3": getLineChooser("L3"),
"Line 4": getLineChooser("L4"),
"Line 5": getLineChooser("L5"),
"Line 6": getLineChooser("L6"),
"Line 7": getLineChooser("L7"),
"Line 8": getLineChooser("L8"),
"Line 9": getLineChooser("L9"),
};
function getMainMenu(){
function getMainMenu() {
var mainMenu = {
"" : { "title" : "Terminal Clock" },
"< Back" : () => back(),
'HR confidence': {
"": { title: "Terminal Clock" },
"< Back": () => back(),
"HR confidence": {
value: settings.HRMinConfidence,
min: 0, max: 100,
onchange: v => {
min: 0,
max: 100,
onchange: (v) => {
settings.HRMinConfidence = v;
writeSettings();
}
},
},
},
"ISO date": {
value: !!settings.isoDate,
onchange: v => {
onchange: (v) => {
settings.isoDate = v;
writeSettings();
}
},
},
};
const save = (key, v) => {
@ -89,19 +106,22 @@
hideWidgets: settings.hideWidgets,
powerSave: settings.powerSave,
});
if(settings.powerSave){
mainMenu['Power on interval'] = {
if (settings.powerSave) {
mainMenu["Power on interval"] = {
value: settings.PowerOnInterval,
min: 3, max: 60,
onchange: v => {
min: 3,
max: 60,
onchange: (v) => {
settings.PowerOnInterval = v;
writeSettings();
},
format: x => x + "m"
format: (x) => x + "m",
};
}
mainMenu['Lines'] = function() { E.showMenu(lineMenu);};
mainMenu["Lines"] = function () {
E.showMenu(lineMenu);
};
return mainMenu;
}

View File

@ -1 +1 @@
0.7: New Text Reader App - Initial version with file browsing and reading capabilities
0.01: New Text Reader App - Initial version with file browsing and reading capabilities

View File

@ -2,7 +2,7 @@
"id": "textreader",
"name": "Text Reader",
"shortName": "TextReader",
"version": "0.7",
"version": "0.01",
"description": "Read text files from your Bangle.js filesystem",
"type": "app",
"tags": "tool,files,reader",
@ -27,4 +27,4 @@
"evaluate": true
}
]
}
}

View File

@ -1,4 +1 @@
0.12: First deployment!
0.13: Refinment of themes and more themes!
0.14: Fixed overlapping theme colors
0.15: Better LoTR theme
0.01: First deployment!

View File

@ -2,7 +2,7 @@
"id": "themes",
"name": "Themes",
"shortName": "Themes",
"version": "0.15",
"version": "0.01",
"description": "Color palettes at your disposal",
"type": "app",
"tags": "tool",
@ -44,4 +44,4 @@
"url": "themes.json"
}
]
}
}