diff --git a/apps/accelrec/ChangeLog b/apps/accelrec/ChangeLog index 2254ad9ea2..eace81e1ec 100644 --- a/apps/accelrec/ChangeLog +++ b/apps/accelrec/ChangeLog @@ -4,3 +4,4 @@ Trigger on 1.04g now, and record 10 samples before trigger 0.03: Bangle.js 2 compatibility 0.04: Minor code improvements +0.05: Can record 100hz, z-axis color changed to yellow, autosave to file, no need select, delete old records diff --git a/apps/accelrec/app.js b/apps/accelrec/app.js index cf434fd7b4..eb91d77afe 100644 --- a/apps/accelrec/app.js +++ b/apps/accelrec/app.js @@ -1,179 +1,253 @@ //var acc; var HZ = 100; -var SAMPLES = 5*HZ; // 5 seconds -var SCALE = 5000; -var THRESH = 1.04; +var SAMPLES = 6 * HZ; // 6 seconds +var SCALE = 2000; +var THRESH = 1.4; var accelx = new Int16Array(SAMPLES); var accely = new Int16Array(SAMPLES); // North var accelz = new Int16Array(SAMPLES); // Into clock face +var timestep = new Int16Array(SAMPLES); // Into clock face var accelIdx = 0; var lastAccel; -function accelHandlerTrigger(a) {"ram" - if (a.mag*2>THRESH) { // *2 because 8g mode - tStart = getTime(); - g.drawString("Recording",g.getWidth()/2,g.getHeight()/2,1); - Bangle.removeListener('accel',accelHandlerTrigger); - Bangle.on('accel',accelHandlerRecord); - lastAccel.forEach(accelHandlerRecord); - accelHandlerRecord(a); - } else { - if (lastAccel.length>10) lastAccel.shift(); - lastAccel.push(a); - } +var timestep_start = 0; + +function accelHandlerTrigger(a) { + "ram" + if (a.mag * 2 > THRESH) { // *2 because 8g mode + timestep_start = getTime(); + g.drawString("Recording", g.getWidth() / 2, g.getHeight() / 2, 1); + Bangle.removeListener('accel', accelHandlerTrigger); + Bangle.on('accel', accelHandlerRecord); + lastAccel.forEach(accelHandlerRecord); + accelHandlerRecord(a); + } else { + if (lastAccel.length > 10) lastAccel.shift(); + lastAccel.push(a); + } } -function accelHandlerRecord(a) {"ram" - var i = accelIdx++; - accelx[i] = a.x*SCALE*2; - accely[i] = -a.y*SCALE*2; - accelz[i] = a.z*SCALE*2; - if (accelIdx>=SAMPLES) recordStop(); + +function accelHandlerRecord(a) { + "ram" + var i = accelIdx++; + accelx[i] = a.x * SCALE * 2; // *2 because of 8g mode + accely[i] = -a.y * SCALE * 2; + accelz[i] = a.z * SCALE * 2; + timestep[i] = (getTime() - timestep_start) * 1000; + if (accelIdx >= SAMPLES) recordStop(); } -function recordStart() {"ram" - Bangle.setLCDTimeout(0); // force LCD on - accelIdx = 0; - lastAccel = []; - Bangle.accelWr(0x18,0b01110100); // off, +-8g - Bangle.accelWr(0x1B,0x03 | 0x40); // 100hz output, ODR/2 filter - Bangle.accelWr(0x18,0b11110100); // +-8g - Bangle.setPollInterval(10); // 100hz input - setTimeout(function() { - Bangle.on('accel',accelHandlerTrigger); - g.clear(1).setFont("6x8",2).setFontAlign(0,0); - g.drawString("Waiting",g.getWidth()/2,g.getHeight()/2); - }, 200); + +function recordStart() { + "ram" + Bangle.setLCDTimeout(0); // force LCD on + accelIdx = 0; + lastAccel = []; + Bangle.accelWr(0x18, 0b01110100); // off, +-8g + Bangle.accelWr(0x1B, 0x03 | 0x40); // 100hz output, ODR/2 filter + Bangle.accelWr(0x18, 0b11110100); // +-8g + Bangle.setPollInterval(10); // 100hz input + setTimeout(function() { + Bangle.on('accel', accelHandlerTrigger); + g.clear(1).setFont("6x8", 2).setFontAlign(0, 0); + g.drawString("Waiting", g.getWidth() / 2, g.getHeight() / 2); + }, 200); } -function recordStop() {"ram" - //console.log("Length:",getTime()-tStart); - Bangle.setPollInterval(80); // default poll interval - Bangle.accelWr(0x18,0b01101100); // off, +-4g - Bangle.accelWr(0x1B,0x0); // default 12.5hz output - Bangle.accelWr(0x18,0b11101100); // +-4g - Bangle.removeListener('accel',accelHandlerRecord); - E.showMessage("Finished"); - showData(); +function recordStop() { + "ram" + //console.log("Length:",getTime()-tStart); + Bangle.setPollInterval(80); // default poll interval + Bangle.accelWr(0x18, 0b01101100); // off, +-4g + Bangle.accelWr(0x1B, 0x0); // default 12.5hz output + Bangle.accelWr(0x18, 0b11101100); // +-4g + Bangle.removeListener('accel', accelHandlerRecord); + E.showMessage("Finished"); + showData(true); } -function showData() { - g.clear(1); - var w = g.getWidth()-20; // width - var m = g.getHeight()/2; // middle - var s = 12; // how many pixels per G - g.fillRect(9,0,9,g.getHeight()); - g.setFontAlign(0,0); - for (var l=-8;l<=8;l++) - g.drawString(l, 5, m - l*s); - - function plot(a) { - g.moveTo(10,m - a[0]*s/SCALE); - for (var i=0;i0.1) { - if (itEnd) tEnd=i; +function showData(save_file) { + g.clear(1); + let csv_files_N = require("Storage").list(/^acc.*\.csv$/).length; + let w_full = g.getWidth(); + let h = g.getHeight(); + var w = g.getWidth() - 20; // width + var m = g.getHeight() / 2; // middle + var s = 12; // how many pixels per G + g.fillRect(9, 0, 9, g.getHeight()); + g.setFontAlign(0, 0); + for (var l = -8; l <= 8; l++) + g.drawString(l, 5, m - l * s); + + function plot(a) { + g.moveTo(10, m - a[0] * s / SCALE); + for (var i = 0; i < SAMPLES; i++) + g.lineTo(10 + i * w / SAMPLES, m - a[i] * s / SCALE); } - if (a>maxAccel) maxAccel=a; - vel += a/HZ; - if (vel>maxVel) maxVel=vel; - } - g.reset(); - g.setFont("6x8").setFontAlign(1,0); - g.drawString("Max Y Accel: "+maxAccel.toFixed(2)+" g",g.getWidth()-14,g.getHeight()-50); - g.drawString("Max Y Vel: "+maxVel.toFixed(2)+" m/s",g.getWidth()-14,g.getHeight()-40); - g.drawString("Time moving: "+(tEnd-tStart)/HZ+" s",g.getWidth()-14,g.getHeight()-30); - //console.log("End Velocity "+vel); - g.setFont("6x8").setFontAlign(0,0,1); - g.drawString("FINISH",g.getWidth()-4,g.getHeight()/2); - setWatch(function() { - showMenu(); - }, global.BTN2?BTN2:BTN); + g.setColor("#FFFA5F"); + plot(accelz); + g.setColor("#ff0000"); + plot(accelx); + g.setColor("#00ff00"); + plot(accely); + + // work out stats + var maxAccel = 0; + var tStart = SAMPLES, + tEnd = 0; + var max_YZ = 0; + for (var i = 0; i < SAMPLES; i++) { + var a = Math.abs(accely[i] / SCALE); + let a_yz = Math.sqrt(Math.pow(accely[i] / SCALE, 2) + Math.pow(accelz[i] / SCALE, 2)); + if (a > 0.1) { + if (i < tStart) tStart = i; + if (i > tEnd) tEnd = i; + } + if (a > maxAccel) maxAccel = a; + if (a_yz > max_YZ) max_YZ = a_yz; + } + g.reset(); + g.setFont("6x8").setFontAlign(1, 0); + g.drawString("Max X Accel: " + maxAccel.toFixed(2) + " g", g.getWidth() - 14, g.getHeight() - 50); + g.drawString("Max YZ Accel: " + max_YZ.toFixed(2) + " g", g.getWidth() - 14, g.getHeight() - 40); + g.drawString("Time moving: " + (tEnd - tStart) / HZ + " s", g.getWidth() - 14, g.getHeight() - 30); + g.setFont("6x8", 2).setFontAlign(0, 0); + g.drawString("File num: " + (csv_files_N + 1), w_full / 2, h - 20); + g.setFont("6x8").setFontAlign(0, 0, 1); + g.drawString("FINISH", g.getWidth() - 4, g.getHeight() / 2); + setWatch(function() { + if (save_file) showSaveMenu(); // when select only plot, don't ask for save option + else showMenu(); + }, global.BTN2 ? BTN2 : BTN); } function showBig(txt) { - g.clear(1); - g.setFontVector(80).setFontAlign(0,0); - g.drawString(txt,g.getWidth()/2, g.getHeight()/2); - g.flip(); + g.clear(1); + g.setFontVector(80).setFontAlign(0, 0); + g.drawString(txt, g.getWidth() / 2, g.getHeight() / 2); + g.flip(); } function countDown() { - showBig(3); - setTimeout(function() { - showBig(2); + showBig(3); setTimeout(function() { - showBig(1); - setTimeout(function() { - recordStart(); - }, 800); + showBig(2); + setTimeout(function() { + showBig(1); + setTimeout(function() { + recordStart(); + }, 800); + }, 1000); }, 1000); - }, 1000); } function showMenu() { - Bangle.setLCDTimeout(10); // set timeout for LCD in menu - var menu = { - "" : { title : "Acceleration Rec" }, - "Start" : function() { - E.showMenu(); - if (accelIdx==0) countDown(); - else E.showPrompt("Overwrite Recording?").then(ok=>{ - if (ok) countDown(); else showMenu(); - }); - }, - "Plot" : function() { - E.showMenu(); - if (accelIdx) showData(); - else E.showAlert("No Data").then(()=>{ - showMenu(); - }); - }, - "Save" : function() { - E.showMenu(); - if (accelIdx) showSaveMenu(); - else E.showAlert("No Data").then(()=>{ - showMenu(); - }); - }, - "Exit" : function() { - load(); - }, - }; - E.showMenu(menu); + Bangle.setLCDTimeout(10); // set timeout for LCD in menu + var menu = { + "": { title: "Acceleration Rec" }, + "Start": function() { + E.showMenu(); + if (accelIdx == 0) countDown(); + else E.showPrompt("Overwrite Recording?").then(ok => { + if (ok) countDown(); + else showMenu(); + }); + }, + "Plot": function() { + E.showMenu(); + if (accelIdx) showData(false); + else E.showAlert("No Data").then(() => { + showMenu(); + }); + }, + "Storage": function() { + E.showMenu(); + if (require("Storage").list(/^acc.*\.csv$/).length) + StorageMenu(); + else + E.showAlert("No Data").then(() => { + showMenu(); + }); + }, + "Exit": function() { + load(); + }, + }; + E.showMenu(menu); } function showSaveMenu() { - var menu = { - "" : { title : "Save" } - }; - [1,2,3,4,5,6].forEach(i=>{ - var fn = "accelrec."+i+".csv"; - var exists = require("Storage").read(fn)!==undefined; - menu["Recording "+i+(exists?" *":"")] = function() { - var csv = ""; - for (var i=0;i { + if (ok) + SaveFile(); + else + showMenu(); + }); +} + +function SaveFile() { + let csv_files_N = require("Storage").list(/^acc.*\.csv$/).length; + //if (csv_files_N > 20) + // E.showMessage("Storage is full"); + // showMenu(); + let csv = ""; + let date = new Date(); + let fn = "accelrec_" + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + "_" + (csv_files_N + 1) + ".csv"; + E.showMessage("Saveing to file \n" + fn); + for (var i = 0; i < SAMPLES; i++) + csv += `${timestep[i]},${accelx[i]/SCALE},${accely[i]/SCALE},${accelz[i]/SCALE}\n`; + require("Storage").write(fn, csv); + showMenu(); +} + +//Show saved csv files +function StorageMenu() { + var menu = { + "": { + title: "Storage" + } }; - }); - menu["< Back"] = function() {showMenu();}; - E.showMenu(menu); + let csv_files = require("Storage").list(/^acc.*\.csv$/); + var inx = 0; + csv_files.forEach(fn => { + inx++; + menu[inx + ". " + fn] = function() { + StorageOptions(fn); + }; + }); + menu["< Back"] = function() { + showMenu(); + }; + E.showMenu(menu); } -showMenu(); +function StorageOptions(file) { + let menu = { + "": { + title: "Options" + }, + "Plot": function() { + showMenu(); + }, + "Delete": function() { + E.showMenu(); + E.showPrompt("Delete recording?").then(ok => { + if (ok) + DeleteRecord(file); + else + StorageMenu(); + }); + }, + "< Back": function() { + StorageMenu(); + }, + }; + E.showMenu(menu); +} + +function DeleteRecord(file) { + E.showMessage("Deleteing file \n" + file); + require("Storage").erase(file); + StorageMenu(); +} +showMenu(); \ No newline at end of file diff --git a/apps/accelrec/interface.html b/apps/accelrec/interface.html index ce35473878..d69b2d50c2 100644 --- a/apps/accelrec/interface.html +++ b/apps/accelrec/interface.html @@ -37,7 +37,7 @@ `; promise = promise.then(function() { document.querySelector(`.btn[fn='${fn}'][act='save']`).addEventListener("click", function() { - Util.saveCSV(fn.slice(0,-4), "X,Y,Z\n"+fileData[fn]); + Util.saveCSV(fn.slice(0,-4), "Time,X,Y,Z\n"+fileData[fn]); }); document.querySelector(`.btn[fn='${fn}'][act='delete']`).addEventListener("click", function() { Util.showModal("Deleting..."); diff --git a/apps/accelrec/metadata.json b/apps/accelrec/metadata.json index b8831c31bf..36d700a190 100644 --- a/apps/accelrec/metadata.json +++ b/apps/accelrec/metadata.json @@ -2,7 +2,7 @@ "id": "accelrec", "name": "Acceleration Recorder", "shortName": "Accel Rec", - "version": "0.04", + "version": "0.05", "description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.", "icon": "app.png", "tags": "", diff --git a/apps/bthome/ChangeLog b/apps/bthome/ChangeLog index 82c93ee1fb..1920ee3a82 100644 --- a/apps/bthome/ChangeLog +++ b/apps/bthome/ChangeLog @@ -4,3 +4,4 @@ Set 'n' for buttons in Bangle.btHomeData correctly (avoids adding extra buttons on end of advertising) 0.04: Fix duplicate button on edit->save 0.05: Use the bleAdvert module +0.06: button number can't be 0. Now generates number automatically diff --git a/apps/bthome/metadata.json b/apps/bthome/metadata.json index 0156a5d327..bbfcfcfe5a 100644 --- a/apps/bthome/metadata.json +++ b/apps/bthome/metadata.json @@ -1,7 +1,7 @@ { "id": "bthome", "name": "BTHome", "shortName":"BTHome", - "version":"0.05", + "version":"0.06", "description": "Allow your Bangle to advertise with BTHome and send events to Home Assistant via Bluetooth", "icon": "icon.png", "type": "app", diff --git a/apps/bthome/settings.js b/apps/bthome/settings.js index 1bdcb270d6..19a8541511 100644 --- a/apps/bthome/settings.js +++ b/apps/bthome/settings.js @@ -11,10 +11,14 @@ require("Storage").writeJSON("bthome.json",settings) } + // Get id number for button that is sent to bthome + function getNewIdNumber(){ + return [1, 2, 3, 4, 5, 6, 7, 8, 9].find(id => settings.buttons.every(button => id != button.n)); + } + function showButtonMenu(button, isNew) { - var isNew = false; if (!button) { - button = {name:"home", icon:"home", n:0, v:"press"}; + button = {name:"home", icon:"home", n:getNewIdNumber(), v:"press"}; isNew = true; } var actions = ["press","double_press","triple_press","long_press","long_double_press","long_triple_press"]; @@ -51,10 +55,6 @@ format : v => actions[v], onchange : v => button.v=actions[v] }, - /*LANG*/"Button #" : { - value : button.n, min:0, max:3, - onchange : v => button.n=v - }, /*LANG*/"Save" : () => { if (isNew) settings.buttons.push(button); saveSettings(); diff --git a/apps/pebblepp/ChangeLog b/apps/pebblepp/ChangeLog index 552258649a..4d81b17d84 100644 --- a/apps/pebblepp/ChangeLog +++ b/apps/pebblepp/ChangeLog @@ -6,4 +6,5 @@ 0.05: Minor code improvements 0.06: Use the clockbg library to allow custom image backgrounds 0.07: Fix automatic coloring of middle of clockinfo images if clockinfo image goes right to the top or left -0.08: Use new clockinfo lib with function to render images wirh borders \ No newline at end of file +0.08: Use new clockinfo lib with function to render images wirh borders +0.09: Add date on the bottom \ No newline at end of file diff --git a/apps/pebblepp/app.js b/apps/pebblepp/app.js index 2c8e241924..2aa50b7dec 100644 --- a/apps/pebblepp/app.js +++ b/apps/pebblepp/app.js @@ -38,6 +38,9 @@ let draw = function() { g.reset(); g.setBgColor(theme.bg).clearRect(0, h2, w, h3); + g.setColor(theme.fg).fillRect(w / 2 - 30, h3 + 5, w / 2 + 30, h); // refresh date background + g.setFontLECO1976Regular22().setFontAlign(0, -1); + g.setColor(theme.bg).drawString(date.getDate() + "." + (date.getMonth() + 1), w / 2, h3 + 5); g.setFontLECO1976Regular42().setFontAlign(0, -1); g.setColor(theme.fg); g.drawString(time, w/2, h2 + 8); @@ -130,10 +133,8 @@ Bangle.setUI({ Bangle.loadWidgets(); require("widget_utils").swipeOn(); // hide widgets, make them visible with a swipe background.fillRect(Bangle.appRect); // start off with completely clear background -// contrast bar (top) -g.setColor(theme.fg).fillRect(0, h2 - 6, w, h2); -// contrast bar (bottom) -g.setColor(theme.fg).fillRect(0, h3, w, h3 + 6); +// background contrast bar +g.setColor(theme.fg).fillRect(0, h2 - 6, w, h3 + 5); draw(); } diff --git a/apps/pebblepp/metadata.json b/apps/pebblepp/metadata.json index 66ce91ee17..eb74fda25b 100644 --- a/apps/pebblepp/metadata.json +++ b/apps/pebblepp/metadata.json @@ -2,7 +2,7 @@ "id": "pebblepp", "name": "Pebble++ Clock", "shortName": "Pebble++", - "version": "0.08", + "version": "0.09", "description": "A pebble style clock (based on the 'Pebble Clock' app) but with two configurable ClockInfo items at the top", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}],