From 674cfcbd3ad461b861d4b543c1ed9430ea156345 Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Thu, 7 Sep 2023 22:36:18 +0100 Subject: [PATCH 001/260] Created app.js --- apps/Tyreid/app.js | 272 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 apps/Tyreid/app.js diff --git a/apps/Tyreid/app.js b/apps/Tyreid/app.js new file mode 100644 index 000000000..8490a8b97 --- /dev/null +++ b/apps/Tyreid/app.js @@ -0,0 +1,272 @@ +//---------------------------- Tyreid ----------------------------// +// +// Bluetooth war-driving app for the Bangle.js 2 +// +// TH10111 2023 +// + +Bangle.loadWidgets(); +Bangle.drawWidgets(); // <-- for development only (shouldn't need for a real app) + +// Global variables +var gpsFix_flag = 0; +var bt_id_arr = []; +var num_bt_devices = 0; +var running_flag = 0; // 0 = stopped, 1 = running, 2 = paused + +// Log file +var file = require("Storage").open("tyreid_log.csv","w"); + +// Logo +var logo = { + width : 176, height : 176, bpp : 2, + buffer : atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC///QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf///QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv/////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH///v//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///+f//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/+/4f//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//b/gf//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/8v+Af//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//C/4Af//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4L/gAf//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC//Av+AAb//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/0C/0AAb//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+AP/QAAb//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/wA/9AAAb//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9AD/0AAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv/gAP/QAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AA/9AAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//QAD/0AAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/8AAP/QAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAA/9AAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AAD/0AAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//AAAP/QAAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/0AAA/9AAAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/+AAAD/0AAAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/wAAAP/QAAAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9AAAA/9AAAAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv/wAAAD/0AAAAAAAL//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAP/QAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//gAAAA/9AAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AAAAD/0AAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//QAAAAP/QAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/4AAAAA/9AAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//AAAAAD/0AAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/0AAAAAP/QAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC//AAAAAA/9AAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAD/0AAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9AAAAAAP/QAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/wAAAAAA/9AAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9AAAAAAD/0AAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv/gAAAAAAP/QAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AAAAAAA/9AAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//QAAAAAAD/0AAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/8AAAAAAAP/QAAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//AAAAAAAA/8AAAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AAAAAAAD/wAAAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//AAAAAAAAP/AAAAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/0AAAAAAAA/8AAAAAAAAAAAAAAH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+AAAAAAAAD/wAAAAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAf/wAAAAAAAAP/AAAAAAAAAAAAAAAH//QAAAAAAAAAAAAAAAAAAAAAAAAAAAv9AAAAAAAAA/8AAAAAAAAAAAAAAAv/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAAD/wAAAAAAAAAAAAAAP//0AAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAP/AAAAAAAAAAAAAAH//+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAAAAAAAB///QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAAAAAv//kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAAAAAAAAP//5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAAAAAAH//9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAAAB///QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAAAAAAAv//kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAAAAAL//5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAAD//9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAAAAAB///QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAAAAf//kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAL//4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAAAAD//9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAAB///QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAf//kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAAAH//4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAC//9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAABv/+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAAf//kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAL//4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAH//9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAv/+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAC//kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAH/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AAAAAAH/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAL/5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAf/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAf/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAv/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAv/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAB//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAB//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAC/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAG/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAH/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAAH/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAAL/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAf/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAAAf/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAAAv/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAAv/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAAAB//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAAC/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAAAAH/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAAAAH/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAAAL/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAAAAAL/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAAAAAf/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAAAAAAv/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAAAAAAv/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAAAAAAAAAAAC/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAAAAAH/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gAAAAAAAAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv+AAAAAAAAAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGqQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") +}; + + +// +// Functions +// + +function gpsTick(fix) { // GPS fix callback + //console.log(fix); // print GPS Fix info to console + if (fix.fix > 0) { + gpsFix_flag = 1; + } else { + gpsFix_flag = 0; + } + WIDGETS["widTyreid"].draw(WIDGETS["widTyreid"]); // update widget with gps tick + Bangle.drawWidgets(); // Not sure why I need this here, but otherwise the widget draws over itself without clearing first! +} + +function gpsON() { // Turn GPS on + Bangle.on('GPS',gpsTick); + Bangle.setGPSPower(true); +} + +function gpsOFF() { // Turn GPS off + Bangle.setGPSPower(false); +} + +function btPacket(packet) { // BT packet callback + let latest_fix = Bangle.getGPSFix(); + let mac = packet.id.substring(0,17); + let mac_info = packet.id.substring(18); + +// console.log(" "); +// console.log(packet); // print packet info + //console.log(mac); + //console.log(5*latest_fix.hdop); // print latest GPS fix info +// console.log(" "); + + // Compile the values to be stored + var new_data = [ + latest_fix.time, + latest_fix.lat, + latest_fix.lon, + latest_fix.alt, + latest_fix.hdop*5, + packet.name, + mac, + mac_info, + packet.manufacturer, + packet.rssi, + packet.services, + packet.data, + packet.serviceData, + packet.manufacturerData + ]; + // Write data to the file (including a new line) + file.write(new_data.join(",")+"\n"); + + if (num_bt_devices < 99) { + if (!bt_id_arr.includes(mac)) { // if device id has not been recorded + bt_id_arr[num_bt_devices] = mac; // note the id + num_bt_devices++; // increment the number of devices found + // Add the new device to the devices menu, with information... + //console.log(" "); + //console.log(mac); + //console.log(packet.manufacturer); + //console.log(latest_fix.time); + //console.log(packet.rssi); + //console.log(" "); + // Add the new device to the devices menu, with information... + device_menu[mac] = () => { + E.showPrompt([mac,mac_info],{title:"MAC",buttons:{"Ok":true}}).then(function(v){ + E.showPrompt(packet.manufacturer,{title:"Manufacturer",buttons:{"Ok":true}}).then(function(v){ + E.showPrompt(latest_fix.time,{title:"First Seen",buttons:{"Ok":true}}).then(function(v){ + E.showPrompt(packet.rssi,{title:"RSSI",buttons:{"Ok":true}}).then(function(v){ + E.showMenu(device_menu); + }); + }); + }); + }); + }; + } + } +} + +function headings() { // Add headings to the file + // Compile the values to be stored + var new_data = [ + "Time", + "Latitude", + "Longitude", + "Altitude", + "Accuracy", + "Name", + "MAC", + "MAC Info", + "Manufacturer", + "RSSI", + "Services", + "Data", + "Service Data", + "Manufacturer Data" + ]; + // Write data to the file (including a new line) + file.write(new_data.join(",")+"\n"); +} + +function btON() { // Turn Bluetooth on + NRF.setScan(btPacket); +} + +function btOFF() { // Turn Bluetooth off + NRF.setScan(); +} + +function start() { // Start the application + bt_id_arr = []; + headings(); + num_bt_devices = 0; + btON(); + running_flag = 1; + E.showMenu(running_menu); +} + +function exit() { // Exit the application + gpsOFF(); + btOFF(); + running_flag = 0; + load(); +} + +function pause() { // Pause the application + btOFF(); + running_flag = 2; + //console.log(bt_id_arr); + E.showMenu(pause_menu); +} + +function resume() { // Continue after pause + btON(); + running_flag = 1; + E.showMenu(running_menu); +} + +function marker() { // add a marker packet to the log + let latest_fix = Bangle.getGPSFix(); + +// console.log(" "); +// console.log("MARKER"); // print packet info +// console.log(" "); + + // Compile the values to be stored + var new_data = [ + latest_fix.time, + latest_fix.lat, + latest_fix.lon, + latest_fix.alt, + latest_fix.hdop, + "MARKER" + ]; + + // Write data to the file (including a new line) + file.write(new_data.join(",")+"\n"); + + // Indicate that the marker has been added + E.showMessage("Marker Added."); + + // Back to the menu + if (running_flag == 0) { + E.showMenu(init_menu); + } else if (running_flag == 1) { + E.showMenu(running_menu); + } else { + E.showMenu(pause_menu); + } +} + +setWatch(() => { // If the button is pressed, then add a marker + marker(); +}, BTN1, {repeat:true}); + +WIDGETS["widTyreid"]={ + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: 24, // width of the widget + draw: function() { + let disp_dev_val = "-"; + g.reset(); // reset the graphics context to defaults (color/font/etc) + if (gpsFix_flag == 1) { + g.setColor(0,1,0); // green + } else { + g.setColor(1,0,0); // red + } + if (num_bt_devices < 99) { + disp_dev_val = num_bt_devices.toString(); + } else { + disp_dev_val = "99+"; + } + g.setFont("6x8",3); + g.drawString(disp_dev_val, this.x+24/2, this.y); + } + }; + + +let init_menu = { + "": { "title": "Tyreid" }, + "Start": function() { start(); }, + "Marker": function() { marker(); }, + "Exit": function() { exit(); }, +}; + +let running_menu = { + "": { "title": "[Running]" }, + "Pause": function() { pause(); }, + "Marker": function() { marker(); }, + "Exit": function() { exit(); }, +}; + +let pause_menu = { + "": { "title": "[Paused]" }, + "Continue": function() { resume(); }, + "Devices": function() { E.showMenu(device_menu); }, + "Marker": function() { marker(); }, + "Exit": function() { exit(); }, +}; + +let device_menu = { + "": { "title": "Devices:" }, + "Back": function() { + if (running_flag == 0) { + E.showMenu(init_menu); + } else if (running_flag == 1) { + E.showMenu(running_menu); + } else { + E.showMenu(pause_menu); + } + }, +}; + + +// Main +gpsON(); // turn GPS on straight away to start trying for a fix +g.setColor(1,1,1).fillRect(0,0,176,176); +g.drawImage(logo,0,0); // splash screen +// 2sec wait before starting initial menu +setTimeout(function () { + E.showMenu(init_menu); +}, 2*1000); + + From 5f589ad2474d678c223be700d735a42411af7b9c Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Thu, 7 Sep 2023 22:48:43 +0100 Subject: [PATCH 002/260] Created app-icon.js --- apps/Tyreid/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/Tyreid/app-icon.js diff --git a/apps/Tyreid/app-icon.js b/apps/Tyreid/app-icon.js new file mode 100644 index 000000000..503a87b59 --- /dev/null +++ b/apps/Tyreid/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("MDACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAtAAAAAAAAAAAAAAB/QAAAAAAAAAAAAAD/0AAAAAAAAAAAAAH+9AAAAAAAAAAAAAPtfQAAAAAAAAAAAAudH0AAAAAAAAAAAB8tB9AAAAAAAAAAAD0tAfQAAAAAAAAAAHgtAH0AAAAAAAAAAPAtAB9AAAAAAAAAAtAtAAfQAAAAAAAAB8AtAAH0AAAAAAAAD0AtAAB9AAAAAAAALgAtAAAfQAAAAAAAfAAtAAAH0AAAAAAA9AAtAAAB9AAAAAAC4AAtAAAAfQAAAAADwAAtAAAALwAAAAAAQAAtAAAAvgAAAAAAAAAsAAAC9AAAAAAAAAAsAAAP0AAAAAAAAAAsAAB/AAAAAAAAAAAsAAH4AAAAAAAAAAAsAAvQAAAAAAAAAAAsAD9AAAAAAAAAAAAsAD0AAAAAAAAAAAAsAB8AAAAAAAAAAAAsAAtAAAAAAAAAAAAsAAPQAAAAAAAAAAAsAAHwAAAAAAAAAAAsAAC4AAAAAAAAAAAsAAA9AAAAAAAAAAAsAAAPAAAAAAAAAAAsAAAHgAAAAAAAAAA8AAAC0AAAAAAAAAA8AAAA8AAAAAAAAAA8AAAAEAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) From 2129518bac3c589e15a540a5ad3815d71d0648c0 Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Thu, 7 Sep 2023 22:52:54 +0100 Subject: [PATCH 003/260] Create metadata.json --- apps/Tyreid/metadata.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 apps/Tyreid/metadata.json diff --git a/apps/Tyreid/metadata.json b/apps/Tyreid/metadata.json new file mode 100644 index 000000000..c84c04113 --- /dev/null +++ b/apps/Tyreid/metadata.json @@ -0,0 +1,14 @@ +{ "id": "Tyreid", + "name": "Tyreid", + "shortName":"Tyreid", + "version":"0.01", + "description": "Bluetooth war-driving app for Bangle.js 2", + "icon": "Tyreid.img", + "tags": "", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"Tyreid.app.js","url":"app.js"}, + {"name":"Tyreid.img","url":"app-icon.js","evaluate":true} + ] +} From 8ba28925da3204b98ebd62b4c22b1ccb1fd1c689 Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Thu, 7 Sep 2023 23:08:25 +0100 Subject: [PATCH 004/260] Update metadata.json --- apps/Tyreid/metadata.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/Tyreid/metadata.json b/apps/Tyreid/metadata.json index c84c04113..20f605c4a 100644 --- a/apps/Tyreid/metadata.json +++ b/apps/Tyreid/metadata.json @@ -6,7 +6,6 @@ "icon": "Tyreid.img", "tags": "", "supports" : ["BANGLEJS2"], - "readme": "README.md", "storage": [ {"name":"Tyreid.app.js","url":"app.js"}, {"name":"Tyreid.img","url":"app-icon.js","evaluate":true} From 7fc876f747d953f3f4b01ac9e1c5361f5841fe49 Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:47:52 +0100 Subject: [PATCH 005/260] Create README.md --- apps/Tyreid/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/Tyreid/README.md diff --git a/apps/Tyreid/README.md b/apps/Tyreid/README.md new file mode 100644 index 000000000..8178c76d6 --- /dev/null +++ b/apps/Tyreid/README.md @@ -0,0 +1 @@ +readme From 1c693d85f8a82527ed8347c2789a1042331c51be Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Fri, 8 Sep 2023 07:03:47 +0100 Subject: [PATCH 006/260] Update README.md --- apps/Tyreid/README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/Tyreid/README.md b/apps/Tyreid/README.md index 8178c76d6..28647e569 100644 --- a/apps/Tyreid/README.md +++ b/apps/Tyreid/README.md @@ -1 +1,17 @@ -readme +Tyreid + +Tyreid is a Bluetooth war-driving app for the Bangle.js 2. + +Menu options: +- Start: This turns on the Bluetooth and starts logging Bluetooth packets with time, latitude, and longitude information to a CSV file. +- Pause/Continue: These functions pause the capture and then allow it to resume. +- Devices: When paused this menu option will display the MAC addresses of discovered Bluetooth devices. Selecting a device will then display the MAC, Manufacturer code, the time it was first seen, and the RSSI of the first sighting. +- Marker: This command adds a 'marker' to the CSV log, which consists of the time and location information, but the Bluetooth packet information is replaced with the word MARKER. Markers can also be added by pressing the watch's button. +- Exit: This exits the app. + +The current number of discovered devices is displayed in the top left corner. + +To retrieve the CSV file, connect to the watch through the Espruino web IDE (https://www.espruino.com/ide/). From there the files stored on the watch can be downloaded by clicking the storage icon in the IDE's central column. + + + From f4cd093fb0c4f0661c441cadaf96af370e1717fc Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Fri, 8 Sep 2023 07:04:21 +0100 Subject: [PATCH 007/260] Update metadata.json --- apps/Tyreid/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/Tyreid/metadata.json b/apps/Tyreid/metadata.json index 20f605c4a..c84c04113 100644 --- a/apps/Tyreid/metadata.json +++ b/apps/Tyreid/metadata.json @@ -6,6 +6,7 @@ "icon": "Tyreid.img", "tags": "", "supports" : ["BANGLEJS2"], + "readme": "README.md", "storage": [ {"name":"Tyreid.app.js","url":"app.js"}, {"name":"Tyreid.img","url":"app-icon.js","evaluate":true} From 2697c544f030199c967af0d6729d2bc54ef6344d Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:32:17 +0100 Subject: [PATCH 008/260] Update app.js --- apps/Tyreid/app.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/Tyreid/app.js b/apps/Tyreid/app.js index 8490a8b97..8ab63cabd 100644 --- a/apps/Tyreid/app.js +++ b/apps/Tyreid/app.js @@ -207,21 +207,21 @@ WIDGETS["widTyreid"]={ width: 24, // width of the widget draw: function() { let disp_dev_val = "-"; - g.reset(); // reset the graphics context to defaults (color/font/etc) - if (gpsFix_flag == 1) { - g.setColor(0,1,0); // green - } else { - g.setColor(1,0,0); // red - } + if (num_bt_devices < 99) { disp_dev_val = num_bt_devices.toString(); } else { disp_dev_val = "99+"; } + g.setFont("6x8",3); - g.drawString(disp_dev_val, this.x+24/2, this.y); - } - }; + if (gpsFix_flag == 1) { + g.setColor(0,1,0).drawString(disp_dev_val, this.x+24/2, this.y); // green + } else { + g.setColor(1,0,0).drawString(disp_dev_val, this.x+24/2, this.y); // red + } + } +}; let init_menu = { From 0474abef3bb7169a8018c92afd4ca1278e1eac76 Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:32:37 +0100 Subject: [PATCH 009/260] Update metadata.json --- apps/Tyreid/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/Tyreid/metadata.json b/apps/Tyreid/metadata.json index c84c04113..adb9c459d 100644 --- a/apps/Tyreid/metadata.json +++ b/apps/Tyreid/metadata.json @@ -1,7 +1,7 @@ { "id": "Tyreid", "name": "Tyreid", "shortName":"Tyreid", - "version":"0.01", + "version":"0.02", "description": "Bluetooth war-driving app for Bangle.js 2", "icon": "Tyreid.img", "tags": "", From 1438501215c1e559173bf172272cf8485f371a0d Mon Sep 17 00:00:00 2001 From: th10111 <144286414+th10111@users.noreply.github.com> Date: Sun, 10 Sep 2023 22:26:52 +0100 Subject: [PATCH 010/260] Update README.md --- apps/Tyreid/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/Tyreid/README.md b/apps/Tyreid/README.md index 28647e569..5c205ab57 100644 --- a/apps/Tyreid/README.md +++ b/apps/Tyreid/README.md @@ -10,6 +10,7 @@ Menu options: - Exit: This exits the app. The current number of discovered devices is displayed in the top left corner. +This value is displayed in green when the GPS has a fix, or red otherwise. To retrieve the CSV file, connect to the watch through the Espruino web IDE (https://www.espruino.com/ide/). From there the files stored on the watch can be downloaded by clicking the storage icon in the IDE's central column. From a67e5cfcee10b51b090d136e0d7d480460baad97 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 Oct 2023 11:25:36 +0100 Subject: [PATCH 011/260] Allow upload even with warnings --- apps/espruinoprog/custom.html | 58 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/apps/espruinoprog/custom.html b/apps/espruinoprog/custom.html index a12189707..c6c51ca3e 100644 --- a/apps/espruinoprog/custom.html +++ b/apps/espruinoprog/custom.html @@ -128,38 +128,36 @@ LED.set();NRF.sleep();`); posteditor.on("change", editorChanged); document.getElementById("upload").addEventListener("click", function() { - if (!hasWarnings()) { - var precode = preeditor.getValue(); - var jscode = jseditor.getValue(); - var postcode = posteditor.getValue(); - var namePrefix = document.getElementById("nameprefix").value; - localStorage.setItem(LS_PRECODE, precode); - localStorage.setItem(LS_JSCODE, jscode); - localStorage.setItem(LS_POSTCODE, postcode); - localStorage.setItem(LS_NAMEPREFIX, namePrefix); + var precode = preeditor.getValue(); + var jscode = jseditor.getValue(); + var postcode = posteditor.getValue(); + var namePrefix = document.getElementById("nameprefix").value; + localStorage.setItem(LS_PRECODE, precode); + localStorage.setItem(LS_JSCODE, jscode); + localStorage.setItem(LS_POSTCODE, postcode); + localStorage.setItem(LS_NAMEPREFIX, namePrefix); - // force version - as long as we're above 1v96 we get the ability to upload to different storage files - var ENV = Espruino.Core.Env.getData(); - ENV.VERSION_MAJOR = 2; - ENV.VERSION_MINOR = 0; - // Now compile - Espruino.transform(jscode, { - SET_TIME_ON_WRITE : false, // time would just be out of date - SAVE_ON_SEND : 1, // save to flash - LOAD_STORAGE_FILE : 0, // do not load from storage after saving - // PRETOKENISE : true, - // MINIFICATION_LEVEL : "ESPRIMA", // maybe? - }).then(content => { - sendCustomizedApp({ - storage: [{ name: "espruinoprog.json", content: JSON.stringify({ - namePrefix : namePrefix, - pre : Espruino.Core.CodeWriter.reformatCode(precode), - code : Espruino.Core.CodeWriter.reformatCode(content), - post : Espruino.Core.CodeWriter.reformatCode(postcode) - })}] - }); + // force version - as long as we're above 1v96 we get the ability to upload to different storage files + var ENV = Espruino.Core.Env.getData(); + ENV.VERSION_MAJOR = 2; + ENV.VERSION_MINOR = 0; + // Now compile + Espruino.transform(jscode, { + SET_TIME_ON_WRITE : false, // time would just be out of date + SAVE_ON_SEND : 1, // save to flash + LOAD_STORAGE_FILE : 0, // do not load from storage after saving + // PRETOKENISE : true, + // MINIFICATION_LEVEL : "ESPRIMA", // maybe? + }).then(content => { + sendCustomizedApp({ + storage: [{ name: "espruinoprog.json", content: JSON.stringify({ + namePrefix : namePrefix, + pre : Espruino.Core.CodeWriter.reformatCode(precode), + code : Espruino.Core.CodeWriter.reformatCode(content), + post : Espruino.Core.CodeWriter.reformatCode(postcode) + })}] }); - } + }); }); document.getElementById("setdefault").addEventListener("click", function(e) { e.preventDefault(); From de5fcd2efa0ab6aa051ffce52da1575e983ae188 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 Oct 2023 11:40:49 +0100 Subject: [PATCH 012/260] Add tool to count flashes of light using the HRM --- apps/flashcount/ChangeLog | 1 + apps/flashcount/app-icon.js | 1 + apps/flashcount/app.js | 59 ++++++++++++++++++++++++++++++++++ apps/flashcount/app.png | Bin 0 -> 1255 bytes apps/flashcount/metadata.json | 13 ++++++++ 5 files changed, 74 insertions(+) create mode 100644 apps/flashcount/ChangeLog create mode 100644 apps/flashcount/app-icon.js create mode 100644 apps/flashcount/app.js create mode 100644 apps/flashcount/app.png create mode 100644 apps/flashcount/metadata.json diff --git a/apps/flashcount/ChangeLog b/apps/flashcount/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/flashcount/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/flashcount/app-icon.js b/apps/flashcount/app-icon.js new file mode 100644 index 000000000..e1cf5fb54 --- /dev/null +++ b/apps/flashcount/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///x3ygHo8H1Jf8AgILLoALVgoLHggLCqAgJioLIqgLDGQsBqtAioOBqoYFqtUAIMVBY9VqwCBDIIAECYILCHowLBrWVBZFlrWWyptGgtq1WqJYI7GrQLCFxGrBYJHEBQNV1Wv9IEBEocFKIOq//qJAIZEAoNq3/+1QMBHoYYBrQLB1J4GitaEYZfGtfvBYJ3HtWr9WlNY0V1Nr1WlC4xIBrWmBZWVrJGFcYILBZY4LBoILIgoNBEILvHDIQ5BBY4IBBYMBMAwLBBA4LPBRMAKAoLRiALWAGw=")) \ No newline at end of file diff --git a/apps/flashcount/app.js b/apps/flashcount/app.js new file mode 100644 index 000000000..e3f925b27 --- /dev/null +++ b/apps/flashcount/app.js @@ -0,0 +1,59 @@ +Bangle.loadWidgets(); +Bangle.drawWidgets(); +E.showMessage("Loading..."); +Bangle.setOptions({hrmPollInterval:5}); +Bangle.setHRMPower(1); + +function drawCounter() { + g.reset().clearRect(0,24,175,90); + //g.drawRect(0,24,175,90); + g.setFontAlign(0,0).setFontVector(60); + g.drawString(count, 88, 60); +} + +function hadPulse() { + count++; + drawCounter(); + g.setColor("#f00").fillCircle(156,156,20); + setTimeout(function() { + g.setColor(g.theme.bg).fillCircle(156,156,20); + }, 500); +} + +if (parseFloat(process.env.VERSION.replace("v","0"))<2019) { + E.showMessage("You need at least firmware 2v19","Error"); +} else if (Bangle.hrmRd(0)!=33) { // wrong sensor - probably VC31 from original bangle.js 2 + E.showMessage("This Bangle.js doesn't have a VC31B HRM sensor","Error"); +} else { + Bangle.setOptions({hrmGreenAdjust:false, hrmWearDetect:false, hrmPushEnv:true}); + Bangle.hrmWr(0x10, 197&0xF8 | 4); // just SLOT2 + Bangle.hrmWr(0x16, 0); // force env to be used as fast as possible + + var samples = 0, samplesHi = 0; + var count = 0; + { + let last = 0; + Bangle.on('HRM-env',v => { + if (v) { + if (!last) hadPulse(); + samplesHi++; + } + last = v; + samples++; + }); + } + + drawCounter(); + setInterval(function() { + g.reset().clearRect(0,90,175,130); + g.setFontAlign(0,0).setFont("6x8:2"); + g.drawString(samples+" sps", 88, 100); + if (samplesHi*5 > samples) { + g.setBgColor("#f00").setColor("#fff"); + g.clearRect(0,110,175,130).drawString("TOO LIGHT",88,120); + } + samples=0; + samplesHi=0; + Bangle.setLCDPower(1); // force LCD on! + }, 1000); +} \ No newline at end of file diff --git a/apps/flashcount/app.png b/apps/flashcount/app.png new file mode 100644 index 0000000000000000000000000000000000000000..379b9d381cd737351d455d34cbfc7661a9b305f4 GIT binary patch literal 1255 zcmVEX>AG#Sgg__Xu%4YBDAu* z=j=o=SQ0f55rxt{XBQK*FFqJTA9&Ej#21m6*!aei(I^i-@}P-6_+a$K7k74cXXczO ziRf?6>}_Ut_Tpu>PO@L}C++NX=Kuc7_y1>$P#bNu;TwdKoVXoHZbw0dAnXGZ(?t|S zfRfrMFw+I5U!x#G#Ml`@7;wz)=#gXy1q}kzTatjZJfSC6+aJU+y=vn4GtD+{$@yXy zKJnkfW=n#wZyFJi&1)whFwMc~(_QF)(UhbZ)fz1fLaB2Gi!s}Kp%Sw%%f*YvT2o% zBp}T^@H`lMW+6Mg%euFk0DZY-&U-a;cI45rvzgE!WVh`p|L(Tj_+cjj%)XN{>bui0 zo$4%UwZQBLyA%4pu&1-xX#|;m+qI6hz~|1nq932}&1tU0`*|!r&oNuBTldes3F$R! z9L}q~2>53RvPUY{yvj#ls>xYml_jR<EJ(hI#1{ULD*%1>GyRTZ}u$cd&7`@ zXdKkLHdRGme;a}L5`j)D*Ni7|Q;H-CrIi+heZ>iVU*N=RCZ-3C6BoBM7j;4toUmW& z%H&iG)J=WPl6j%vwB5|>mCrNx4nubPJ)~sl9M*JZ#yOGE7sirdlsZ@uR zPRwp_!v6Gpcr*_BBL^Yf)m@haUoK=MJBuJQ;LKE}ZxGBw^R?vlwp=xg2-|`F4OW!o zXt8Ar)1E4*y z6LLGItd&9jY(;trfwtFUB6qEGC=kbNxn%_G(XVAvCQDgRLkM!C6V|Sj>Aj~iCw3pP z6S%X2lOrvUel3$4UvAp<8-a%_X97O+D&%(V2W@D~-N61GCI3$JEoZ_PJR{w}3{6S& zwk-PAkx;4!rdOqc$P%#hyZE`_(PAM%)8^o@YP^kZwOBXmKkhMWoYGNkp7 zICme+K5uj;=7jz%w_dbb;F!Hv-j!_5%Uy;?>F!3~N(h;S7*$q{fQZtwHOk{!y}yI$ zRA;e7uLw*(LaPNYmExGL Date: Fri, 6 Oct 2023 14:27:59 +0100 Subject: [PATCH 013/260] ios 0.14: Add settings page, allow time sync Allow negative/positive actions to pass through to message GUI --- apps/ios/ChangeLog | 2 ++ apps/ios/README.md | 28 ++++++++++++++++++---------- apps/ios/boot.js | 35 ++++++++++++++++++++++++++++++----- apps/ios/metadata.json | 6 ++++-- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/apps/ios/ChangeLog b/apps/ios/ChangeLog index 8ab99b4db..b9558bf21 100644 --- a/apps/ios/ChangeLog +++ b/apps/ios/ChangeLog @@ -11,3 +11,5 @@ 0.11: Added letters with caron to unicodeRemap, to properly display messages in Czech language 0.12: Use new message library 0.13: Making ANCS message receive more resilient (#2402) +0.14: Add settings page, allow time sync + Allow negative/positive actions to pass through to message GUI \ No newline at end of file diff --git a/apps/ios/README.md b/apps/ios/README.md index b4c2c6ac9..056a241d6 100644 --- a/apps/ios/README.md +++ b/apps/ios/README.md @@ -1,27 +1,35 @@ # iOS integration app This is the iOS integration app for Bangle.js. This app allows you to receive -notifications from your iPhone. The Apple Notification Center Service (ANCS) -sends all the messages to your watch. +notifications from your iPhone. The Apple Notification Center Service (ANCS) +sends all the messages to your watch. -You can allow this if you connect your Bangle to your iPhone. It will be -prompted for immediatly after you connect the Bangle to the iPhone. +You can allow this if you connect your Bangle to your iPhone. It will be +prompted for immediatly after you connect the Bangle to the iPhone. -### Connecting your Bangle(2).js to your iPhone -The Bangle watches are Bluetooth Low Energy (BLE) devices. Sometimes they -will not be seen/detected by the Bluetooth scanner in your iPhone settings +### Setting + +Under `Settings -> Apps -> iOS Integration` there is +a `Time Sync` setting. This will enable syncing between the +watch and iOS. + +### Connecting your Bangle.js to your iPhone + +The Bangle watches are Bluetooth Low Energy (BLE) devices. Sometimes they +will not be seen/detected by the Bluetooth scanner in your iPhone settings menu. -To resolve this, you can download numerous apps who can actually scan +To resolve this, you can download an app that can actually scan for BLE devices. There are great ones out there, free and paid. -We really like WebBLE, which we also recommend to load apps on your -watch with your iOS device, as Safari does not support WebBluetooth +We really like WebBLE, which we also recommend to load apps on your +watch with your iOS device, as Safari does not support WebBluetooth for now. It's just a few bucks/pounds/euro's. If you like to try a free app first, you can always use NRF Toolbox or Bluetooth BLE Device Finder to find and connect your Bangle. + ## Requests Please file any issues on https://github.com/espruino/BangleApps/issues/new?title=ios%20app diff --git a/apps/ios/boot.js b/apps/ios/boot.js index 8952a047e..1b38436d8 100644 --- a/apps/ios/boot.js +++ b/apps/ios/boot.js @@ -27,13 +27,11 @@ E.on('ANCS',msg=>{ function ancsHandler() { var msg = Bangle.ancsMessageQueue[0]; NRF.ancsGetNotificationInfo( msg.uid ).then( info => { // success - if(msg.preExisting === true){ info.new = false; } else { info.new = true; } - E.emit("notify", Object.assign(msg, info)); Bangle.ancsMessageQueue.shift(); if (Bangle.ancsMessageQueue.length) @@ -169,7 +167,9 @@ E.on('notify',msg=>{ new : msg.new, title : msg.title&&E.decodeUTF8(msg.title, unicodeRemap, replacer), subject : msg.subtitle&&E.decodeUTF8(msg.subtitle, unicodeRemap, replacer), - body : msg.message&&E.decodeUTF8(msg.message, unicodeRemap, replacer) || "Cannot display" + body : msg.message&&E.decodeUTF8(msg.message, unicodeRemap, replacer) || "Cannot display", + positive : msg.positive, + negative : msg.negative }); // TODO: posaction/negaction? }); @@ -196,7 +196,7 @@ Bangle.musicControl = cmd => { }; // Message response Bangle.messageResponse = (msg,response) => { - if (isFinite(msg.id)) return NRF.sendANCSAction(msg.id, response);//true/false + if (isFinite(msg.id)) return NRF.ancsAction(msg.id, response);//true/false // error/warn here? }; // remove all messages on disconnect @@ -225,6 +225,8 @@ NRF.ancsGetNotificationInfo = function(uid) { }); }; +E.on("notify", n => print("NOTIFY", n)); + E.emit("ANCS", { event:"add", uid:42, @@ -232,9 +234,32 @@ E.emit("ANCS", { categoryCnt:42, silent:true, important:false, - preExisting:true, + preExisting:false, positive:false, negative:true }); + */ + +{ + let settings = require("Storage").readJSON("ios.settings.json",1)||{}; + let ctsUpdate = e=>{ + if (process.env.VERSION=="2v19") + e.date.setMonth(e.date.getMonth()-1); // fix for bug in 2v19 firmware + var tz = 0; + if (e.timezone!==undefined) { + E.setTimeZone(e.timezone); + tz = e.timezone*3600; + var settings = require('Storage').readJSON('setting.json',1)||{}; + settings.timezone = e.timezone; + require('Storage').writeJSON('setting.json',settings); + } + setTime((e.date.getTime()/1000) - tz); + }; + if (settings.timeSync && NRF.ctsGetTime) { + if (NRF.ctsIsActive()) + NRF.ctsGetTime().then(ctsUpdate, function(){ /* */ }) + E.on('CTS',ctsUpdate); + } +} \ No newline at end of file diff --git a/apps/ios/metadata.json b/apps/ios/metadata.json index 42e0060d0..958315655 100644 --- a/apps/ios/metadata.json +++ b/apps/ios/metadata.json @@ -1,7 +1,7 @@ { "id": "ios", "name": "iOS Integration", - "version": "0.13", + "version": "0.14", "description": "Display notifications/music/etc from iOS devices", "icon": "app.png", "tags": "tool,system,ios,apple,messages,notifications", @@ -11,7 +11,9 @@ "storage": [ {"name":"ios.app.js","url":"app.js"}, {"name":"ios.img","url":"app-icon.js","evaluate":true}, - {"name":"ios.boot.js","url":"boot.js"} + {"name":"ios.boot.js","url":"boot.js"}, + {"name":"ios.settings.js","url":"settings.js"} ], + "data": [{"name":"ios.settings.json"}], "sortorder": -8 } From e5493caa9d7380e81cb70a56034ffeb42f2fa4eb Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 6 Oct 2023 14:42:10 +0100 Subject: [PATCH 014/260] Oops - forgot commis --- apps/ios/settings.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 apps/ios/settings.js diff --git a/apps/ios/settings.js b/apps/ios/settings.js new file mode 100644 index 000000000..a90284219 --- /dev/null +++ b/apps/ios/settings.js @@ -0,0 +1,18 @@ +(function(back) { + var settings = require("Storage").readJSON("ios.settings.json",1)||{}; + function updateSettings() { + require("Storage").writeJSON("ios.settings.json", settings); + } + var mainmenu = { + "" : { "title" : "iOS" }, + "< Back" : back, + /*LANG*/"Time Sync" : { + value : !!settings.timeSync, + onchange: v => { + settings.timeSync = v; + updateSettings(); + } + } + }; + E.showMenu(mainmenu); +}) From db75324d00167b54407f832addd223ba2ebf2cc1 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 22 Sep 2023 20:38:11 +0200 Subject: [PATCH 015/260] saclock: add "monochrome" setting for Bangle.js 2 Only for Bangle.js 2, because part of the "simple" is that we draw to a graphics buffer, and B1 doesn't have enough memory for a colour buffer. (Drawing directly would involve sprinkling y-offsets and "redraw background" all over the code; doable, but no longer simple) --- apps/saclock/ChangeLog | 3 ++- apps/saclock/app.js | 21 +++++++++++++++------ apps/saclock/metadata.json | 8 ++++++-- apps/saclock/screenshot.png | Bin 14588 -> 0 bytes apps/saclock/screenshot1.png | Bin 0 -> 2504 bytes apps/saclock/screenshot2.png | Bin 0 -> 2723 bytes apps/saclock/screenshot3.png | Bin 0 -> 2550 bytes apps/saclock/settings.js | 21 +++++++++++++++++---- 8 files changed, 40 insertions(+), 13 deletions(-) delete mode 100644 apps/saclock/screenshot.png create mode 100644 apps/saclock/screenshot1.png create mode 100644 apps/saclock/screenshot2.png create mode 100644 apps/saclock/screenshot3.png diff --git a/apps/saclock/ChangeLog b/apps/saclock/ChangeLog index 88c983c2c..006982ef0 100644 --- a/apps/saclock/ChangeLog +++ b/apps/saclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! -0.02: Hide widgets instead of not loading them at all \ No newline at end of file +0.02: Hide widgets instead of not loading them at all +0.03: Bangle.js 2: add "monochrome" setting diff --git a/apps/saclock/app.js b/apps/saclock/app.js index 3bac66211..40849d1d2 100644 --- a/apps/saclock/app.js +++ b/apps/saclock/app.js @@ -30,11 +30,15 @@ function move(points, x, y) { let clock = new (require("ClockFace"))({ settingsFile: "saclock.settings.json", init: function() { + if (process.env.HWVERSION<2) this.multicol = false; // colored buffer won't fit in Bangle.js 1 memory :-( // create a graphics buffer, and pre-draw the outer ring const bs = Math.min(Bangle.appRect.w, Bangle.appRect.h); // buffer size - this.r = Math.min(Bangle.appRect.w, Bangle.appRect.h)/2; // outer radius - this.buffer = Graphics.createArrayBuffer(bs, bs, 1, {msb: true}); + this.r = Math.min(Bangle.appRect.w, Bangle.appRect.h)/2 - 1; // outer radius + this.bits = this.multicol ? 16 : 1; + this.buffer = Graphics.createArrayBuffer(bs, bs, this.bits, {msb: true}); let buf = this.buffer; + buf.setColor(g.theme.bg).fillRect(0,0, bs,bs); + buf.setColor(this.multicol ? g.theme.bgH : g.theme.fg); buf.fillCircle(this.r, this.r, this.r); // only fill this once: we only draw inside the inner ring }, update: function(time) { @@ -48,8 +52,8 @@ let clock = new (require("ClockFace"))({ hr = ((time.getHours()%12)+(time.getMinutes()/60))/12*Math.TAU, // hour hand rotation ml = 0.8*r2, // minute hand length mr = time.getMinutes()/60*Math.TAU, // minute hand rotation - x = Math.floor((Bangle.appRect.x+Bangle.appRect.x2)/2), // "real" clock center, only - y = Math.floor((Bangle.appRect.y+Bangle.appRect.y2)/2); // used for drawing buffer + x = Math.ceil((Bangle.appRect.x+Bangle.appRect.x2)/2), // "real" clock center, only + y = Math.ceil((Bangle.appRect.y+Bangle.appRect.y2)/2); // used for drawing buffer let buf = this.buffer; function drawHand(length, radians) { @@ -67,13 +71,18 @@ let clock = new (require("ClockFace"))({ } buf.setColor(g.theme.bg).fillCircle(c, c, r2); // clear inside - buf.setColor(g.theme.fg); + buf.setColor(this.multicol ? g.theme.fg2 : g.theme.fg); drawHand(hl, hr); // hour hand + buf.setColor(g.theme.fg); drawHand(ml, mr); // minute hand buf.fillCircle(c, c, Math.floor(hw)); // hands joiner + if (!this.multicol && !g.theme.dark) { + // apparently 1-bit g.drawImage swaps fg/bg colors for light themes? + g.setColor(g.theme.bg).setBgColor(g.theme.fg); + } g.drawImage({ width: buf.getWidth(), height: buf.getHeight(), - buffer: buf.buffer + buffer: buf.buffer, bpp: this.bits, }, x, y, {rotate: 0}); // setting `rotate` centers the image on x,y }, }); diff --git a/apps/saclock/metadata.json b/apps/saclock/metadata.json index 6ad55b0fe..bf0d99493 100644 --- a/apps/saclock/metadata.json +++ b/apps/saclock/metadata.json @@ -1,9 +1,13 @@ { "id": "saclock", "name": "Simple analog clock", "shortName":"Analog clock", - "version":"0.02", + "version":"0.03", "description": "A very basic analog clock", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [ + {"url":"screenshot1.png"}, + {"url":"screenshot2.png"}, + {"url":"screenshot3.png"} + ], "icon": "icon.png", "type": "clock", "tags": "clock,analog", diff --git a/apps/saclock/screenshot.png b/apps/saclock/screenshot.png deleted file mode 100644 index 595b032dd688bf69f249371a779f3f13dd298dff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14588 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 diff --git a/apps/saclock/screenshot1.png b/apps/saclock/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..c5a539d6e2c2b4cbc9d216393baa958a9fa80520 GIT binary patch literal 2504 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 literal 0 HcmV?d00001 diff --git a/apps/saclock/screenshot3.png b/apps/saclock/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..6bf9a6e2a65c836c22945cffa69f28676481d17a GIT binary patch literal 2550 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 M07*qoM6N<$f*xAK3;+NC literal 0 HcmV?d00001 diff --git a/apps/saclock/settings.js b/apps/saclock/settings.js index 30ea95321..fc50d04dc 100644 --- a/apps/saclock/settings.js +++ b/apps/saclock/settings.js @@ -1,10 +1,23 @@ (function(back) { + let settings = require("Storage").readJSON("saclock.settings.json", true)||{}; + function save(key, value) { + settings[key] = value; + require("Storage").writeJSON("saclock.settings.json", settings); + } + let menu = { "": {"title": /*LANG*/"Analog Clock"}, - /*LANG*/"< Back": back, + /*LANG*/"< Back": back }; - require("ClockFace_menu").addSettingsFile(menu, "saclock.settings.json", [ - "hideWidgets" - ]); + if (process.env.HWVERSION>1) { // Bangle.js 1 memory won't fit a coloured graphics buffer + menu[/*LANG*/"Monochrome"] = { + // saved as "multicol" so the default is monochrome (as in previous version) + value: !settings.multicol, + onchange: v => save("multicol", !v), + } + } + require("ClockFace_menu").addItems(menu, save, { + hideWidgets: settings.hideWidgets, + }); E.showMenu(menu); }); From 844b01c54dcbd29d0ddca65f1a94346ab9dc47b3 Mon Sep 17 00:00:00 2001 From: g-rden <94605617+g-rden@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:37:00 +0000 Subject: [PATCH 016/260] Bugs fixed and simplified Fixed bug in function drawClock: displayed time jumps from 11:50 to 12:59 to 12:07 Fixed bug in function drawClock: skipping 23 o'clock Simplified various parts & removed unreachable checks --- apps/sunrise/app.js | 45 +++++++++++---------------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/apps/sunrise/app.js b/apps/sunrise/app.js index 3feb4dfd4..e1f4c76b5 100644 --- a/apps/sunrise/app.js +++ b/apps/sunrise/app.js @@ -162,7 +162,6 @@ Math.mod = function (a, b) { return result; }; -const delta = 2; const sunrise = new Date().sunrise(lat, lon); const sr = sunrise.getHours() + ':' + sunrise.getMinutes(); console.log('sunrise', sunrise); @@ -176,25 +175,18 @@ const oy = h / 1.7; let sunRiseX = 0; let sunSetX = 0; -const sinStep = 12; +const sinStep = 13; function drawSinuses () { let x = 0; - g.setColor(0, 0, 0); - // g.fillRect(0,oy,w, h); g.setColor(1, 1, 1); - let y = oy; - for (i = 0; i < w; i++) { - x = i; - x2 = x + sinStep + 1; - y2 = ypos(i); - if (x == 0) { - y = y2; - } - g.drawLine(x, y, x2, y2); + let y = ypos(x); + while (x < w) { + y2 = ypos(x); + g.drawLine(x, y, x + sinStep, y2); y = y2; - i += sinStep; // no need to draw all steps + x += sinStep; // no need to draw all steps } // sea level line @@ -206,7 +198,6 @@ function drawSinuses () { sunSetX = xfromTime(hh1) + (r / 2); g.setColor(0, 0.5, 1); g.drawLine(0, sl0, w, sl1); - g.setColor(0, 0.5, 1); g.drawLine(0, sl0 + 1, w, sl1 + 1); /* g.setColor(0, 0, 1); @@ -295,27 +286,19 @@ function drawClock () { } else { ypos = 32; fhours = 24 * (pos / w); - if (fhours > 23) { - fhours = 0; - } const nexth = 24 * 60 * (pos / w); fmins = 59 - ((24 * 60) - nexth) % 60; - if (fmins < 0) { - fmins = 0; + + // this prevents the displayed time to jump from 11:50 to 12:59 to 12:07 + if (fmins == 59) { + fhours--; } } - if (fmins > 59) { - fmins = 59; - } const hours = ((fhours < 10) ? '0' : '') + (0 | fhours); const mins = ((fmins < 10) ? '0' : '') + (0 | fmins); curTime = hours + ':' + mins; g.setFont('Vector', 30); - if (realTime) { - g.setColor(1, 1, 1); - } else { - g.setColor(0, 1, 1); - } + g.setColor(realTime, 1, 1); g.drawString(curTime, w / 1.9, ypos); // day-month if (realTime) { @@ -361,8 +344,6 @@ Bangle.on('lock', () => { renderScreen(); -realPos = xfromTime((new Date()).getHours()); - function initialAnimationFrame () { let distance = (realPos - curPos) / 4; if (distance > 20) { @@ -371,10 +352,6 @@ function initialAnimationFrame () { curPos += distance; pos = curPos; renderScreen(); - if (curPos >= realPos) { - frame = 0; - } - frames--; if (frames-- > 0) { setTimeout(initialAnimationFrame, 50); } else { From d64ed09c537c30918536a4db119bff76aee7be11 Mon Sep 17 00:00:00 2001 From: g-rden <94605617+g-rden@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:47:11 +0000 Subject: [PATCH 017/260] Update to 0.05 --- apps/sunrise/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sunrise/metadata.json b/apps/sunrise/metadata.json index 051ff99bd..8b263e16c 100644 --- a/apps/sunrise/metadata.json +++ b/apps/sunrise/metadata.json @@ -2,7 +2,7 @@ "id": "sunrise", "name": "Sunrise", "shortName": "Sunrise", - "version": "0.04", + "version": "0.05", "type": "clock", "description": "Show sunrise and sunset times", "icon": "app.png", From 2993d391d572523629a80571409dfde32b4b4ea8 Mon Sep 17 00:00:00 2001 From: g-rden <94605617+g-rden@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:54:49 +0000 Subject: [PATCH 018/260] Updated to 0.05 --- apps/sunrise/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/sunrise/ChangeLog b/apps/sunrise/ChangeLog index 490992812..1f1c7e8df 100644 --- a/apps/sunrise/ChangeLog +++ b/apps/sunrise/ChangeLog @@ -2,3 +2,4 @@ 0.02: Faster sinus line and fix button to open menu 0.03: Show day/month, add animations, fix !mylocation and text glitch 0.04: Always show the widgets, swifter animations and lighter sea line +0.05: Fixed hours increasing too early, added missing 23 o'clock, simplified code From f09532d6f7722353b3528030b2d65a32fa4d8e62 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sat, 7 Oct 2023 22:28:13 +0200 Subject: [PATCH 019/260] Split functions in preparation. --- apps/tetris/tetris.app.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/tetris/tetris.app.js b/apps/tetris/tetris.app.js index e24a731a9..a84873e36 100644 --- a/apps/tetris/tetris.app.js +++ b/apps/tetris/tetris.app.js @@ -143,24 +143,32 @@ function gameStep() { } } -Bangle.setUI(); -Bangle.on("touch", (e) => { +function rotate() { t = rotateTile(ct, 3); if (moveOk(t, 0, 0)) { drawTile(ct, ctn, ox+px*8, oy+py*8, true); ct = t; drawTile(ct, ctn, ox+px*8, oy+py*8, false); } -}); +} -Bangle.on("swipe", (x,y) => { - if (y<0) y = 0; +function move(x, y) { if (moveOk(ct, x, y)) { drawTile(ct, ctn, ox+px*8, oy+py*8, true); px += x; py += y; drawTile(ct, ctn, ox+px*8, oy+py*8, false); } +} + +Bangle.setUI(); +Bangle.on("touch", (e) => { + rotate(); +}); + +Bangle.on("swipe", (x,y) => { + if (y<0) y = 0; + move(x, y); }); drawBoundingBox(); From 7a0c3f2bd975eff97eb0f30456601ce4c114d574 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sat, 7 Oct 2023 23:05:05 +0200 Subject: [PATCH 020/260] Implement controls by clicking, implement game over. --- apps/tetris/tetris.app.js | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/tetris/tetris.app.js b/apps/tetris/tetris.app.js index a84873e36..255437b62 100644 --- a/apps/tetris/tetris.app.js +++ b/apps/tetris/tetris.app.js @@ -95,6 +95,11 @@ function redrawPF(ly) { } } +function gameOver() { + g.setColor(1, 1, 1).setFontAlign(0, 1, 0).setFont("Vector",22) + .drawString("Game Over", 176/2, 76); +} + function insertAndCheck() { for (y=0; y { - rotate(); +Bangle.on("drag", (e) => { + let h = 176/2; + if (!e.b) + return; + if (e.y < h) { + if (e.x < h) + rotate(); + else + move(0, 1); + } else { + if (e.x < h) + move(-1, 0); + else + move(1, 0); + } }); Bangle.on("swipe", (x,y) => { From 5a546819540d1a1a9ca9ddc0ba239e13370ddc84 Mon Sep 17 00:00:00 2001 From: g-rden <94605617+g-rden@users.noreply.github.com> Date: Sat, 7 Oct 2023 22:30:37 +0000 Subject: [PATCH 021/260] sine line fix & simplification Corrected first sine line section. Removed radius offset from sine line x values. & Simplified --- apps/sunrise/app.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/sunrise/app.js b/apps/sunrise/app.js index e1f4c76b5..13f77fe00 100644 --- a/apps/sunrise/app.js +++ b/apps/sunrise/app.js @@ -183,7 +183,7 @@ function drawSinuses () { g.setColor(1, 1, 1); let y = ypos(x); while (x < w) { - y2 = ypos(x); + y2 = ypos(x + sinStep); g.drawLine(x, y, x + sinStep, y2); y = y2; x += sinStep; // no need to draw all steps @@ -225,7 +225,7 @@ function drawGlow () { } const rh = r / 2; const x = pos; - const y = ypos(x - r); + const y = ypos(x); const r2 = 0; if (x > sunRiseX && x < sunSetX) { g.setColor(0.2, 0.2, 0); @@ -246,8 +246,7 @@ function seaLevel (hour) { } function ypos (x) { - const pc = (x * 100 / w); - return oy + (32 * Math.sin(1.7 + (pc / 16))); + return oy + (32 * Math.sin(1.7 + (x * 100 / (16 * w)))); } function xfromTime (t) { @@ -260,7 +259,7 @@ function drawBall () { if (frames < 1 && realTime) { x = xfromTime(now.getHours()); } - const y = ypos(x - r); + const y = ypos(x); // glow if (x < sunRiseX || x > sunSetX) { From 87afbe89388a4bb9051e5dba1dd7bf65eb7a4954 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sun, 8 Oct 2023 12:00:00 +0200 Subject: [PATCH 022/260] Update metadata/changelogs. --- apps/tetris/ChangeLog | 2 ++ apps/tetris/README.md | 4 ++-- apps/tetris/metadata.json | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 apps/tetris/ChangeLog diff --git a/apps/tetris/ChangeLog b/apps/tetris/ChangeLog new file mode 100644 index 000000000..6366af6c0 --- /dev/null +++ b/apps/tetris/ChangeLog @@ -0,0 +1,2 @@ +0.01: New app! +0.02: Better controls, implement game over. diff --git a/apps/tetris/README.md b/apps/tetris/README.md index 2c41657f4..611c5c25c 100644 --- a/apps/tetris/README.md +++ b/apps/tetris/README.md @@ -4,5 +4,5 @@ Bangle version of the classic game of Tetris. ## Controls -Tapping the screen rotates the pieces once, swiping left, right or down moves the -piece in that direction, if possible. \ No newline at end of file +Tap top part of screen to rotate and move down, tap bottom part to +move left/right. \ No newline at end of file diff --git a/apps/tetris/metadata.json b/apps/tetris/metadata.json index f683a5be7..790874648 100644 --- a/apps/tetris/metadata.json +++ b/apps/tetris/metadata.json @@ -6,7 +6,9 @@ "icon": "tetris.png", "readme": "README.md", "tags": "game", - "supports" : ["BANGLEJS2"], + "supports" : ["BANGLEJS2"], + "allow_emulator": true, + "readme": "README.md", "storage": [ {"name":"tetris.app.js","url":"tetris.app.js"}, {"name":"tetris.img","url":"app-icon.js","evaluate":true} From ade2df3f0fc6990a76727fc3e750f3daadd1c5a0 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sun, 8 Oct 2023 12:05:30 +0200 Subject: [PATCH 023/260] Implement move down with one click. --- apps/tetris/tetris.app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/tetris/tetris.app.js b/apps/tetris/tetris.app.js index 255437b62..77c40de9a 100644 --- a/apps/tetris/tetris.app.js +++ b/apps/tetris/tetris.app.js @@ -177,8 +177,13 @@ Bangle.on("drag", (e) => { if (e.y < h) { if (e.x < h) rotate(); - else - move(0, 1); + else { + let i = 0; + for (i=0; i<10; i++) { + move(0, 1); + g.flip(); + } + } } else { if (e.x < h) move(-1, 0); From a9cfd8946651b0c4968b613440177ffd69e1d6b5 Mon Sep 17 00:00:00 2001 From: g-rden <94605617+g-rden@users.noreply.github.com> Date: Sun, 8 Oct 2023 10:09:06 +0000 Subject: [PATCH 024/260] Bug fixes Increased sun position resolution. Fixed various wrong offsets. Fixed sun positions for sun rise & set. Fixed sine line not drawing until the right screen edge. Simplified --- apps/sunrise/app.js | 78 ++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/apps/sunrise/app.js b/apps/sunrise/app.js index 13f77fe00..f58fc5d8f 100644 --- a/apps/sunrise/app.js +++ b/apps/sunrise/app.js @@ -182,20 +182,20 @@ function drawSinuses () { g.setColor(1, 1, 1); let y = ypos(x); - while (x < w) { + // until drawn line touches right side of the screen + while ((x - sinStep / 2) < w) { y2 = ypos(x + sinStep); - g.drawLine(x, y, x + sinStep, y2); + // both x are offset by -sinStep/2 + g.drawLine(x - sinStep / 2, y, x + sinStep / 2, y2); y = y2; x += sinStep; // no need to draw all steps } // sea level line - const hh0 = sunrise.getHours(); - const hh1 = sunset.getHours(); - const sl0 = seaLevel(hh0); - const sl1 = seaLevel(hh1); - sunRiseX = xfromTime(hh0) + (r / 2); - sunSetX = xfromTime(hh1) + (r / 2); + const sl0 = seaLevel(sunrise.getHours()); + const sl1 = seaLevel(sunset.getHours()); + sunRiseX = xfromTime(sunrise.getHours() + sunrise.getMinutes() / 60); + sunSetX = xfromTime(sunset.getHours() + sunset.getMinutes() / 60); g.setColor(0, 0.5, 1); g.drawLine(0, sl0, w, sl1); g.drawLine(0, sl0 + 1, w, sl1 + 1); @@ -221,19 +221,16 @@ const r = 10; function drawGlow () { const now = new Date(); if (frames < 1 && realTime) { - pos = xfromTime(now.getHours()); + pos = xfromTime(now.getHours() + now.getMinutes() / 60); } - const rh = r / 2; const x = pos; - const y = ypos(x); - const r2 = 0; + const y = ypos(x + sinStep / 2); + + g.setColor(0.2, 0.2, 0); + // wide glow if (x > sunRiseX && x < sunSetX) { - g.setColor(0.2, 0.2, 0); g.fillCircle(x, y, r + 20); g.setColor(0.5, 0.5, 0); - // wide glow - } else { - g.setColor(0.2, 0.2, 0); } // smol glow g.fillCircle(x, y, r + 8); @@ -254,20 +251,18 @@ function xfromTime (t) { } function drawBall () { - let x = pos; const now = new Date(); if (frames < 1 && realTime) { - x = xfromTime(now.getHours()); + pos = xfromTime(now.getHours() + now.getMinutes() / 60); } - const y = ypos(x); - + const x = pos; + const y = ypos(x + sinStep / 2); // glow - if (x < sunRiseX || x > sunSetX) { - g.setColor(0.5, 0.5, 0); - } else { + if (x > sunRiseX && x < sunSetX) { g.setColor(1, 1, 1); + } else { + g.setColor(0.5, 0.5, 0); } - const rh = r / 2; g.fillCircle(x, y, r); g.setColor(1, 1, 0); g.drawCircle(x, y, r); @@ -275,44 +270,41 @@ function drawBall () { function drawClock () { const now = new Date(); - let curTime = ''; - let fhours = 0.0; - let fmins = 0.0; - let ypos = 32; + let hours = 0.0; + let mins = 0.0; if (realTime) { - fhours = now.getHours(); - fmins = now.getMinutes(); + hours = now.getHours(); + mins = now.getMinutes(); } else { - ypos = 32; - fhours = 24 * (pos / w); + hours = 24 * (pos / w); const nexth = 24 * 60 * (pos / w); - fmins = 59 - ((24 * 60) - nexth) % 60; + mins = 59 - ((24 * 60) - nexth) % 60; // this prevents the displayed time to jump from 11:50 to 12:59 to 12:07 - if (fmins == 59) { - fhours--; + if (mins == 59) { + hours--; } } - const hours = ((fhours < 10) ? '0' : '') + (0 | fhours); - const mins = ((fmins < 10) ? '0' : '') + (0 | fmins); - curTime = hours + ':' + mins; + + hours = ((hours < 10) ? '0' : '') + (0 | hours); + mins = ((mins < 10) ? '0' : '') + (0 | mins); g.setFont('Vector', 30); g.setColor(realTime, 1, 1); - g.drawString(curTime, w / 1.9, ypos); + g.drawString('' + hours + ':' + mins, w / 1.9, 32); // day-month if (realTime) { const mo = now.getMonth() + 1; const da = now.getDate(); - const daymonth = '' + da + '/' + mo; g.setFont('6x8', 2); - g.drawString(daymonth, 5, 30); + g.drawString('' + da + '/' + mo, 5, 30); } } function renderScreen () { + const now = new Date(); g.setColor(0, 0, 0); g.fillRect(0, 30, w, h); - realPos = xfromTime((new Date()).getHours()); + realPos = xfromTime(now.getHours() + now.getMinutes() / 60); g.setFontAlign(-1, -1, 0); Bangle.drawWidgets(); @@ -329,7 +321,7 @@ Bangle.on('drag', function (tap, top) { curPos = pos; initialAnimation(); } else { - pos = tap.x - 5; + pos = tap.x; realTime = false; } renderScreen(); From 2dbde15cc4d8c0f1da8f12eb96dca9c9f2ac45be Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sun, 8 Oct 2023 12:10:31 +0200 Subject: [PATCH 025/260] Update version to 0.02 --- apps/tetris/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tetris/metadata.json b/apps/tetris/metadata.json index 790874648..f10c06c54 100644 --- a/apps/tetris/metadata.json +++ b/apps/tetris/metadata.json @@ -1,7 +1,7 @@ { "id": "tetris", "name": "Tetris", "shortName":"Tetris", - "version":"0.01", + "version":"0.02", "description": "Tetris", "icon": "tetris.png", "readme": "README.md", From 27ed85d6770e5768030515d4378273f6ce8cf590 Mon Sep 17 00:00:00 2001 From: g-rden <94605617+g-rden@users.noreply.github.com> Date: Sun, 8 Oct 2023 10:53:27 +0000 Subject: [PATCH 026/260] Fix sine and sun pos offset --- apps/sunrise/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/sunrise/app.js b/apps/sunrise/app.js index f58fc5d8f..ce6fc3a1b 100644 --- a/apps/sunrise/app.js +++ b/apps/sunrise/app.js @@ -182,11 +182,10 @@ function drawSinuses () { g.setColor(1, 1, 1); let y = ypos(x); - // until drawn line touches right side of the screen - while ((x - sinStep / 2) < w) { + while (x < w) { y2 = ypos(x + sinStep); // both x are offset by -sinStep/2 - g.drawLine(x - sinStep / 2, y, x + sinStep / 2, y2); + g.drawLine(x, y, x + sinStep, y2); y = y2; x += sinStep; // no need to draw all steps } @@ -224,7 +223,7 @@ function drawGlow () { pos = xfromTime(now.getHours() + now.getMinutes() / 60); } const x = pos; - const y = ypos(x + sinStep / 2); + const y = ypos(x); g.setColor(0.2, 0.2, 0); // wide glow @@ -256,7 +255,8 @@ function drawBall () { pos = xfromTime(now.getHours() + now.getMinutes() / 60); } const x = pos; - const y = ypos(x + sinStep / 2); + const y = ypos(x); + // glow if (x > sunRiseX && x < sunSetX) { g.setColor(1, 1, 1); From d34da4356e5466a565efb40ede4ee14e4ba7bfc1 Mon Sep 17 00:00:00 2001 From: g-rden <94605617+g-rden@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:24:54 +0000 Subject: [PATCH 027/260] Fixed zenith position, time formatting & misc Offset ypos function. Use float in sine function instead of fraction to represent 2*pi. Added function to format time, which makes times draw correct. Moved global variables. Made animations more consistent --- apps/sunrise/app.js | 62 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/apps/sunrise/app.js b/apps/sunrise/app.js index ce6fc3a1b..4c52020bb 100644 --- a/apps/sunrise/app.js +++ b/apps/sunrise/app.js @@ -14,9 +14,6 @@ function loadLocation () { return { lat: 41.38, lon: 2.168 }; } } -let frames = 0; // amount of pending frames to render (0 if none) -let curPos = 0; // x position of the sun -let realPos = 0; // x position of the sun depending on currentime const latlon = loadLocation() || {}; const lat = latlon.lat || 41.38; const lon = latlon.lon || 2.168; @@ -163,11 +160,7 @@ Math.mod = function (a, b) { }; const sunrise = new Date().sunrise(lat, lon); -const sr = sunrise.getHours() + ':' + sunrise.getMinutes(); -console.log('sunrise', sunrise); const sunset = new Date().sunset(lat, lon); -const ss = sunset.getHours() + ':' + sunset.getMinutes(); -console.log('sunset', sunset); const w = g.getWidth(); const h = g.getHeight(); @@ -177,6 +170,21 @@ let sunRiseX = 0; let sunSetX = 0; const sinStep = 13; +let pos = 0; +let realTime = true; +const r = 10; + +let frames = 0; // amount of pending frames to render (0 if none) +// set to 1 because pos 0 is displayed as 0-1:59 +let curPos = 1; // x position of the sun +let realPos = 0; // x position of the sun depending on currentime + + +function formatAsTime (hour, minute) { + return '' + ((hour < 10) ? '0' : '') + (0 | hour) + + ':' + ((minute < 10) ? '0' : '') + (0 | minute); +} + function drawSinuses () { let x = 0; @@ -184,7 +192,6 @@ function drawSinuses () { let y = ypos(x); while (x < w) { y2 = ypos(x + sinStep); - // both x are offset by -sinStep/2 g.drawLine(x, y, x + sinStep, y2); y = y2; x += sinStep; // no need to draw all steps @@ -209,14 +216,10 @@ function drawSinuses () { function drawTimes () { g.setColor(1, 1, 1); g.setFont('6x8', 2); - g.drawString(sr, 10, h - 20); - g.drawString(ss, w - 60, h - 20); + g.drawString(formatAsTime(sunrise.getHours(), sunrise.getMinutes()), 10, h - 20); + g.drawString(formatAsTime(sunset.getHours(), sunset.getMinutes()), w - 60, h - 20); } -let pos = 0; -let realTime = true; -const r = 10; - function drawGlow () { const now = new Date(); if (frames < 1 && realTime) { @@ -242,7 +245,8 @@ function seaLevel (hour) { } function ypos (x) { - return oy + (32 * Math.sin(1.7 + (x * 100 / (16 * w)))); + // offset, resulting in zenith being at the correct time + return oy + (32 * Math.sin(((x + sunRiseX - 12) / w) * 6.28 )); } function xfromTime (t) { @@ -286,11 +290,9 @@ function drawClock () { } } - hours = ((hours < 10) ? '0' : '') + (0 | hours); - mins = ((mins < 10) ? '0' : '') + (0 | mins); g.setFont('Vector', 30); g.setColor(realTime, 1, 1); - g.drawString('' + hours + ':' + mins, w / 1.9, 32); + g.drawString(formatAsTime(hours, mins), w / 1.9, 32); // day-month if (realTime) { const mo = now.getMonth() + 1; @@ -333,17 +335,13 @@ Bangle.on('lock', () => { renderScreen(); }); -renderScreen(); - function initialAnimationFrame () { - let distance = (realPos - curPos) / 4; - if (distance > 20) { - distance = 20; - } - curPos += distance; - pos = curPos; - renderScreen(); - if (frames-- > 0) { + if (frames > 0) { + let distance = (realPos - curPos) / frames; + pos = curPos; + curPos += distance; + renderScreen(); + frames--; setTimeout(initialAnimationFrame, 50); } else { realTime = true; @@ -352,17 +350,21 @@ function initialAnimationFrame () { } function initialAnimation () { + const now = new Date(); + realPos = xfromTime(now.getHours() + now.getMinutes() / 60); const distance = Math.abs(realPos - pos); - frames = distance / 4; + frames = distance / 16; realTime = false; initialAnimationFrame(); } function main () { + sunRiseX = xfromTime(sunrise.getHours() + sunrise.getMinutes() / 60); + sunSetX = xfromTime(sunset.getHours() + sunset.getMinutes() / 60); + g.setBgColor(0, 0, 0); g.clear(); setInterval(renderScreen, 60 * 1000); - pos = 0; initialAnimation(); } From 8a4a2cee5a1ab2b7b195783b9bab15368490211c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Oct 2023 12:50:06 +0100 Subject: [PATCH 028/260] recorder/openstmap 0.31: Ensure that background-drawn tracks can get cancelled, and draw less at a time to make updates smoother plotTrack now draws the current track even if you're not actively recording --- apps/openstmap/ChangeLog | 3 ++- apps/openstmap/app.js | 4 ++++ apps/openstmap/metadata.json | 2 +- apps/recorder/ChangeLog | 2 ++ apps/recorder/metadata.json | 2 +- apps/recorder/widget.js | 6 +++--- 6 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openstmap/ChangeLog b/apps/openstmap/ChangeLog index 32951bda7..10b29fd3b 100644 --- a/apps/openstmap/ChangeLog +++ b/apps/openstmap/ChangeLog @@ -29,4 +29,5 @@ 0.22: Replace position marker with direction arrow 0.23: Bugfix: Enable Compass if needed 0.24: Allow zooming by clicking the screen -0.25: Enable scaled image filtering on 2v19+ firmware \ No newline at end of file +0.25: Enable scaled image filtering on 2v19+ firmware +0.26: Ensure that when redrawing, we always cancel any in-progress track draw \ No newline at end of file diff --git a/apps/openstmap/app.js b/apps/openstmap/app.js index 9b53077ab..1f4b0b8b7 100644 --- a/apps/openstmap/app.js +++ b/apps/openstmap/app.js @@ -30,6 +30,10 @@ if (settings.dirSrc === undefined) { // Redraw the whole page function redraw() { + // ensure we do cancel track drawing + if (plotTrack && plotTrack.stop) + plotTrack.stop(); + // set clip rect so we don't overwrite widgets g.setClipRect(R.x,R.y,R.x2,R.y2); const count = m.draw(); if (checkMapPos && count === 0) { diff --git a/apps/openstmap/metadata.json b/apps/openstmap/metadata.json index 05dcf2709..29278cbc3 100644 --- a/apps/openstmap/metadata.json +++ b/apps/openstmap/metadata.json @@ -2,7 +2,7 @@ "id": "openstmap", "name": "OpenStreetMap", "shortName": "OpenStMap", - "version": "0.25", + "version": "0.26", "description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps", "readme": "README.md", "icon": "app.png", diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 5f4d1f8b4..9e78bc7a2 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -36,3 +36,5 @@ 0.28: Automatically create new track if the filename is different 0.29: When plotting with OpenStMap scale map to track width & height 0.30: Add clock info for showing and toggling recording state +0.31: Ensure that background-drawn tracks can get cancelled, and draw less at a time to make updates smoother + plotTrack now draws the current track even if you're not actively recording \ No newline at end of file diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 15ba165d1..b47fb9ded 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.30", + "version": "0.31", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget,clkinfo", diff --git a/apps/recorder/widget.js b/apps/recorder/widget.js index e34fecfbc..2525a96e4 100644 --- a/apps/recorder/widget.js +++ b/apps/recorder/widget.js @@ -288,8 +288,8 @@ } */ options = options||{}; - if (!activeRecorders.length) return; // not recording var settings = loadSettings(); + if (!settings.file) return; // no file specified // keep function to draw track in RAM function plot(g) { "ram"; var f = require("Storage").open(settings.file,"r"); @@ -311,7 +311,7 @@ mp = m.latLonToXY(+c[la], +c[lo]); g.moveTo(mp.x,mp.y).setColor(color); l = f.readLine(f); - var n = options.async ? 20 : 200; // only plot first 200 points to keep things fast(ish) + var n = options.async ? 10 : 200; // only plot first 200 points to keep things fast(ish) while(l && n--) { c = l.split(","); if (c[la]) { @@ -333,7 +333,7 @@ } }; } - plot(g); + return plot(g); }}; // load settings, set correct widget width reload(); From 70b89fbe2f320c7e78dff492727e35dc59c42811 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 10 Oct 2023 10:50:07 +0100 Subject: [PATCH 029/260] backswipe: ignore `undefined` handlers `undefined` handlers are created when we [remove listeners] part-way through the array. This fixes `backswipe` for all firmwares, but leaves the door open for a potential firmware change. [remove listeners]: https://github.com/bobrippling/Espruino/blob/0f16231a4369bb2d154b9fab5a0d806122cddb39/src/jswrap_object.c#L1035-L1035 --- apps/backswipe/ChangeLog | 1 + apps/backswipe/boot.js | 2 +- apps/backswipe/metadata.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/backswipe/ChangeLog b/apps/backswipe/ChangeLog index 1e5479d6e..54ffebfc7 100644 --- a/apps/backswipe/ChangeLog +++ b/apps/backswipe/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Don't fire if the app uses swipes already. +0.03: Only count defined handlers in the handler array. diff --git a/apps/backswipe/boot.js b/apps/backswipe/boot.js index e46f902eb..d5d54cd59 100644 --- a/apps/backswipe/boot.js +++ b/apps/backswipe/boot.js @@ -26,7 +26,7 @@ if (Bangle["#on"+eventType] === undefined) { return 0; } else if (Bangle["#on"+eventType] instanceof Array) { - return Bangle["#on"+eventType].length; + return Bangle["#on"+eventType].filter(x=>x).length; } else if (Bangle["#on"+eventType] !== undefined) { return 1; } diff --git a/apps/backswipe/metadata.json b/apps/backswipe/metadata.json index c7cb2185f..add609a0f 100644 --- a/apps/backswipe/metadata.json +++ b/apps/backswipe/metadata.json @@ -1,7 +1,7 @@ { "id": "backswipe", "name": "Back Swipe", "shortName":"BackSwipe", - "version":"0.02", + "version":"0.03", "description": "Service that allows you to use an app's back button using left to right swipe gesture", "icon": "app.png", "tags": "back,gesture,swipe", From 213ac33faae04b2f45bdbf6d7a2cd4a8d11693df Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 10 Oct 2023 11:26:10 +0100 Subject: [PATCH 030/260] 0.64: Default to wakeOnTwist being off --- apps/setting/ChangeLog | 3 ++- apps/setting/metadata.json | 2 +- apps/setting/settings.js | 2 +- apps/setting/settings.min.json | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index dbeea10ca..4f4196e32 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -70,4 +70,5 @@ of 'Select Clock' 0.61: Permit temporary bypass of the BLE whitelist 0.62: Fix whitelist showing as 'on' by default when it's not after 0.59 0.63: Whitelist: Try to resolve peer addresses using NRF.resolveAddress() - for 2v19 or 2v18 cutting edge builds - Remove 'beta' label from passkey - it's been around for a while and works ok \ No newline at end of file + Remove 'beta' label from passkey - it's been around for a while and works ok +0.64: Default to wakeOnTwist being off \ No newline at end of file diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index c94abdd82..07376468a 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -1,7 +1,7 @@ { "id": "setting", "name": "Settings", - "version": "0.63", + "version": "0.64", "description": "A menu for setting up Bangle.js", "icon": "settings.png", "tags": "tool,system", diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 3c4115a2f..d19bb14d7 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -50,7 +50,7 @@ function resetSettings() { wakeOnBTN3: true, wakeOnFaceUp: false, wakeOnTouch: false, - wakeOnTwist: true, + wakeOnTwist: false, twistThreshold: 819.2, twistMaxY: -800, twistTimeout: 1000 diff --git a/apps/setting/settings.min.json b/apps/setting/settings.min.json index 984054c11..42d2babc4 100644 --- a/apps/setting/settings.min.json +++ b/apps/setting/settings.min.json @@ -1 +1 @@ -{"ble":true,"blerepl":true,"log":false,"timeout":10,"vibrate":true,"beep":"vib","timezone":0,"HID":false,"clock":null,"12hour":false,"brightness":1,"options":{"wakeOnBTN1":true,"wakeOnBTN2":true,"wakeOnBTN3":true,"wakeOnFaceUp":false,"wakeOnTouch":false,"wakeOnTwist":true,"twistThreshold":819.2,"twistMaxY":-800,"twistTimeout":1000}} \ No newline at end of file +{"ble":true,"blerepl":true,"log":false,"timeout":10,"vibrate":true,"beep":"vib","timezone":0,"HID":false,"clock":null,"12hour":false,"brightness":1,"options":{"wakeOnBTN1":true,"wakeOnBTN2":true,"wakeOnBTN3":true,"wakeOnFaceUp":false,"wakeOnTouch":false,"wakeOnTwist":false,"twistThreshold":819.2,"twistMaxY":-800,"twistTimeout":1000}} \ No newline at end of file From b58ab4bb26c6b0e01054bb9f25706028b0b646e0 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Wed, 11 Oct 2023 19:26:20 +0100 Subject: [PATCH 031/260] Update app.js Updated to work with new API. Additional capability includes: 1. Now also records upto 2 hours - if you cancel at any time the CSV file will still be there, the timer you set at the start is more so that you get an alert when it's complete. 2. Along with raw PPG readings, it also records bandpassed filtered data in a second column, available in the new API. 3. Rather than overwriting 1 data file, the app will record upto 5 files before recording to a generic data file as a fallback if all 5 allocated files remain on the watch storage. The limit is in place to avoid going over storage limits as these files can get large over time. --- apps/hrrawexp/app.js | 86 ++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/apps/hrrawexp/app.js b/apps/hrrawexp/app.js index f78d3fbf6..ddd47dc42 100644 --- a/apps/hrrawexp/app.js +++ b/apps/hrrawexp/app.js @@ -1,12 +1,25 @@ -var counter = 1; +var counter = 15; var logging_started; var interval; var value; +var filt; -var file = require("Storage").open("hrm_log.csv", "w"); -file.write(""); +var fileClosed = 0; +var Storage = require("Storage"); +var file; -file = require("Storage").open("hrm_log.csv", "a"); +function exists(name){ + s = require('Storage'); + var fileList = s.list(); + var fileExists = false; + for (let i = 0; i < fileList.length; i++) { + fileExists = fileList[i].includes(name); + if(fileExists){ + break; + } + } + return fileExists; +} function update_timer() { g.clear(); @@ -33,31 +46,56 @@ function update_timer() { function btn1Pressed() { if (!logging_started) { - if (counter < 60) - counter += 1; + if (counter < 120) + counter += 15; else - counter = 1; + counter = 15; update_timer(); } } function btn3Pressed() { if (!logging_started) { - if (counter > 1) - counter -= 1; + if (counter > 15) + counter -= 15; else - counter = 60; + counter = 120; update_timer(); } } function btn2Pressed() { - launchtime = 0 | getTime(); - file.write(launchtime + "," + "\n"); - logging_started = true; - counter = counter * 60; - interval = setInterval(countDown, 1000); - Bangle.setHRMPower(1); + if (!logging_started) { + var filename = ""; + var fileset = false; + + for (let i = 0; i < 5; i++) { + filename = "HRM_data" + i.toString() + ".csv"; + if(exists(filename) == 0){ + file = require("Storage").open(filename,"w"); + console.log("creating new file " + filename); + fileset = true; + } + if(fileset){ + break; + } + } + + if (!fileset){ + console.log("overwiting file"); + file = require("Storage").open("HRM_data.csv","w"); + } + + file.write(""); + file = require("Storage").open(filename,"a"); + + //launchtime = 0 | getTime(); + //file.write(launchtime + "," + "\n"); + logging_started = true; + counter = counter * 60; + interval = setInterval(countDown, 1000); + Bangle.setHRMPower(1); + } } function fmtMSS(e) { @@ -69,11 +107,12 @@ function fmtMSS(e) { function countDown() { g.clear(); counter--; - if (counter == 0) { + if (counter <= 0 && fileClosed == 0) { Bangle.setHRMPower(0); clearInterval(interval); g.drawString("Finished", g.getWidth() / 2, g.getHeight() / 2); Bangle.buzz(500, 1); + fileClosed = 1; } else g.drawString(fmtMSS(counter), g.getWidth() / 2, g.getHeight() / 2); @@ -85,13 +124,8 @@ setWatch(btn1Pressed, BTN1, { repeat: true }); setWatch(btn2Pressed, BTN2, { repeat: true }); setWatch(btn3Pressed, BTN3, { repeat: true }); -Bangle.on('HRM', function (hrm) { - for (let i = 0; i < hrm.raw.length; i++) { - value = hrm.raw[i]; - if (value < -2) - value = -2; - if (value > 6) - value = 6; - file.write(value + "," + "\n"); - } +Bangle.on('HRM-raw', function (hrm) { + value = hrm.raw; + filt = hrm.filt; + file.write(value + "," + filt + "," + "\n"); }); From 9f37d2f5de73b93d766679e7cfaec35acb7fd698 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Wed, 11 Oct 2023 19:27:42 +0100 Subject: [PATCH 032/260] Update README.md --- apps/hrrawexp/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/hrrawexp/README.md b/apps/hrrawexp/README.md index abf2d3d7c..caf7f9833 100644 --- a/apps/hrrawexp/README.md +++ b/apps/hrrawexp/README.md @@ -3,11 +3,11 @@ Extract hrm raw signal data to CSV file Simple app that will run the heart rate monitor for a defined period of time you set at the start. --The app creates a csv file (it's actually just 1 column) and you can download this via My Apps in the App Loader. +Updated to work with new API. Additional capability includes: --The max time value is 60 minutes. - --The first item holds the data/time when the readings were taken and the file is reset each time the app is run. +1. Now also records upto 2 hours - if you cancel at any time the CSV file will still be there, the timer you set at the start is more so that you get an alert when it's complete. +2. Along with raw PPG readings, it also records bandpassed filtered data in a second column, available in the new API. +3. Rather than overwriting 1 data file, the app will record upto 5 files before recording to a generic data file as a fallback if all 5 allocated files remain on the watch storage. The limit is in place to avoid going over storage limits as these files can get large over time. -The hrm sensor is sampled @50Hz and this app does not do any processing on it other than clip overly high/extreme values, the array is written as-is. There is an example Python script that can process this signal, smooth it and also extract a myriad of heart rate variability metrics using the hrvanalysis library: https://github.com/jabituyaben/BangleJS-HRM-Signal-Processing From 10135176b7ee74da5958741b56053a09a0a8cdb4 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Wed, 11 Oct 2023 22:04:29 +0100 Subject: [PATCH 033/260] Update metadata.json --- apps/hrrawexp/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/hrrawexp/metadata.json b/apps/hrrawexp/metadata.json index 3920731aa..a15575539 100644 --- a/apps/hrrawexp/metadata.json +++ b/apps/hrrawexp/metadata.json @@ -2,7 +2,7 @@ "id": "hrrawexp", "name": "HRM Data Exporter", "shortName": "HRM Data Exporter", - "version": "0.01", + "version": "2", "description": "export raw hrm signal data to a csv file", "icon": "app-icon.png", "tags": "", From 5bd98caa1604bf83bd71ae9f527b7daaa1ec0de5 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Wed, 11 Oct 2023 22:06:44 +0100 Subject: [PATCH 034/260] Create ChangeLog --- apps/hrrawexp/ChangeLog | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 apps/hrrawexp/ChangeLog diff --git a/apps/hrrawexp/ChangeLog b/apps/hrrawexp/ChangeLog new file mode 100644 index 000000000..26f1f4200 --- /dev/null +++ b/apps/hrrawexp/ChangeLog @@ -0,0 +1,3 @@ +0.01: New App! +0.02: Fixes +2: updated to work with new API and additional features added such as longer recording time and additional filtered data From 13a7fbe43ad0c13f55857e9d6328d2194e3cfef9 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Wed, 11 Oct 2023 22:18:13 +0100 Subject: [PATCH 035/260] Update ChangeLog --- apps/hrrawexp/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/hrrawexp/ChangeLog b/apps/hrrawexp/ChangeLog index 26f1f4200..0a32e06e6 100644 --- a/apps/hrrawexp/ChangeLog +++ b/apps/hrrawexp/ChangeLog @@ -1,3 +1,3 @@ 0.01: New App! 0.02: Fixes -2: updated to work with new API and additional features added such as longer recording time and additional filtered data +0.03: updated to work with new API and additional features added such as longer recording time and additional filtered data From ef923cba858de3297312e561ac3b652ce9f368b6 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Wed, 11 Oct 2023 22:18:27 +0100 Subject: [PATCH 036/260] Update metadata.json --- apps/hrrawexp/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/hrrawexp/metadata.json b/apps/hrrawexp/metadata.json index a15575539..7df0f450b 100644 --- a/apps/hrrawexp/metadata.json +++ b/apps/hrrawexp/metadata.json @@ -2,7 +2,7 @@ "id": "hrrawexp", "name": "HRM Data Exporter", "shortName": "HRM Data Exporter", - "version": "2", + "version": "0.03", "description": "export raw hrm signal data to a csv file", "icon": "app-icon.png", "tags": "", From c18a52e15b0892566d7e391d5ea8b39ab9c26b8f Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Wed, 11 Oct 2023 23:45:54 +0100 Subject: [PATCH 037/260] Update app.js --- apps/hrrawexp/app.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/hrrawexp/app.js b/apps/hrrawexp/app.js index ddd47dc42..652feba5a 100644 --- a/apps/hrrawexp/app.js +++ b/apps/hrrawexp/app.js @@ -99,9 +99,11 @@ function btn2Pressed() { } function fmtMSS(e) { - var m = Math.floor(e % 3600 / 60).toString().padStart(2, '0'), - s = Math.floor(e % 60).toString().padStart(2, '0'); - return m + ':' + s; + h = Math.floor(e / 3600); + e %= 3600; + m = Math.floor(e / 60); + s = e % 60; + return h + ":" + m + ':' + s; } function countDown() { From ee405145ca90555a33bce199e7f5ddf3f814308c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 13 Oct 2023 09:03:27 +0100 Subject: [PATCH 038/260] run 0.17: Ensure screen redraws after "Resume run?" menu (#3044) --- apps/run/ChangeLog | 1 + apps/run/app.js | 6 +++++- apps/run/metadata.json | 2 +- apps/runplus/ChangeLog | 1 + apps/runplus/app.js | 6 +++++- apps/runplus/metadata.json | 2 +- 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index ab2803ec6..22ab6c22f 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -15,3 +15,4 @@ 0.14: Fix Bangle.js 1 issue where after the 'overwrite track' menu, the start/stop button stopped working 0.15: Keep run state between runs (allowing you to exit and restart the app) 0.16: Added ability to resume a run that was stopped previously (fix #1907) +0.17: Ensure screen redraws after "Resume run?" menu (#3044) \ No newline at end of file diff --git a/apps/run/app.js b/apps/run/app.js index 507e8581a..0e2d78288 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -60,7 +60,11 @@ function onStartStop() { isMenuDisplayed = true; return E.showPrompt("Resume run?",{title:"Run"}); }).then(r => { - isMenuDisplayed=false;shouldResume=r; + isMenuDisplayed = false; + layout.setUI(); // grab our input handling again + layout.forgetLazyState(); + layout.render(); + shouldResume = r; }); } diff --git a/apps/run/metadata.json b/apps/run/metadata.json index ed253a319..07fb9b85e 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.16", + "version":"0.17", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", diff --git a/apps/runplus/ChangeLog b/apps/runplus/ChangeLog index 05d24b96d..96800175a 100644 --- a/apps/runplus/ChangeLog +++ b/apps/runplus/ChangeLog @@ -22,3 +22,4 @@ Write to correct settings file, fixing settings not working. 0.20: Tweak HRM min/max defaults. Extend min/max intervals in settings. Fix another typo. 0.21: Rebase on "Run" app ver. 0.16. +0.22: Ensure screen redraws after "Resume run?" menu (#3044) \ No newline at end of file diff --git a/apps/runplus/app.js b/apps/runplus/app.js index 41fab7ae2..92428d2dc 100644 --- a/apps/runplus/app.js +++ b/apps/runplus/app.js @@ -71,7 +71,11 @@ function onStartStop() { isMenuDisplayed = true; return E.showPrompt("Resume run?",{title:"Run"}); }).then(r => { - isMenuDisplayed=false;shouldResume=r; + isMenuDisplayed=false; + layout.setUI(); // grab our input handling again + layout.forgetLazyState(); + layout.render(); + shouldResume=r; }); } diff --git a/apps/runplus/metadata.json b/apps/runplus/metadata.json index 40256e595..16c6101ca 100644 --- a/apps/runplus/metadata.json +++ b/apps/runplus/metadata.json @@ -1,7 +1,7 @@ { "id": "runplus", "name": "Run+", - "version": "0.21", + "version": "0.22", "description": "Displays distance, time, steps, cadence, pace and more for runners. Based on the Run app, but extended with additional screen for heart rate interval training.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps,karvonen,karvonnen", From 4c62777636bc57b67775e420e24bcd592aa4e653 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 13 Oct 2023 09:40:20 +0100 Subject: [PATCH 039/260] Add option to automatically reload the clock after uploading an app --- core | 2 +- index.html | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core b/core index 11f8e16d2..0f78c425b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 11f8e16d2ebb726bb92f29d812dc3ccba4f362a9 +Subproject commit 0f78c425bbf1e1947a4981232d2d80110fd04fb8 diff --git a/index.html b/index.html index 6c3809343..3db9aedea 100644 --- a/index.html +++ b/index.html @@ -179,9 +179,13 @@ - + +
    -

    Your current firmware version is unknown and DFU is unknown

    +

    Your current firmware version is unknown and DFU is unknown. + The DFU (bootloader) rarely changes, so it does not have to be the same version as your main firmware.