diff --git a/apps/Tyreid/ChangeLog b/apps/Tyreid/ChangeLog new file mode 100644 index 000000000..2f792c8de --- /dev/null +++ b/apps/Tyreid/ChangeLog @@ -0,0 +1 @@ +0.01: Change log created diff --git a/apps/Tyreid/README.md b/apps/Tyreid/README.md new file mode 100644 index 000000000..5c205ab57 --- /dev/null +++ b/apps/Tyreid/README.md @@ -0,0 +1,18 @@ +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. +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. + + + 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")) diff --git a/apps/Tyreid/app.js b/apps/Tyreid/app.js new file mode 100644 index 000000000..8ab63cabd --- /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 = "-"; + + if (num_bt_devices < 99) { + disp_dev_val = num_bt_devices.toString(); + } else { + disp_dev_val = "99+"; + } + + g.setFont("6x8",3); + 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 = { + "": { "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); + + diff --git a/apps/Tyreid/metadata.json b/apps/Tyreid/metadata.json new file mode 100644 index 000000000..4663287e8 --- /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": "small_logo.png", + "tags": "", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"Tyreid.app.js","url":"app.js"}, + {"name":"Tyreid.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/Tyreid/small_logo.png b/apps/Tyreid/small_logo.png new file mode 100644 index 000000000..8b705cd3f Binary files /dev/null and b/apps/Tyreid/small_logo.png differ diff --git a/apps/approxclock/ChangeLog b/apps/approxclock/ChangeLog new file mode 100644 index 000000000..9ba3e983a --- /dev/null +++ b/apps/approxclock/ChangeLog @@ -0,0 +1,4 @@ +0.1: Initial release +0.2: Added more descriptive approximations +0.2f: Bug fixes: Incorrect hour drawn after 50 mins, incorrect quarter minute drawn after 50 mins +0.3: Added touch interaction to display exact time and date. \ No newline at end of file diff --git a/apps/approxclock/app-icon.js b/apps/approxclock/app-icon.js new file mode 100644 index 000000000..d63ad4b1f --- /dev/null +++ b/apps/approxclock/app-icon.js @@ -0,0 +1 @@ +atob("MDAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArgVYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABW19cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsrNcrAACBVoGsVgAAgVaBrFYAAKzXK4GsKwAAgayBAAAAgVYAVoEAAAAAAAAAAADXVqyBAACs14Gs1ysArNeBrNcrAIHX14HXgQCB14HXrAAAVtdW11YAAAAAAAAAAFbXK4GsAACs1wAr11YArNcAK9dWAADXrABWVgDXgQCB1wAAAKzXgQAAAAAAAAAAAKzXrNfXKwCs1wAA14EArKwAK9dWAADXVgAAAADXgQBW1ysAAIHXVgAAAAAAAAAAANfXgYHXVgCs11aB11YArNcrgddWACvXgSsAAACsrCus1wAAK9es1ysAAAAAAAAAK9dWAACsrACsrKzXrAAArKzX16wAVtfX16wAAAAr19fXKwAArKwArKwAAAAAAAAAAAAAAAAAAACsrAArAAAArIEAKwAAAAAAAAAAAAAAACsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsrAAAAAAArIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWVgAAAAAAVlYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArVoErAAAAAAAAAAAAAAAAAAAAAAArVgAAAAAAAAAAAAAAAAAAAAAAAAArrNfXgQCBrNdWAAAAAAAAAAAAAAAAAAAAAABW1wAAAAAAAAAAAAAAAAAAAAAAACvXrCtWgQAAANdWAAAAAAArKwAAAAAAACsAAABW1wAAAAAAAAAAAAAAAAAAAAAAAFbXKwAAAAAAANdWAAAAAIHX16wAAACB19fXVgBW1wAA14EAAAAAAAAAAAAAAAAAAIGsAAAAAAAAANdWAAAAK9eBVteBACvXgSuBVgBW1wBW1ysAAAAAAAAAAAAAAAAAAIHXAAAAAAAAANdWAAAAVtcrAKyBAFbXKwAAAABW16zX1wAAAAAAAAAAAAAAAAAAAFbXVgAAAAAAANeBAAAAVtcrANeBAFbXKwAAAABW14HXrAAAAAAAAAAAAAAAAAAAAACs14GBrAAAAKzXrIEAK9esrNdWACvX14GBVgBW1wAr11YAAAAAAAAAAAAAAAAAAAAAVoGBgQAAACusrIEAACusrFYAAAArgaysVgBWgQAAgYEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") \ No newline at end of file diff --git a/apps/approxclock/app.js b/apps/approxclock/app.js new file mode 100644 index 000000000..4f0bb570a --- /dev/null +++ b/apps/approxclock/app.js @@ -0,0 +1,156 @@ +//load fonts +require("FontSinclair").add(Graphics); +require("FontTeletext5x9Ascii").add(Graphics); + +//const + +const numbers = { + "0": "Twelve", + "1": "One", + "2": "Two", + "3": "Three", + "4": "Four", + "5": "Five", + "6": "Six", + "7": "Seven", + "8": "Eight", + "9": "Nine", + "10": "Ten", + "11": "Eleven", + "12": "Twelve", + "13": "One", + "14": "Two", + "15": "Three", + "16": "Four", + "17": "Five", + "18": "Six", + "19": "Seven", + "20": "Eight", + "21": "Nine", + "22": "Ten", + "23": "Eleven", + "24": "Twelve", +}; + +const minutesByQuarterString = { + 0: "O'Clock", + 15: "Fifteen", + 30: "Thirty", + 45: "Fourty-Five" +}; + +const width = g.getWidth(); +const height = g.getHeight(); +let drawTimeout; + +const getNearestHour = (hours, minutes) => { + if (minutes > 54) { + return hours + 1; + } + return hours; +}; + +const getApproximatePrefix = (minutes, minutesByQuarter) => { + if (minutes === minutesByQuarter) { + return " exactly"; + } else if (minutesByQuarter - minutes < -54) { + return " nearly"; + } else if (minutesByQuarter - minutes < -5) { + return " after"; + } else if (minutesByQuarter - minutes < 0) { + return " just after"; + } else if (minutesByQuarter - minutes > 5) { + return " before"; + } else { + return " nearly"; + } +}; + +const getMinutesByQuarter = minutes => { + if (minutes < 10) { + return 0; + } else if (minutes < 20) { + return 15; + } else if (minutes < 40) { + return 30; + } else if (minutes < 55) { + return 45; + } else { + return 0; + } +}; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function () { + drawTimeout = undefined; + drawTime(); + }, 60000 - (Date.now() % 60000)); +} + +const drawTimeExact = () => { + var dateTime = Date(); + var hours = dateTime.getHours(); + var minutes = dateTime.getMinutes().toString().padStart(2,0); + var day = dateTime.getDay(); + var date = dateTime.getDate(); + var month = dateTime.getMonth(); + var year = dateTime.getFullYear(); + g.clear(); + g.setBgColor(0,0,0); + g.clearRect(0,0,width, height); + g.setColor(1,1,1); + g.setFont("Vector", 30); + g.drawString(hours + ":" + minutes, (width - g.stringWidth(hours + ":" + minutes))/2, height * 0.3, false); + g.setFont("Vector", 26); + g.drawString(month + 1 + "/" + date + "/" + year, (width - g.stringWidth(month + 1 + "/" + date + "/" + year))/2, height * 0.6, false); +}; + +const drawTime = () => { + //Grab time vars + var date = Date(); + var hour = date.getHours(); + var minutes = date.getMinutes(); + var minutesByQuarter = getMinutesByQuarter(minutes); + + //reset graphics + g.clear(); + g.reset(); + + //Build watch face + g.setBgColor(0, 0, 0); + g.clearRect(0, 0, width, height); + g.setFont("Vector", 22); + g.setColor(1, 1, 1); + g.drawString("It's" + getApproximatePrefix(minutes, minutesByQuarter), (width - g.stringWidth("It's" + getApproximatePrefix(minutes, minutesByQuarter))) / 2, height * 0.25, false); + g.setFont("Vector", 30); + g.drawString(numbers[getNearestHour(hour, minutes)], (width - g.stringWidth(numbers[getNearestHour(hour, minutes)])) / 2, height * 0.45, false); + g.setFont("Vector", 22); + g.drawString(minutesByQuarterString[minutesByQuarter], (width - g.stringWidth(minutesByQuarterString[minutesByQuarter])) / 2, height * 0.7, false); + + queueDraw(); +}; + +g.clear(); +drawTime(); + +Bangle.on('lcdPower', function (on) { + if (on) { + drawTime(); + } else { + if (idTimeout) { + clearTimeout(idTimeout); + } + } +}); + +Bangle.on('touch', function(button, xy){ + drawTimeExact(); + setTimeout(drawTime, 7000); +}); + +// Show launcher when button pressed +Bangle.setUI("clock"); +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/approxclock/app.png b/apps/approxclock/app.png new file mode 100644 index 000000000..a5fd8db83 Binary files /dev/null and b/apps/approxclock/app.png differ diff --git a/apps/approxclock/metadata.json b/apps/approxclock/metadata.json new file mode 100644 index 000000000..80e476e5b --- /dev/null +++ b/apps/approxclock/metadata.json @@ -0,0 +1,18 @@ +{ "id": "approxclock", + "name": "Approximate Clock", + "shortName" : "Approx Clock", + "version": "0.3", + "icon": "app.png", + "description": "A really basic spelled out time display for people looking for the vague time at a glance.", + "readme": "readme.md", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"approxclock.app.js","url":"app.js"}, + {"name":"approxclock.img","url":"app-icon.js","evaluate":true} + ], + "screenshots": [ + {"url": "screenshot.png"} + ] +} diff --git a/apps/approxclock/readme.md b/apps/approxclock/readme.md new file mode 100644 index 000000000..aa1b74267 --- /dev/null +++ b/apps/approxclock/readme.md @@ -0,0 +1,7 @@ +## Approximate Clock + +### Description + +Get a rough idea of the time at a quick glance, mostly made for myself based on a similar watchface on pebble. I find this keeps me from checking my watch too often and also saves me from moments of severe brainfart staring at these mysterious symbols we call numbers. + +Exact time and date can be viewed temporarily by touching the screen. \ No newline at end of file diff --git a/apps/approxclock/screenshot.png b/apps/approxclock/screenshot.png new file mode 100644 index 000000000..fe13bbe33 Binary files /dev/null and b/apps/approxclock/screenshot.png differ diff --git a/apps/astral/ChangeLog b/apps/astral/ChangeLog index 17b623677..e77aa2ca2 100644 --- a/apps/astral/ChangeLog +++ b/apps/astral/ChangeLog @@ -5,3 +5,4 @@ 0.05: Added adjustment for Bangle.js magnetometer heading fix 0.06: optimized to update much faster 0.07: added support for bangle.js 2 +0.08: call setUI before loading widgets to indicate we're a clock diff --git a/apps/astral/app.js b/apps/astral/app.js index 88f3f7e0d..7c8f5512a 100644 --- a/apps/astral/app.js +++ b/apps/astral/app.js @@ -850,6 +850,8 @@ g.setBgColor(0, 0, 0); g.fillRect(0, 0, 175, 175); current_moonphase = getMoonPhase(); +Bangle.setUI("clock"); + // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -865,8 +867,6 @@ Bangle.setGPSPower(1); var secondInterval; -Bangle.setUI("clock"); - autoUpdate(); setWatch(SwitchSensorState, BTN1, { repeat: true }); diff --git a/apps/astral/metadata.json b/apps/astral/metadata.json index 4b4922169..16696056f 100644 --- a/apps/astral/metadata.json +++ b/apps/astral/metadata.json @@ -1,7 +1,7 @@ { "id": "astral", "name": "Astral Clock", - "version": "0.07", + "version": "0.08", "description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.", "icon": "app-icon.png", "type": "clock", diff --git a/apps/cards/ChangeLog b/apps/cards/ChangeLog index 00945cd13..24c1bf8ff 100644 --- a/apps/cards/ChangeLog +++ b/apps/cards/ChangeLog @@ -1 +1,2 @@ 0.01: Simple app to display loyalty cards +0.02: Hiding widgets while showing the code diff --git a/apps/cards/app.js b/apps/cards/app.js index dcef7da76..33b4c9e15 100644 --- a/apps/cards/app.js +++ b/apps/cards/app.js @@ -18,9 +18,8 @@ Bangle.drawWidgets(); const WHITE=-1 const BLACK=0 -var FILE = "android.cards.json"; - -var Locale = require("locale"); +const Locale = require("locale"); +const widget_utils = require('widget_utils'); var fontSmall = "6x8"; var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2"; @@ -90,6 +89,7 @@ function printLinearCode(binary) { } function showCode(card) { + widget_utils.hide(); E.showScroller(); // keeping it on rising edge would come back twice.. setWatch(()=>showCard(card), BTN, {edge:"falling"}); @@ -151,6 +151,7 @@ function showCard(card) { var titleColor = g.theme.fg2; if (card.color) titleColor = isLight(titleBgColor) ? BLACK : WHITE; + widget_utils.show(); E.showScroller({ h : g.getFontHeight(), // height of each menu item in pixels c : lines.length, // number of menu items diff --git a/apps/cards/metadata.json b/apps/cards/metadata.json index 63b7da847..810741d5f 100644 --- a/apps/cards/metadata.json +++ b/apps/cards/metadata.json @@ -1,7 +1,7 @@ { "id": "cards", "name": "Cards", - "version": "0.01", + "version": "0.02", "description": "Display loyalty cards", "icon": "app.png", "screenshots": [{"url":"screenshot_cards_overview.png"}, {"url":"screenshot_cards_card1.png"}, {"url":"screenshot_cards_card2.png"}, {"url":"screenshot_cards_barcode.png"}, {"url":"screenshot_cards_qrcode.png"}], diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 9e78bc7a2..c3ea6041a 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -37,4 +37,5 @@ 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 + plotTrack now draws the current track even if you're not actively recording +0.32: Add cadence data to output files \ No newline at end of file diff --git a/apps/recorder/interface.html b/apps/recorder/interface.html index f2774c79f..7f1e3bbc6 100644 --- a/apps/recorder/interface.html +++ b/apps/recorder/interface.html @@ -95,17 +95,27 @@ function saveGPX(track, title) { ${title} `; + let lastTime = 0; track.forEach(pt=>{ + let cadence; + if (pt.Steps && lastTime != 0){ + cadence = pt.Steps * 60000 / (pt.Time.getTime() - lastTime); + cadence = cadence / 2; /*Convert from rpm to spm (one cycle is two steps), see https://github.com/espruino/BangleApps/pull/3068#issuecomment-1790041058*/ + } + lastTime = pt.Time.getTime(); + gpx += ` ${pt.Altitude} - ${pt.Heartrate ? `${pt.Heartrate}`:``}${""/*...65*/} + ${pt.Heartrate ? `${pt.Heartrate}`:``} + ${cadence ? `${cadence}`:``} ${""/*...65*/} `; + }); // https://www8.garmin.com/xmlschemas/TrackPointExtensionv1.xsd gpx += ` diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index b47fb9ded..a95ddf470 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.31", + "version": "0.32", "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/sixths/ChangeLog b/apps/sixths/ChangeLog index 263d4078d..454f6d101 100644 --- a/apps/sixths/ChangeLog +++ b/apps/sixths/ChangeLog @@ -1 +1,2 @@ 0.01: attempt to import +0.02: better GPS support, adding altitude and temperature support diff --git a/apps/sixths/README.md b/apps/sixths/README.md index e5d76d5ad..17369c7a0 100644 --- a/apps/sixths/README.md +++ b/apps/sixths/README.md @@ -25,8 +25,9 @@ minutes, real distance will be usually higher than approximation. Useful gestures: F -- disable GPS. -G -- enable GPS for 4 hours. +G -- enable GPS for 4 hours in low power mode. N -- take a note and write it to the log. +S -- enable GPS for 30 minutes in high power mode. When application detects watch is being worn, it will use vibrations to communicate back to the user. @@ -48,4 +49,10 @@ night. I'd like to make display nicer, and likely more dynamic, displaying whatever application believes is most important at the time (and -possibly allowing scrolling). \ No newline at end of file +possibly allowing scrolling). + +Todo: + +*) only turn on compass when needed + +*) adjust draw timeouts to save power \ No newline at end of file diff --git a/apps/sixths/metadata.json b/apps/sixths/metadata.json index ece88348d..d79e72ced 100644 --- a/apps/sixths/metadata.json +++ b/apps/sixths/metadata.json @@ -1,13 +1,15 @@ { "id": "sixths", "name": "Sixth sense", - "version":"0.01", + "version":"0.02", "description": "Clock for outdoor use with GPS support", "icon": "app.png", "readme": "README.md", "supports" : ["BANGLEJS2"], - "tags": "", + "allow_emulator": true, + "type": "clock", + "tags": "clock", "storage": [ - {"name":"sixths.app.js","url":"app.js"}, + {"name":"sixths.app.js","url":"sixths.app.js"}, {"name":"sixths.img","url":"app-icon.js","evaluate":true} ] } diff --git a/apps/sixths/app.js b/apps/sixths/sixths.app.js similarity index 52% rename from apps/sixths/app.js rename to apps/sixths/sixths.app.js index ce036f79d..2749a02c0 100644 --- a/apps/sixths/app.js +++ b/apps/sixths/sixths.app.js @@ -1,20 +1,53 @@ +// Sixth sense + +// Options you'll want to edit +const rest_altitude = 354; +const geoid_to_sea_level = 0; // Maybe BangleJS2 already compensates? + const W = g.getWidth(); const H = g.getHeight(); var cx = 100; cy = 105; sc = 70; -var buzz = "", msg = ""; temp = 0; alt = 0; bpm = 0; -var buzz = "", msg = "", inm = "", l = "", note = "(NOTEHERE)"; -var mode = 0, mode_time = 0; // 0 .. normal, 1 .. note +var buzz = "", /* Set this to transmit morse via vibrations */ + inm = "", l = "", /* For incoming morse handling */ + in_str = "", + note = "(NOTEHERE)", + debug = "v930", debug2 = "(otherdb)", debug3 = "(short)"; +var mode = 0, mode_time = 0; // 0 .. normal, 1 .. note, 2.. mark name +var disp_mode = 0; // 0 .. normal, 1 .. small time -var gps_on = 0, last_fix = 0, last_restart = 0, last_pause = 0, last_fstart = 0; // utime -var gps_needed = 0, gps_limit = 0; // seconds +// GPS handling +var gps_on = 0, // time GPS was turned on + last_fix = 0, // time of last fix + last_restart = 0, last_pause = 0, last_fstart = 0; // utime +var gps_needed = 0, // how long to wait for a fix + gps_limit = 0, // timeout -- when to stop recording + gps_speed_limit = 0; var prev_fix = null; var gps_dist = 0; -var is_active = false; -var cur_altitude = 0, cur_temperature = 0, alt_adjust = 0; -const rest_altitude = 354; +var mark_heading = -1; + +// Is the human present? +var is_active = false, last_active = getTime(); +var is_level = false; + +// For altitude handling. +var cur_altitude = 0; +var cur_temperature = 0, alt_adjust = 0; +var alt_adjust_mode = ""; + +// Marks +var cur_mark = null; + +// Icons + +icon_alt = "\0\x08\x1a\1\x00\x00\x00\x20\x30\x78\x7C\xFE\xFF\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00"; +icon_m = "\0\x08\x1a\1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00"; +icon_km = "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00"; +icon_kph = "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\xFF\x00\xC3\xC3\xFF\xC3\xC3"; +icon_c = "\0\x08\x1a\1\x00\x00\x60\x90\x90\x60\x00\x7F\xFF\xC0\xC0\xC0\xC0\xC0\xFF\x7F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; function toMorse(x) { r = ""; @@ -28,12 +61,10 @@ function toMorse(x) { } return r; } - function aload(s) { buzz += toMorse(' E'); load(s); } - function gpsRestart() { print("gpsRestart"); Bangle.setGPSPower(1, "sixths"); @@ -41,33 +72,155 @@ function gpsRestart() { last_pause = 0; last_fstart = 0; } - function gpsPause() { print("gpsPause"); Bangle.setGPSPower(0, "sixths"); last_restart = 0; last_pause = getTime(); } - function gpsOn() { gps_on = getTime(); gps_needed = 1000; - gps_limit = 60*60*4; last_fix = 0; prev_fix = null; gps_dist = 0; gpsRestart(); } - function gpsOff() { Bangle.setGPSPower(0, "sixths"); gps_on = 0; } +function fmtDist(km) { return km.toFixed(1) + icon_km; } +function fmtSteps(n) { return fmtDist(0.001 * 0.719 * n); } +function fmtAlt(m) { return m.toFixed(0) + icon_alt; } +function fmtTimeDiff(d) { + if (d < 180) + return ""+d.toFixed(0); + d = d/60; + return ""+d.toFixed(0)+"m"; +} +function gpsHandleFix(fix) { + if (!prev_fix) { + show("GPS acquired", 10); + buzz += " ."; + prev_fix = fix; + } + if (0) { + /* GPS altitude fluctuates a lot, not really usable */ + alt_adjust = cur_altitude - (fix.alt + geoid_to_sea_level); + alt_adjust_mode = "g"; + } + if (1) { + debug = ""+fix.alt+"m "+alt_adjust; + } + if (1) { + let now1 = Date(); + let now2 = fix.time; + n1 = now1.getMinutes() * 60 + now1.getSeconds(); + n2 = now2.getMinutes() * 60 + now2.getSeconds(); + debug2 = "te "+(n2-n1)+"s"; + } + loggps(fix); + d = calcDistance(fix, prev_fix); + if (d > 30) { + prev_fix = fix; + gps_dist += d/1000; + } +} +function gpsHandle() { + let msg = ""; + if (!last_restart) { + d = (getTime()-last_pause); + if (last_fix) + msg = "PL"+ fmtTimeDiff(getTime()-last_fix); + else + msg = "PN"+ fmtTimeDiff(getTime()-gps_on); + print("gps on, paused ", d, gps_needed); + if (d > gps_needed * 2) { + gpsRestart(); + } + } else { + fix = Bangle.getGPSFix(); + if (fix && fix.fix && fix.lat) { + gpsHandleFix(fix); + msg = fix.speed.toFixed(1) + icon_kph; + print("GPS FIX", msg); + + if (!last_fstart) + last_fstart = getTime(); + last_fix = getTime(); + gps_needed = 60; + } else { + if (last_fix) + msg = "L"+ fmtTimeDiff(getTime()-last_fix); + else { + msg = "N"+ fmtTimeDiff(getTime()-gps_on); + if (fix) { + msg += " " + fix.satellites + "sats"; + } + } + } + + d = (getTime()-last_restart); + d2 = (getTime()-last_fstart); + print("gps on, restarted ", d, gps_needed, d2, fix.lat); + if (getTime() > gps_speed_limit && + (d > gps_needed || (last_fstart && d2 > 10))) { + gpsPause(); + gps_needed = gps_needed * 1.5; + print("Pausing, next try", gps_needed); + } + } + msg += " "+gps_dist.toFixed(1)+icon_km; + return msg; +} +function markNew() { + let r = {}; + r.time = getTime(); + r.fix = prev_fix; + r.steps = Bangle.getHealthStatus("day").steps; + r.gps_dist = gps_dist; + r.altitude = cur_altitude; + r.name = "auto"; + return r; +} +function markHandle() { + let m = cur_mark; + msg = m.name + ">" + fmtTimeDiff(getTime()- m.time); + if (m.fix && m.fix.fix) { + let s = fmtDist(calcDistance(m.fix, prev_fix)/1000) + icon_km; + msg += " " + s; + debug = "wp>" + s; + mark_heading = 180 + calcBearing(m.fix, prev_fix); + debug2 = "wp>" + mark_heading; + } else { + msg += " w" + fmtDist(gps_dist - m.gps_dist); + } + return msg; +} +function entryDone() { + show(":" + in_str); + buzz += " ."; + switch (mode) { + case 1: logstamp(">" + in_str); break; + case 2: cur_mark.name = in_str; break; + } + in_str = 0; + mode = 0; +} function inputHandler(s) { - print("Ascii: ", s); - if (mode == 1) { - note = note + s; + print("Ascii: ", s, s[0], s[1]); + if (s[0] == '^') { + switch (s[1]) { + case 'E': mode = 0; break; + case 'T': entryDone(); break; + } + return; + } + if ((mode == 1) || (mode == 2)){ + in_str = in_str + s; + show(">"+in_str, 10); mode_time = getTime(); return; } @@ -80,12 +233,21 @@ function inputHandler(s) { else s = s+(bat/5); buzz += toMorse(s); + show("Bat "+bat+"%", 60); + break; + case 'F': gpsOff(); show("GPS off", 3); break; + case 'G': gpsOn(); gps_limit = getTime() + 60*60*4; show("GPS on", 3); break; + case 'I': + disp_mode += 1; + if (disp_mode == 2) { + disp_mode = 0; + } break; - case 'F': gpsOff(); break; - case 'G': gpsOn(); break; case 'L': aload("altimeter.app.js"); break; - case 'N': mode = 1; note = ">"; mode_time = getTime(); break; + case 'M': mode = 2; show("M>", 10); cur_mark = markNew(); mode_time = getTime(); break; + case 'N': mode = 1; show(">", 10); mode_time = getTime(); break; case 'O': aload("orloj.app.js"); break; + case 'S': gpsOn(); gps_limit = getTime() + 60*30; gps_speed_limit = gps_limit; show("GPS on", 3); break; case 'T': s = ' T'; d = new Date(); @@ -94,9 +256,9 @@ function inputHandler(s) { buzz += toMorse(s); break; case 'R': aload("run.app.js"); break; + case 'Y': buzz += " ."; Bangle.resetCompass(); break; } } - const morseDict = { '.-': 'A', '-...': 'B', @@ -135,37 +297,46 @@ const morseDict = { '-....': '6', '-----': '0', }; - let asciiDict = {}; - for (let k in morseDict) { print(k, morseDict[k]); asciiDict[morseDict[k]] = k; } - - function morseToAscii(morse) { return morseDict[morse]; } - function asciiToMorse(char) { return asciiDict[char]; } - function morseHandler() { - inputHandler(morseToAscii(inm)); + if (inm[0] == "^") { + inputHandler("^"+morseToAscii(inm.substr(1))); + } else { + inputHandler(morseToAscii(inm)); + } + inm = ""; l = ""; } - function touchHandler(d) { let x = Math.floor(d.x); let y = Math.floor(d.y); - g.setColor(0.25, 0, 0); - g.fillCircle(W-x, W-y, 5); - - if (d.b) { + if (1) { /* Just a debugging feature */ + g.setColor(0.25, 0, 0); + if (0) + g.fillCircle(W-x, W-y, 5); + else + g.fillCircle(x, y, 5); + } + if (!d.b) { + morseHandler(); + l = ""; + return; + } + if (y > H/2 && l == "") { + inm = "^"; + } if (x < W/2 && y < H/2 && l != ".u") { inm = inm + "."; l = ".u"; @@ -181,14 +352,10 @@ function touchHandler(d) { if (x > W/2 && y > H/2 && l != "-d") { inm = inm + "-"; l = "-d"; - } + } - } else - morseHandler(); - - print(inm, "drag:", d); + //print(inm, "drag:", d); } - function add0(i) { if (i > 9) { return ""+i; @@ -196,18 +363,14 @@ function add0(i) { return "0"+i; } } - var lastHour = -1, lastMin = -1; - function logstamp(s) { logfile.write("utime=" + getTime() + " " + s + "\n"); } - function loggps(fix) { logfile.write(fix.lat + " " + fix.lon + " "); logstamp(""); } - function hourly() { print("hourly"); s = ' T'; @@ -215,31 +378,35 @@ function hourly() { buzz += toMorse(s); logstamp(""); } - +function show(msg, timeout) { + note = msg; +} function fivemin() { print("fivemin"); s = ' B'; bat = E.getBattery(); - if (bat < 45) { - s = s+(bat/5); + if (bat < 25) { if (is_active) buzz += toMorse(s); + show("Bat "+bat+"%", 60); } - if (0) + try { Bangle.getPressure().then((x) => { cur_altitude = x.altitude; cur_temperature = x.temperature; }, - print) - .catch(print); + print); + } catch (e) { + print("Altimeter error", e); + } + } - function every(now) { - if ((mode > 0) && (mode_time - getTime() > 60)) { + if ((mode > 0) && (getTime() - mode_time > 10)) { if (mode == 1) { - logstamp(">" + note); + entryDone(); } mode = 0; } - if (gps_on && getTime() - gps_on > gps_limit) { + if (gps_on && getTime() > gps_limit && getTime() > gps_speed_limit) { Bangle.setGPSPower(0, "sixths"); gps_on = 0; } @@ -255,96 +422,136 @@ function every(now) { } +function radians(a) { return a*Math.PI/180; } +function degrees(a) { return a*180/Math.PI; } // distance between 2 lat and lons, in meters, Mean Earth Radius = 6371km // https://www.movable-type.co.uk/scripts/latlong.html // (Equirectangular approximation) function calcDistance(a,b) { - function radians(a) { return a*Math.PI/180; } var x = radians(b.lon-a.lon) * Math.cos(radians((a.lat+b.lat)/2)); var y = radians(b.lat-a.lat); return Math.sqrt(x*x + y*y) * 6371000; } +// thanks to waypointer +function calcBearing(a,b){ + var delta = radians(b.lon-a.lon); + var alat = radians(a.lat); + var blat = radians(b.lat); + var y = Math.sin(delta) * Math.cos(blat); + var x = Math.cos(alat)*Math.sin(blat) - + Math.sin(alat)*Math.cos(blat)*Math.cos(delta); + return Math.round(degrees(Math.atan2(y, x))); +} +function testBearing() { + let p1 = {}, p2 = {}; + p1.lat = 40; p2.lat = 50; + p1.lon = 14; p2.lon = 14; + print("bearing = ", calcBearing(p1, p2)); +} +function radA(p) { return p*(Math.PI*2); } +function radD(d) { return d*(H/2); } +function radX(p, d) { + let a = radA(p); + return H/2 + Math.sin(a)*radD(d); +} +function radY(p, d) { + let a = radA(p); + return W/2 - Math.cos(a)*radD(d); +} +function drawDot(h, d, s) { + let x = radX(h/360, d); + let y = radY(h/360, d); + g.fillCircle(x,y, 10); +} +function drawBackground() { + acc = Bangle.getAccel(); + is_level = (acc.z < -0.95); + if (is_level) { + let obj = Bangle.getCompass(); + if (obj) { + let h = 360-obj.heading; + print("Compass", h); + g.setColor(0.5, 0.5, 1); + drawDot(h, 0.7, 10); + } + } + if (prev_fix && prev_fix.fix) { + g.setColor(0.5, 1, 0.5); + drawDot(prev_fix.course, 0.5, 6); + } + if (mark_heading != -1) { + g.setColor(1, 0.5, 0.5); + drawDot(mark_heading, 0.6, 8); + } +} +function drawTime(now) { + if (disp_mode == 0) + g.setFont('Vector', 60); + else + g.setFont('Vector', 26); + g.setFontAlign(1, 1); + g.drawString(now.getHours() + ":" + add0(now.getMinutes()), W, 90); +} function draw() { + if (disp_mode == 2) { + draw_all(); + return; + } g.setColor(1, 1, 1); - g.fillRect(0, 25, W, H); - g.setFont('Vector', 60); + g.fillRect(0, 24, W, H); + + if (0) { + g.setColor(0.25, 1, 1); + g.fillPoly([ W/2, 24, W, 80, 0, 80 ]); + } + let msg = ""; + if (gps_on) { + msg = gpsHandle(); + } else { + msg = note; + } + drawBackground(); - g.setColor(0, 0, 0); - g.setFontAlign(-1, 1); let now = new Date(); - g.drawString(now.getHours() + ":" + add0(now.getMinutes()), 10, 90); + g.setColor(0, 0, 0); + drawTime(now); every(now); let km = 0.001 * 0.719 * Bangle.getHealthStatus("day").steps; + g.setFontAlign(-1, 1); g.setFont('Vector', 26); const weekday = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; - g.drawString(weekday[now.getDay()] + "" + now.getDate() + ". " + km.toFixed(1) + "km", 10, 115); + g.drawString(weekday[now.getDay()] + "" + now.getDate() + ". " + + fmtSteps(Bangle.getHealthStatus("day").steps), 10, 115); - if (gps_on) { - if (!last_restart) { - d = (getTime()-last_pause); - if (last_fix) - msg = "PL"+ (getTime()-last_fix).toFixed(0); - else - msg = "PN"+ (getTime()-gps_on).toFixed(0); - - print("gps on, paused ", d, gps_needed); - if (d > gps_needed * 2) { - gpsRestart(); - } - } else { - fix = Bangle.getGPSFix(); - if (fix.fix && fix.lat) { - if (!prev_fix) { - prev_fix = fix; - } - msg = fix.speed.toFixed(1) + " km/h"; - if (!last_fstart) - last_fstart = getTime(); - last_fix = getTime(); - gps_needed = 60; - loggps(fix); - print("GPS FIX", msg); - d = calcDistance(fix, prev_fix); - if (d > 30) { - prev_fix = fix; - gps_dist += d/1000; - } - } else { - if (last_fix) - msg = "L"+ (getTime()-last_fix).toFixed(0); - else - msg = "N"+ (getTime()-gps_on).toFixed(0); - } - - d = (getTime()-last_restart); - d2 = (getTime()-last_fstart); - print("gps on, restarted ", d, gps_needed, d2, fix.lat); - if (d > gps_needed || (last_fstart && d2 > 10)) { - gpsPause(); - gps_needed = gps_needed * 1.5; - print("Pausing, next try", gps_needed); - } - } - msg += " "+gps_dist.toFixed(1)+"km"; - } else { - msg = note; - } g.drawString(msg, 10, 145); - if (is_active) { - g.drawString("act " + (cur_altitude - alt_adjust).toFixed(0), 10, 175); - } else { + + if (getTime() - last_active > 15*60) { alt_adjust = cur_altitude - rest_altitude; - g.drawString(alt_adjust.toFixed(0) + "m " + cur_temperature.toFixed(1)+"C", 10, 175); + alt_adjust_mode = "h"; + msg = "H)" + fmtAlt(alt_adjust); + } else { + msg = alt_adjust_mode+")"+fmtAlt(cur_altitude - alt_adjust); } + msg = msg + " " + cur_temperature.toFixed(1)+icon_c; + if (cur_mark) { + msg = markHandle(); + } + g.drawString(msg, 10, 175); + + if (disp_mode == 1) { + g.drawString(debug, 10, 45); + g.drawString(debug2, 10, 65); + g.drawString(debug3, 10, 85); + } + queueDraw(); } - function draw_all() { g.setColor(0, 0, 0); g.fillRect(0, 0, W, H); @@ -394,14 +601,13 @@ function draw_all() { g.setFont('Vector', 22); g.drawString(now.getDate()+"."+(now.getMonth()+1)+" "+now.getDay(), 3, 60); - g.drawString(msg, 3, 80); + g.drawString("(message here)", 3, 80); g.drawString("S" + step + " B" + Math.round(bat/10) + (Bangle.isCharging()?"c":""), 3, 100); g.drawString("A" + Math.round(alt) + " T" + Math.round(temp), 3, 120); g.drawString("C" + Math.round(co.heading) + " B" + bpm, 3, 140); queueDraw(); } - function accelTask() { tm = 100; acc = Bangle.getAccel(); @@ -424,7 +630,6 @@ function accelTask() { setTimeout(accelTask, tm); } - function buzzTask() { if (buzz != "") { now = buzz[0]; @@ -442,9 +647,8 @@ function buzzTask() { setTimeout(buzzTask, 6*dot); } else print("Unknown character -- ", now, buzz); } else - setTimeout(buzzTask, 60000); + setTimeout(buzzTask, 1000); } - function aliveTask() { function cmp(s) { let d = acc[s] - last_acc[s]; @@ -456,6 +660,7 @@ function aliveTask() { if (cmp("x") || cmp("y") || cmp("z")) { print("active"); is_active = true; + last_active = getTime(); } last_acc = acc; @@ -476,14 +681,15 @@ function queueDraw() { }, next - (Date.now() % next)); } - function start() { Bangle.on("drag", touchHandler); if (0) Bangle.on("accel", accelHandler); - if (0) { + if (1) { Bangle.setCompassPower(1, "sixths"); Bangle.setBarometerPower(1, "sixths"); + } + if (0) { Bangle.setHRMPower(1, "sixths"); Bangle.setGPSPower(1, "sixths"); Bangle.on("HRM", (hrm) => { bpm = hrm.bpm; } ); @@ -500,9 +706,14 @@ function start() { } g.reset(); -Bangle.setUI(); +Bangle.setUI({ + mode : "clock" +}); Bangle.loadWidgets(); Bangle.drawWidgets(); let logfile = require("Storage").open("sixths.egt", "a"); -start(); +if (0) { + testBearing(); +} else + start(); diff --git a/apps/stacker/README.md b/apps/stacker/README.md index 5be5b7bee..e1019f970 100644 --- a/apps/stacker/README.md +++ b/apps/stacker/README.md @@ -5,7 +5,8 @@ A simple game of stacking cubes. ## Usage -Press the button to stack! +Boxes move horizontally. Use button to stack them on top of existing +boxes. You win when you reach top of the screen. ## Creator diff --git a/apps/stacker/metadata.json b/apps/stacker/metadata.json index abaf49a6d..3516625a1 100644 --- a/apps/stacker/metadata.json +++ b/apps/stacker/metadata.json @@ -6,6 +6,7 @@ "icon": "app.png", "tags": "game", "supports" : ["BANGLEJS", "BANGLEJS2"], + "allow_emulator": true, "readme": "README.md", "storage": [ {"name":"stacker.app.js","url":"app.js"}, diff --git a/apps/tetris/ChangeLog b/apps/tetris/ChangeLog index 6366af6c0..aae9b12d7 100644 --- a/apps/tetris/ChangeLog +++ b/apps/tetris/ChangeLog @@ -1,2 +1,3 @@ 0.01: New app! 0.02: Better controls, implement game over. +0.03: Implement mode and level selection screens. diff --git a/apps/tetris/metadata.json b/apps/tetris/metadata.json index f10c06c54..f0a7fd9ab 100644 --- a/apps/tetris/metadata.json +++ b/apps/tetris/metadata.json @@ -1,7 +1,7 @@ { "id": "tetris", "name": "Tetris", "shortName":"Tetris", - "version":"0.02", + "version":"0.03", "description": "Tetris", "icon": "tetris.png", "readme": "README.md", diff --git a/apps/tetris/tetris.app.js b/apps/tetris/tetris.app.js index 77c40de9a..ac9954093 100644 --- a/apps/tetris/tetris.app.js +++ b/apps/tetris/tetris.app.js @@ -36,11 +36,27 @@ const tiles = [ const ox = 176/2 - 5*8; const oy = 8; -var pf = Array(23).fill().map(()=>Array(12).fill(0)); // field is really 10x20, but adding a border for collision checks -pf[20].fill(1); -pf[21].fill(1); -pf[22].fill(1); -pf.forEach((x,i) => { pf[i][0] = 1; pf[i][11] = 1; }); +/* 0 .. simulated arrows + 1 .. drag piece + 2 .. accelerometer. 12 lines record. + 3 .. altimeter + */ +var control = 0, level = 0; +var alt_start = -9999; /* For altimeter control */ +/* 0 .. menu + 1 .. game + 2 .. game over */ +var state = 0; + +var pf; + +function initGame() { + pf = Array(23).fill().map(()=>Array(12).fill(0)); // field is really 10x20, but adding a border for collision checks + pf[20].fill(1); + pf[21].fill(1); + pf[22].fill(1); + pf.forEach((x,i) => { pf[i][0] = 1; pf[i][11] = 1; }); +} function rotateTile(t, r) { var nt = JSON.parse(JSON.stringify(t)); @@ -98,6 +114,8 @@ function redrawPF(ly) { function gameOver() { g.setColor(1, 1, 1).setFontAlign(0, 1, 0).setFont("Vector",22) .drawString("Game Over", 176/2, 76); + state = 0; + E.showAlert("Game Over").then(selectGame, print); } function insertAndCheck() { @@ -138,6 +156,8 @@ function moveOk(t, dx, dy) { } function gameStep() { + if (state != 1) + return; if (Date.now()-time > dropInterval) { // drop one step time = Date.now(); if (moveOk(ct, 0, 1)) { @@ -169,12 +189,50 @@ function move(x, y) { } } -Bangle.setUI(); -Bangle.on("drag", (e) => { - let h = 176/2; - if (!e.b) +function linear(x) { + print("Linear: ", x); + let now = px / 10; + if (x < now-0.06) + move(-1, 0); + if (x > now+0.06) + move(1, 0); +} + +function newGame() { + E.showMenu(); + Bangle.setUI(); + if (control == 2) { + Bangle.on("accel", (e) => { + if (state != 1) return; + if (control != 2) return; + print(e.x); + linear((0.2-e.x) * 2.5); + }); + } + if (control == 3) { + Bangle.setBarometerPower(true); + Bangle.on("pressure", (e) => { + if (state != 1) return; + if (control != 3) return; + let a = e.altitude; + if (alt_start == -9999) + alt_start = a; + a = a - alt_start; + print(e.altitude, a); + linear(a); + }); + } + Bangle.on("drag", (e) => { + let h = 176/2; + if (state == 2) { + if (e.b) + selectGame(); + return; + } + if (!e.b) return; - if (e.y < h) { + if (state == 0) return; + if (e.y < h) { if (e.x < h) rotate(); else { @@ -184,21 +242,60 @@ Bangle.on("drag", (e) => { g.flip(); } } - } else { + } else { + if (control == 1) + linear((e.x - 20) / 156); + if (control != 0) + return; if (e.x < h) move(-1, 0); else move(1, 0); - } -}); + } + }); -Bangle.on("swipe", (x,y) => { - if (y<0) y = 0; - move(x, y); -}); + initGame(); + drawGame(); + state = 1; + var step = 450 - 50*level; + if (control == 3) + step = step*2; + dropInterval = step; + var gi = setInterval(gameStep, 50); +} -drawBoundingBox(); -g.setColor(1, 1, 1).setFontAlign(0, 1, 0).setFont("6x15", 1).drawString("Lines", 22, 30).drawString("Next", 176-22, 30); -showNext(ntn, ntr); -g.setColor(0).fillRect(5, 30, 41, 80).setColor(1, 1, 1).drawString(nlines.toString(), 22, 50); -var gi = setInterval(gameStep, 20); +function drawGame() { + drawBoundingBox(); + g.setColor(1, 1, 1).setFontAlign(0, 1, 0) + .setFont("6x15", 1).drawString("Lines", 22, 30) + .drawString("Next", 176-22, 30); + showNext(ntn, ntr); + g.setColor(0).fillRect(5, 30, 41, 80) + .setColor(1, 1, 1).drawString(nlines.toString(), 22, 50); +} + +function selectLevel() { + print("Level selection menu"); + + var menu = {}; + menu["Level 1"] = () => { level = 0; selectGame(); }; + menu["Level 2"] = () => { level = 1; selectGame(); }; + menu["Level 3"] = () => { level = 2; selectGame(); }; + E.showMenu(menu); +} + +function selectGame() { + state = 0; + print("Game selection menu"); + //for (let i = 0; i < 100000; i++) ; + + var menu = {}; + menu["Normal"] = () => { control = 0; newGame(); }; + menu["Drag"] = () => { control = 1; newGame(); }; + menu["Tilt"] = () => { control = 2; newGame(); }; + menu["Move"] = () => { control = 3; newGame(); }; + menu["Level"] = () => { selectLevel(); }; + E.showMenu(menu); +} + +selectGame(); diff --git a/apps/waypoint_editor/ChangeLog b/apps/waypoint_editor/ChangeLog index 0ec5d2df8..0f45b79cc 100644 --- a/apps/waypoint_editor/ChangeLog +++ b/apps/waypoint_editor/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Display waypoint name instead of its index in remove menu and fix icon +0.03: Use text input for waypoint names, allow marking waypoint with current GPS position diff --git a/apps/waypoint_editor/app.js b/apps/waypoint_editor/app.js index 48a956d82..cbdcdbfd3 100644 --- a/apps/waypoint_editor/app.js +++ b/apps/waypoint_editor/app.js @@ -13,6 +13,10 @@ var wp = require('Storage').readJSON("waypoints.json", true) || []; 2 .. DD MM'ss" */ var mode = 1; +var key; /* Shared between functions, typically wp name */ +var fix; /* GPS fix */ +var cancel_gps; +var gps_start; function writeWP() { require('Storage').writeJSON("waypoints.json", wp); @@ -22,28 +26,94 @@ function mainMenu() { var menu = { "< Back" : Bangle.load }; - if (Object.keys(wp).length==0) Object.assign(menu, {"NO WPs":""}); - else for (let id in wp) { + if (Object.keys(wp).length==0) { + //Object.assign(menu, {"NO WPs":""}); + print("(no waypoints)"); + } else for (let id in wp) { let i = id; - menu[wp[id]["name"]]=()=>{ decode(i); }; + menu[wp[id]["name"]]=()=>{ show(i); }; } menu["Add"]=addCard; menu["Remove"]=removeCard; menu["Format"]=setFormat; + menu["Mark GPS"]=markGps; g.clear(); E.showMenu(menu); } -function setFormat() { - var confirmRemove = new Layout ( - {type:"v", c: [ - {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:"Format"}, - {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "DD.dddd", cb:l=>{ mode = 0; mainMenu(); }}, - {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "DD MM.mmm'", cb:l=>{ mode = 1; mainMenu(); }}, - {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "DD MM'ss"+'"', cb:l=>{ mode = 2; mainMenu(); }}, - ], lazy:true}); +function updateGps() { + let have = false, lat = "lat", lon = "lon", alt = "alt", speed = "speed"; + + if (cancel_gps) + return; + fix = Bangle.getGPSFix(); + + speed = "no fix for " + (getTime() - gps_start).toFixed(0) + "s"; + + if (fix && fix.fix && fix.lat) { + lat = "" + lat(fix.lat); + lon = "" + lon(fix.lon); + alt = "alt " + fix.alt.toFixed(0) + "m"; + speed = "speed " + fix.speed.toFixed(1) + "kt"; + have = true; + } + + g.reset().setFont("Vector", 20) + .setColor(1,1,1) + .fillRect(0, 0, 176, 120) + .setColor(0,0,0) + .drawString(key, 0, 0) + .drawString(lat, 0, 20) + .drawString(lon, 0, 40) + .drawString(alt, 0, 60) + .drawString(speed, 0, 80); + + setTimeout(updateGps, 100); +} + +function stopGps() { + cancel_gps=true; + Bangle.setGPSPower(0, "waypoint_editor"); +} + +function confirmGps(s) { + key = s; + var la = new Layout ( + {type:"v", c: [ + {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:""}, + {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:""}, + {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:""}, + {type:"h", c: [ + {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "YES", cb:l=>{ + print("should mark", key, fix); createWP(fix.lat, fix.lon, key); cancel_gps=true; mainMenu(); + }}, + {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: " NO", cb:l=>{ cancel_gps=true; mainMenu(); }} + ]} + ], lazy:true}); g.clear(); - confirmRemove.render(); + la.render(); + updateGps(); +} + +function markGps() { + cancel_gps = false; + Bangle.setGPSPower(1, "waypoint_editor"); + gps_start = getTime(); + require("textinput").input({text:"wp"}).then(key => { + confirmGps(key); + }); +} + +function setFormat() { + var la = new Layout ( + {type:"v", c: [ + {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:"Format"}, + {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "DD.dddd", cb:l=>{ mode = 0; mainMenu(); }}, + {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "DD MM.mmm'", cb:l=>{ mode = 1; mainMenu(); }}, + {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "DD MM'ss"+'"', cb:l=>{ mode = 2; mainMenu(); }}, + ], lazy:true}); + g.clear(); + la.render(); } function format(x) { @@ -65,7 +135,6 @@ function format(x) { return "" + d + " " + mf + "'" + s + '"'; } } - function lat(x) { c = "N"; if (x<0) { @@ -74,7 +143,6 @@ function lat(x) { } return c+format(x); } - function lon(x) { c = "E"; if (x<0) { @@ -84,17 +152,17 @@ function lon(x) { return c+format(x); } -function decode(pin) { - print(pin); - var i = wp[pin]; - var pinDecrypted=i["name"] + "\n" + lat(i["lat"]) + "\n" + lon(i["lon"]); - var showPin = new Layout ({ - type:"v", c: [ - {type:"txt", font:"10%", pad:1, fillx:1, filly:1, label: pinDecrypted}, - {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label:"OK", cb:l=>{mainMenu();}} - ], lazy:true}); - g.clear(); - showPin.render(); +function show(pin) { + print(pin); + var i = wp[pin]; + var l = i["name"] + "\n" + lat(i["lat"]) + "\n" + lon(i["lon"]); + var la = new Layout ({ + type:"v", c: [ + {type:"txt", font:"10%", pad:1, fillx:1, filly:1, label: l}, + {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label:"OK", cb:l=>{mainMenu();}} + ], lazy:true}); + g.clear(); + la.render(); } function showNumpad(text, key_, callback) { @@ -155,10 +223,10 @@ function showNumpad(text, key_, callback) { function removeCard() { var menu = { - "" : {title : "select card"}, + "" : {title : "Select WP"}, "< Back" : mainMenu }; - if (Object.keys(wp).length==0) Object.assign(menu, {"NO CARDS":""}); + if (Object.keys(wp).length==0) Object.assign(menu, {"No WPs":""}); else { wp.forEach((val, card) => { const name = wp[card].name; @@ -186,17 +254,16 @@ function removeCard() { } function ask01(t, cb) { - var confirmRemove = new Layout ( + var la = new Layout ( {type:"v", c: [ - {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:"Format"}, + {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:"Select"}, {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: t[0], cb:l=>{ cb(1); }}, {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: t[1], cb:l=>{ cb(-1); }}, ], lazy:true}); g.clear(); - confirmRemove.render(); + la.render(); } - function askCoordinate(t1, t2, callback) { let sign = 1; ask01(t1, function(sign) { @@ -237,8 +304,27 @@ function askPosition(callback) { }); } +function createWP(lat, lon, name) { + let n = {}; + n["name"] = name; + n["lat"] = lat; + n["lon"] = lon; + wp.push(n); + print("add -- waypoints", wp); + writeWP(); +} + +function addCardName(name) { + g.clear(); + askPosition(function(lat, lon) { + print("position -- ", lat, lon); + createWP(lat, lon, result); + mainMenu(); + }); +} + function addCard() { - showNumpad("wpXX", "wp", function() { + require("textinput").input({text:"wp"}).then(key => { result = key; if (wp[result]!=undefined) { E.showMenu(); @@ -247,29 +333,17 @@ function addCard() { {type:"txt", font:Math.min(15,100/result.length)+"%", pad:1, fillx:1, filly:1, label:result}, {type:"txt", font:"12%", pad:1, fillx:1, filly:1, label:"already exists."}, {type:"h", c: [ - {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label: "REPLACE", cb:l=>{encodeCard(result);}}, + {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label: "REPLACE", cb:l=>{addCardName(result);}}, {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label: "CANCEL", cb:l=>{mainMenu();}} ]} ], lazy:true}); g.clear(); alreadyExists.render(); - } - g.clear(); - askPosition(function(lat, lon) { - print("position -- ", lat, lon); - let n = {}; - n["name"] = result; - n["lat"] = lat; - n["lon"] = lon; - wp.push(n); - print("add -- waypoints", wp); - writeWP(); - mainMenu(); - }); + } + addCardName(result); }); } - g.reset(); Bangle.setUI(); mainMenu(); diff --git a/apps/waypoint_editor/metadata.json b/apps/waypoint_editor/metadata.json index 12ff6e095..87f0ed8ce 100644 --- a/apps/waypoint_editor/metadata.json +++ b/apps/waypoint_editor/metadata.json @@ -1,11 +1,13 @@ { "id": "waypoint_editor", "name": "Waypoint editor", - "version":"0.02", + "version":"0.03", "description": "Allows editing waypoints on device", "icon": "app.png", "readme": "README.md", "supports" : ["BANGLEJS2"], + "allow_emulator": true, "tags": "tool,outdoors,gps", + "dependencies": {"textinput":"type"}, "storage": [ {"name":"waypoint_editor.app.js","url":"app.js"}, {"name":"waypoint_editor.img","url":"app-icon.js","evaluate":true} diff --git a/apps/widclk/ChangeLog b/apps/widclk/ChangeLog index 1a89e2780..bbf9f2762 100644 --- a/apps/widclk/ChangeLog +++ b/apps/widclk/ChangeLog @@ -4,3 +4,4 @@ 0.05: Don't show clock widget if already showing clock app 0.06: Use 7 segment font, update *on* the minute, use less memory 0.07: allow turning on/off when quick-switching apps +0.08: Ensure we clear the whole rect so we don't end up leaving old text when time changes (fix #3073) \ No newline at end of file diff --git a/apps/widclk/metadata.json b/apps/widclk/metadata.json index e4d7d76d1..b0e345ad9 100644 --- a/apps/widclk/metadata.json +++ b/apps/widclk/metadata.json @@ -1,7 +1,7 @@ { "id": "widclk", "name": "Digital clock widget", - "version": "0.07", + "version": "0.08", "description": "A simple digital clock widget that appears when not showing a fullscreen clock", "icon": "widget.png", "type": "widget", diff --git a/apps/widclk/widget.js b/apps/widclk/widget.js index a31bd4772..af35ae459 100644 --- a/apps/widclk/widget.js +++ b/apps/widclk/widget.js @@ -7,13 +7,13 @@ WIDGETS["wdclk"]={area:"tl",width:Bangle.CLOCK?0:52/* g.stringWidth("00:00") */, return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw } if (!this.width) return; // if not visible, return -g.reset().setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 512+9); +g.reset().setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 512+9).setFontAlign(0,0); var time = require("locale").time(new Date(),1); - g.drawString(time, this.x, this.y+3, true); // 5 * 6*2 = 60 + g.clearRect(this.x, this.y, this.x+this.width-1, this.y+23).drawString(time, this.x+this.width/2, this.y+12); // 5 * 6*2 = 60 // queue draw in one minute if (this.drawTimeout) clearTimeout(this.drawTimeout); this.drawTimeout = setTimeout(()=>{ this.drawTimeout = undefined; this.draw(); }, 60000 - (Date.now() % 60000)); -}}; +}}; \ No newline at end of file diff --git a/apps/widclkbttm/ChangeLog b/apps/widclkbttm/ChangeLog index 373337378..29958b249 100644 --- a/apps/widclkbttm/ChangeLog +++ b/apps/widclkbttm/ChangeLog @@ -3,4 +3,4 @@ 0.03: based in widclk v0.05 compatible at same time, bottom area and color 0.04: refactored to use less memory, and allow turning on/off when quick-switching apps 0.05: Remove cyan color, use theme foreground instead - +0.06: Ensure we clear the whole rect so we don't end up leaving old text when time changes diff --git a/apps/widclkbttm/metadata.json b/apps/widclkbttm/metadata.json index 4b14ef9c6..5721f0114 100644 --- a/apps/widclkbttm/metadata.json +++ b/apps/widclkbttm/metadata.json @@ -2,7 +2,7 @@ "id": "widclkbttm", "name": "Digital clock (Bottom) widget", "shortName": "Digital clock Bottom Widget", - "version": "0.05", + "version": "0.06", "description": "Displays time HH:mm in the bottom of the screen (may not be compatible with some apps)", "icon": "widclkbttm.png", "type": "widget", diff --git a/apps/widclkbttm/widclkbttm.wid.js b/apps/widclkbttm/widclkbttm.wid.js index 50142a5b9..55c841500 100644 --- a/apps/widclkbttm/widclkbttm.wid.js +++ b/apps/widclkbttm/widclkbttm.wid.js @@ -4,7 +4,7 @@ WIDGETS["wdclkbttm"]={area:"br",width:Bangle.CLOCK?0:60,draw:function() { return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw } if (!this.width) return; // if not visible, return - g.reset().setFont("6x8", 2).setFontAlign(-1, 0); + g.reset().setFont("6x8", 2).setFontAlign(-1, 0).clearRect(this.x, this.y, this.x+this.width-1, this.y+23); var time = require("locale").time(new Date(),1); g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 // queue draw in one minute