Bangle.js Data Storage (using interface.html)
In Bangle.js you may often want to store data over time, and then recall it later on your PC. In this tutorial we'll talk about how to do that.
There's a more general tutorial about storing data on Espruino as well.
We'll assume you've been through creating an app already so you know what's involved in creating one.
For this example, we're just going to have a menu that lets you write your current
GPS location and time to a file along with a name (for example you could mark the
location of every tree you find by standing by it and choosing Add Tree
).
Note: We've already added a gpspoilog
to the App Loader
for you, so while you can upload this code yourself you'll find it is already all available
for you.
Watch App
This is the code for the app - the majority of it is just creating the menu:
var menuItems = {
"":{title:"GPS POI Log"},
" ":{value:"No Fix"},
"Add Tree" : ()=>addItem("Tree"),
"Add Gate" : ()=>addItem("Gate"),
"Add Flower" : ()=>addItem("Flower"),
"Add Plant" : ()=>addItem("Plant")
};
var menu = E.showMenu(menuItems);
var gps = { fix : 0};
var gpsCount = 0;
// Create the file in append mode
var file = require("Storage").open("gpspoilog.csv","a");
function setStatus(msg) {
menuItems[" "].value = msg;
menu.draw();
}
Bangle.on('GPS',function(g) {
gps = g;
gpsCount++;
var msg;
if (g.fix) {
msg = g.satellites + " Satellites";
} else {
msg = "No Fix";
}
setStatus(" "+"-\\|/"[gpsCount&3]);
});
function addItem(name) {
if (!gps.fix) {
setStatus("Ignored - no fix");
return; // don't do anything as no fix
}
// The fields we want to put in out CSV file
var csv = [
0|getTime(), // Time to the nearest second
gps.lat,
gps.lon,
gps.alt,
name
];
// Write data here
file.write(csv.join(",")+"\n");
setStatus("Written");
}
Bangle.loadWidgets();
Bangle.drawWidgets();
Bangle.setGPSPower(1);
First we need to open a file, which is done with this line:
var file = require("Storage").open("gpspoilog.csv","a");
This opens a file in append
(a
) mode. If it doesn't exist, it is created
empty, but if it does then subsequent writes will go on the end.
And now, we just need to write data into the file in addItem
using
file.write
:
file.write(csv.join(",")+"\n");
A few things are going on here:
csv
is an array, so we convert it to a string usingjoin
, which adds all elements together with a comma between them.write
doesn't add a newline, so we need to add one with\n
so we can read the data line by line later.write
also can't currently write the character code 255 ("\xff"
) in files, so you need to stick to writing text, not binary data.write
writes data as soon as it is called - there's no need toclose
a file when you're finished.- A file created with
require("Storage").open
is different to one created withrequire("Storage").write
since it is designed to be appended to. As such you can only access the files withrequire("Storage").open
and not withrequire("Storage").write/read/erase/etc
Ok, now this is sorted, you can upload the app, run it, and get some data:
- Open the Web IDE and connect to your Bangle
- Click the down-arrow by the Upload button, choose
Storage
,New File
, and entergpspoilog.app.js
as the name. - Click the Upload button to uplaod the app
- Now copy/paste the following into the IDE on the left-hand side. This will create a listing for your app in the Launcher without you having to upload it via the app store:
require("Storage").write("gpspoilog.info",{
"id":"gpspoilog",
"name":"GPS POI Log",
"src":"gpspoilog.app.js"
});
Now, you can go for a walk - when you have a GPS signal you can start logging
some data by choosing Add Plant
, etc from the menu.
Reading the data
With the IDE
The easiest way to read the data is to open the file in the Web IDE. This may be enough for many of you:
- Click the Storage icon in the middle of the screen (4 discs)
- Click the 'eye' icon next to
gpspoilog.csv (StorageFile)
in the window - You should now see the file contents, and you can save this to a file if you wish.
In the app
You can access the data programmatically - either reading in chunks or line by line.
For example this code will write one line at a time:
var f = require("Storage").open("gpspoilog.csv","r");
var l = f.readLine();
while (l!==undefined) {
console.log(l);
l = f.readLine();
}
Reading with the App Loader
However, you can also add the loading functionality to the App Loader itself.
First, we'll need to add the app. This is basically as documented in
Adding an app to the Bangle.js App Loader with one extra
addition - a "interface"
element in the JSON.
- Set up your own App loader as described here
- Copy the directory
apps/_example_app
toapps/gpspoilog
- Write the JS file above over the top of
apps/gpspoilog/app.js
- Change
metadata.json
, as shown:
{ "id": "gpspoilog",
"name": "GPS POI Logger",
"shortName":"GPS POI Log",
"icon": "app.png",
"version":"0.01",
"description": "A way to log points of interest with their GPS coordinates",
"tags": "outdoors",
"interface": "interface.html",
"storage": [
{"name":"gpspoilog.app.js","url":"app.js"},
{"name":"gpspoilog.img","url":"app-icon.js","evaluate":true}
]
}
Now you need to add the 'interface' file - copy the following to apps/gpspoilog/interface.html
.
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<div id="data"></div>
<button class="btn btn-default" id="btnSave">Save</button>
<button class="btn btn-default" id="btnDelete">Delete</button>
<script src="../../core/lib/interface.js"></script>
<script>
var dataElement = document.getElementById("data");
var csvData = "";
function getData() {
// show loading window
Util.showModal("Loading...");
// get the data
dataElement.innerHTML = "";
Util.readStorageFile(`gpspoilog.csv`,data=>{
csvData = data.trim();
// remove window
Util.hideModal();
// If no data, report it and exit
if (data.length==0) {
dataElement.innerHTML = "<b>No data found</b>";
return;
}
// Otherwise parse the data and output it as a table
dataElement.innerHTML = `<table>
<tr>
<th>Time</th>
<th>Lat</th>
<th>Lon</th>
<th>Alt</th>
<th>Type</th>
</tr>`+data.trim().split("\n").map(l=>{
l = l.split(",");
return `<tr>
<td>${(new Date(l[0]*1000)).toLocaleString()}</td>
<td>${l[1]}</td>
<td>${l[2]}</td>
<td>${l[3]}</td>
<td>${l[4]}</td>
</tr>`
}).join("\n")+"</table>";
});
}
// 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>
This does a few basic things:
onInit
is called when the page loadsgetData
grabs the data from the watchUtil.showModal
displays a status screen when things are happeningUtil.readStorageFile
reads the Storage file from the Bangle and returns a string containing its contentsUtil.saveCSV
can pop up a save dialogUtil.eraseStorageFile
erases the file
For more information about the available functions you can check out the interface.js file.
To use your new interface HTML file:
- view your personal App Loader site
- Click
Connect
up the top right - Click
My Apps
- Next to
GPS POI Logger
there's a down arrow icon. Click it - It'll pop up a
GPS POI Logger
showing you the data you recorded - You can now save the data or delete it from the Bangle
And that's it! When you have it working as you want you can even submit it to the official App Loader site
This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.