Merge remote-tracking branch 'upstream/master'
commit
15c95bf538
19
apps.json
19
apps.json
|
|
@ -1341,7 +1341,7 @@
|
||||||
"name": "Active Pedometer",
|
"name": "Active Pedometer",
|
||||||
"shortName":"Active Pedometer",
|
"shortName":"Active Pedometer",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.07",
|
"version":"0.08",
|
||||||
"description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.",
|
"description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.",
|
||||||
"tags": "outdoors,widget",
|
"tags": "outdoors,widget",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
|
@ -2189,6 +2189,23 @@
|
||||||
{"wildcard":"accelrec.?.csv" }
|
{"wildcard":"accelrec.?.csv" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{ "id": "accellog",
|
||||||
|
"name": "Acceleration Logger",
|
||||||
|
"shortName":"Accel Log",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"interface": "interface.html",
|
||||||
|
"description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC",
|
||||||
|
"tags": "outdoor",
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"accellog.app.js","url":"app.js"},
|
||||||
|
{"name":"accellog.img","url":"app-icon.js","evaluate":true}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{"wildcard":"accellog.?.csv" }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "cprassist",
|
"id": "cprassist",
|
||||||
"name":"CPR Assist",
|
"name":"CPR Assist",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Acceleration Logger
|
||||||
|
|
||||||
|
Logs XYZ acceleration data (at the normal 12.5Hz) to a CSV file that can be downloaded to your PC.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
* Run the app 'Accel Log' from Bangle.js menu
|
||||||
|
* Optionally choose a file number if you want to record to multiple different files.
|
||||||
|
* Choose `Start`
|
||||||
|
* Acceleration data will now be recording
|
||||||
|
* When you're done, press `BTN2`
|
||||||
|
|
||||||
|
## Downloading Data
|
||||||
|
|
||||||
|
* Go to the Bangle.js App Loader
|
||||||
|
* Connect to your Bangle
|
||||||
|
* Under `My Apps` look for `Acceleration Logger`
|
||||||
|
* You'll see a download arrow next to it - click that
|
||||||
|
* You can now choose to Save or Delete each track you have recorded
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("oFAwhC/AH4A2xAedhGIwA+dAAI+dAAJAcEAJ/fD/4f5hAJIYSo6JIihaKxBATxAACC4YnBAAQ+TD7o/CFRJfTP5a/eb6pEOD/7JFwczAA0ybgwfUkUjD4QaDD6syiMSD4ZABCIa8JD547BCIY/ZHQQ+LD6Z/cHZYf/f6E4D6uCD4gACD6wgBkQACBAYfWABYf/D/4fPwf/ABgf/D6czABBf/P/5f/P/5f/D+WIABwfuAH4A/ADo="))
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
var fileNumber = 0;
|
||||||
|
var MAXLOGS = 9;
|
||||||
|
|
||||||
|
function getFileName(n) {
|
||||||
|
return "accellog."+n+".csv";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMenu() {
|
||||||
|
var menu = {
|
||||||
|
"" : { title : "Accel Logger" },
|
||||||
|
"File No" : {
|
||||||
|
value : fileNumber,
|
||||||
|
min : 0,
|
||||||
|
max : MAXLOGS,
|
||||||
|
onchange : v => { fileNumber=v; }
|
||||||
|
},
|
||||||
|
"Start" : function() {
|
||||||
|
E.showMenu();
|
||||||
|
startRecord();
|
||||||
|
},
|
||||||
|
"View Logs" : function() {
|
||||||
|
viewLogs();
|
||||||
|
},
|
||||||
|
"Exit" : function() {
|
||||||
|
load();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewLog(n) {
|
||||||
|
E.showMessage("Loading...");
|
||||||
|
var f = require("Storage").open(getFileName(n), "r");
|
||||||
|
var records = 0, l = "", ll="";
|
||||||
|
while ((l=f.readLine())!==undefined) {records++;ll=l;}
|
||||||
|
var length = 0;
|
||||||
|
if (ll) length = (ll.split(",")[0]|0)/1000;
|
||||||
|
|
||||||
|
var menu = {
|
||||||
|
"" : { title : "Log "+n }
|
||||||
|
};
|
||||||
|
menu[records+" Records"] = "";
|
||||||
|
menu[length+" Seconds"] = "";
|
||||||
|
menu["DELETE"] = function() {
|
||||||
|
E.showPrompt("Delete Log "+n).then(ok=>{
|
||||||
|
if (ok) {
|
||||||
|
E.showMessage("Erasing...");
|
||||||
|
f.erase();
|
||||||
|
viewLogs();
|
||||||
|
} else viewLog(n);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
menu["< Back"] = function() {
|
||||||
|
viewLogs();
|
||||||
|
};
|
||||||
|
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewLogs() {
|
||||||
|
var menu = {
|
||||||
|
"" : { title : "Logs" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var hadLogs = false;
|
||||||
|
for (var i=0;i<=MAXLOGS;i++) {
|
||||||
|
var f = require("Storage").open(getFileName(i), "r");
|
||||||
|
if (f.readLine()!==undefined) {
|
||||||
|
(function(i) {
|
||||||
|
menu["Log "+i] = () => viewLog(i);
|
||||||
|
})(i);
|
||||||
|
hadLogs = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hadLogs)
|
||||||
|
menu["No Logs Found"] = function(){};
|
||||||
|
menu["< Back"] = function() { showMenu(); };
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startRecord(force) {
|
||||||
|
if (!force) {
|
||||||
|
// check for existing file
|
||||||
|
var f = require("Storage").open(getFileName(fileNumber), "r");
|
||||||
|
if (f.readLine()!==undefined)
|
||||||
|
return E.showPrompt("Overwrite Log "+fileNumber+"?").then(ok=>{
|
||||||
|
if (ok) startRecord(true); else showMenu();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// display
|
||||||
|
g.clear(1);
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
var w = g.getWidth();
|
||||||
|
var h = g.getHeight();
|
||||||
|
g.setColor("#ff0000").fillRect(0,h-48,w,h);
|
||||||
|
g.setColor("#ffffff").setFont("6x8",2).setFontAlign(0,0).drawString("RECORDING", w/2,h-24);
|
||||||
|
g.setFont("6x8").drawString("Samples:",w/2,h/3 - 20);
|
||||||
|
g.setFont("6x8").drawString("Time:",w/2,h*2/3 - 20);
|
||||||
|
g.setFont("6x8",2).setFontAlign(0,0,1).drawString("STOP",w-10,h/2);
|
||||||
|
|
||||||
|
// now start writing
|
||||||
|
f = require("Storage").open(getFileName(fileNumber), "w");
|
||||||
|
f.write("Time (ms),X,Y,Z\n");
|
||||||
|
var start = getTime();
|
||||||
|
var sampleCount = 0;
|
||||||
|
|
||||||
|
function accelHandler(accel) {
|
||||||
|
var t = getTime()-start;
|
||||||
|
f.write([
|
||||||
|
t*1000,
|
||||||
|
accel.x*8192,
|
||||||
|
accel.y*8192,
|
||||||
|
accel.z*8192].map(n=>Math.round(n)).join(",")+"\n");
|
||||||
|
|
||||||
|
sampleCount++;
|
||||||
|
g.reset().setFont("6x8",2).setFontAlign(0,0);
|
||||||
|
g.drawString(" "+sampleCount+" ",w/2,h/3,true);
|
||||||
|
g.drawString(" "+Math.round(t)+"s ",w/2,h*2/3,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.setPollInterval(80); // 12.5 Hz
|
||||||
|
Bangle.on('accel', accelHandler);
|
||||||
|
setWatch(()=>{
|
||||||
|
Bangle.removeListener('accel', accelHandler);
|
||||||
|
showMenu();
|
||||||
|
}, BTN2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
showMenu();
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,107 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="data"></div>
|
||||||
|
|
||||||
|
<script src="../../core/lib/interface.js"></script>
|
||||||
|
<script>
|
||||||
|
var dataElement = document.getElementById("data");
|
||||||
|
|
||||||
|
function getData() {
|
||||||
|
// show loading window
|
||||||
|
Util.showModal("Loading...");
|
||||||
|
// get the data
|
||||||
|
dataElement.innerHTML = "";
|
||||||
|
var promise = Promise.resolve();
|
||||||
|
Puck.eval('require("Storage").list(/accellog\\..\\.csv\\x01/)',files=>{
|
||||||
|
if (files.length==0) {
|
||||||
|
dataElement.innerHTML = "<p>No saved data</p>";
|
||||||
|
} else {
|
||||||
|
files.forEach(fn => {
|
||||||
|
fn = fn.slice(0,-1);
|
||||||
|
dataElement.innerHTML += `
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title h5">${fn}</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button class="btn btn-primary" fn="${fn}" act="save">Save</button>
|
||||||
|
<button class="btn" fn="${fn}" act="delete">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
promise = promise.then(function() {
|
||||||
|
document.querySelector(`.btn[fn='${fn}'][act='save']`).addEventListener("click", function() {
|
||||||
|
Util.readStorageFile(fn, function(data) {
|
||||||
|
Util.saveCSV(fn.slice(0,-4), data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
document.querySelector(`.btn[fn='${fn}'][act='delete']`).addEventListener("click", function() {
|
||||||
|
Util.showModal("Deleting...");
|
||||||
|
Util.eraseStorageFile(fn, function() {
|
||||||
|
Util.hideModal();
|
||||||
|
getData();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return new Promise(resolve=>{
|
||||||
|
Puck.eval(`require("Storage").read(${JSON.stringify(fn)})`,csv=>{
|
||||||
|
fileData[fn] = csv.trim();
|
||||||
|
var el = document.querySelector(`.card-body[fn='${fn}']`);
|
||||||
|
el.innerHTML = '<canvas width="400" height="100"></canvas>';
|
||||||
|
var c = el.firstChild;
|
||||||
|
var ctx = c.getContext("2d");
|
||||||
|
var lines = csv.split("\n");
|
||||||
|
var y = 50, sx = 400/lines.length, sy = 50/8;
|
||||||
|
function plot(n) {
|
||||||
|
var last;
|
||||||
|
ctx.beginPath();
|
||||||
|
lines.map((l,x)=>{
|
||||||
|
l = l.split(",");
|
||||||
|
var yc = y + parseFloat(l[n])*sy;
|
||||||
|
if (!last) {
|
||||||
|
ctx.moveTo(0, yc);
|
||||||
|
} else {
|
||||||
|
ctx.lineTo(x*sx, yc);
|
||||||
|
}
|
||||||
|
last = l;
|
||||||
|
});
|
||||||
|
ctx.stroke();
|
||||||
|
};
|
||||||
|
ctx.strokeStyle = 'red';
|
||||||
|
plot(0);
|
||||||
|
ctx.strokeStyle = 'green';
|
||||||
|
plot(1);
|
||||||
|
ctx.strokeStyle = 'blue';
|
||||||
|
plot(2);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// remove window
|
||||||
|
Util.hideModal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can call a utility function to save the data
|
||||||
|
/*document.getElementById("btnSave").addEventListener("click", function() {
|
||||||
|
Util.saveCSV("gpsdata", csvData);
|
||||||
|
});
|
||||||
|
// Or you can also delete the file
|
||||||
|
document.getElementById("btnDelete").addEventListener("click", function() {
|
||||||
|
Util.showModal("Deleting...");
|
||||||
|
Util.eraseStorageFile("gpspoilog.csv", function() {
|
||||||
|
Util.hideModal();
|
||||||
|
getData();
|
||||||
|
});
|
||||||
|
});*/
|
||||||
|
// Called when app starts
|
||||||
|
function onInit() {
|
||||||
|
getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
# Acceleration Recorder
|
# Acceleration Recorder
|
||||||
|
|
||||||
This app records a short period of acceleration data from the accelerometer
|
This app records a short period of acceleration data from the accelerometer at
|
||||||
and
|
100Hz (starting when acceleration happens) and graphs it, working out max acceleration
|
||||||
|
and max velocity. Data can also be downloaded to your PC.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
0.05: Fix default step/distance display if it hasn't been set up first
|
0.05: Fix default step/distance display if it hasn't been set up first
|
||||||
0.06: Added WIDGETS.activepedom.getSteps()
|
0.06: Added WIDGETS.activepedom.getSteps()
|
||||||
0.07: Added settings to be able to hide line1 and line2 so there is no visible widget
|
0.07: Added settings to be able to hide line1 and line2 so there is no visible widget
|
||||||
|
0.08: Fixed zero steps issue caused by 0.07
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue