diff --git a/apps.json b/apps.json index 1f85d0ec6..2e338a432 100644 --- a/apps.json +++ b/apps.json @@ -4540,5 +4540,22 @@ {"name":"poweroff.app.js","url":"app.js"}, {"name":"poweroff.img","url":"app-icon.js","evaluate":true} ] +}, +{ + "id": "sensible", + "name": "SensiBLE", + "shortName": "SensiBLE", + "version": "0.02", + "description": "Collect, display and advertise real-time sensor data.", + "icon": "sensible.png", + "type": "app", + "tags": "tool,sensors", + "supports" : [ "BANGLEJS2" ], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + { "name": "sensible.app.js", "url": "sensible.js" }, + { "name": "sensible.img", "url": "sensible-icon.js", "evaluate": true } + ] } ] diff --git a/apps/sensible/ChangeLog b/apps/sensible/ChangeLog new file mode 100644 index 000000000..ba597a22f --- /dev/null +++ b/apps/sensible/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Corrected variable initialisation diff --git a/apps/sensible/README.md b/apps/sensible/README.md new file mode 100644 index 000000000..f79b61aea --- /dev/null +++ b/apps/sensible/README.md @@ -0,0 +1,35 @@ +# Sensible + +Collect all the sensor data from the Bangle.js 2, display the live readings in menu pages, and broadcast in Bluetooth Low Energy (BLE) advertising packets to any listening devices in range. + + +## Usage + +The advertising packets will be recognised by [Pareto Anywhere](https://www.reelyactive.com/pareto/anywhere/) open source middleware and any other program which observes the standard packet types. Also convenient for testing individual sensors of the Bangle.js 2 via the menu interface. + + +## Features + +Currently implements: +- Accelerometer +- Barometer +- GPS +- Heart Rate Monitor +- Magnetometer + +in the menu display but NOT YET in Bluetooth Low Energy advertising (which will be implemented in a subsequent version). + + +## Controls + +Browse and control sensors using the standard Espruino menu interface. + + +## Requests + +[Contact reelyActive](https://www.reelyactive.com/contact/) for support/updates. + + +## Creator + +Developed by [jeffyactive](https://github.com/jeffyactive) of [reelyActive](https://www.reelyactive.com) diff --git a/apps/sensible/sensible-icon.js b/apps/sensible/sensible-icon.js new file mode 100644 index 000000000..f904fc7f3 --- /dev/null +++ b/apps/sensible/sensible-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkG/4AG+cilGIxGCkU/B44AGmQUBAAsjCyoYN+QWJAAMvCxsjLQXzG4gYIOIZwG+YLDCw34BRIkFx4JFHQRDElGCJYgOCFw5RCPQwJFGAg4BIoSRIDAQQEG4YLBHgYAGJQIjCJ4RGBDoU4SIqNDwYwDJAQEDFwSRGDAQfBFQgIDFwQtDRoowBAgQDEDYQzC7oACTogrEA4IfF/4WDDAY/Fx4CCEYQbB/oXF74TDCAYGBUoIDDCwowCUoIkBAYSABGwIDCLogADBIKMCAYRODLwRGGJAaMFPwghBnoXJHoJ8DF4Q5DC5HTKogVBgAAFpoXH6oQGAA1dC7/UC5sNC4/dCA0QAwsEC50BC40AC5FQC4sgMB4XFgUwC40FC4/QBwkD+B5HDA6oFh/xSREFqtVbogMEj/yVxkFMwRgEl//Y5sAqhgF///SA4AHghgDgQXBPBAAHrpICh4XBMBoADC4ReBAALxHABUBCwX/bI4AKgYXD+YXRn4XDSKCNDAAZ5QOoZhSLohhESRkBLopJQIo4YOCxYYCJQ0BCxoACmURCoMRkYOI")) \ No newline at end of file diff --git a/apps/sensible/sensible.js b/apps/sensible/sensible.js new file mode 100644 index 000000000..c569ff720 --- /dev/null +++ b/apps/sensible/sensible.js @@ -0,0 +1,162 @@ +/** + * Copyright reelyActive 2021 + * We believe in an open Internet of Things + */ + + +// Non-user-configurable constants +const APP_ID = 'sensible'; + + +// Global variables +let acc, bar, hrm, mag; +let isAccMenu = false; +let isBarMenu = false; +let isGpsMenu = false; +let isHrmMenu = false; +let isMagMenu = false; +let isBarEnabled = true; +let isGpsEnabled = true; +let isHrmEnabled = true; +let isMagEnabled = true; + + +// Menus +let mainMenu = { + "": { "title": "-- SensiBLE --" }, + "Acceleration": function() { E.showMenu(accMenu); isAccMenu = true; }, + "Barometer": function() { E.showMenu(barMenu); isBarMenu = true; }, + "GPS": function() { E.showMenu(gpsMenu); isGpsMenu = true; }, + "Heart Rate": function() { E.showMenu(hrmMenu); isHrmMenu = true; }, + "Magnetometer": function() { E.showMenu(magMenu); isMagMenu = true; } +}; +let accMenu = { + "": { "title" : "- Acceleration -" }, + "State": { value: "On" }, + "x": { value: null }, + "y": { value: null }, + "z": { value: null }, + "<-": function() { E.showMenu(mainMenu); isAccMenu = false; }, +}; +let barMenu = { + "": { "title" : "- Barometer -" }, + "State": { + value: isBarEnabled, + format: v => v ? "On" : "Off", + onchange: v => { isBarEnabled = v; Bangle.setBarometerPower(v, APP_ID); } + }, + "Altitude": { value: null }, + "Press": { value: null }, + "Temp": { value: null }, + "<-": function() { E.showMenu(mainMenu); isBarMenu = false; }, +}; +let gpsMenu = { + "": { "title" : "- GPS -" }, + "State": { + value: isGpsEnabled, + format: v => v ? "On" : "Off", + onchange: v => { isGpsEnabled = v; Bangle.setGPSPower(v, APP_ID); } + }, + "Lat": { value: null }, + "Lon": { value: null }, + "Altitude": { value: null }, + "Satellites": { value: null }, + "HDOP": { value: null }, + "<-": function() { E.showMenu(mainMenu); isGpsMenu = false; }, +}; +let hrmMenu = { + "": { "title" : "- Heart Rate -" }, + "State": { + value: isHrmEnabled, + format: v => v ? "On" : "Off", + onchange: v => { isHrmEnabled = v; Bangle.setHRMPower(v, APP_ID); } + }, + "BPM": { value: null }, + "Confidence": { value: null }, + "<-": function() { E.showMenu(mainMenu); isHrmMenu = false; }, +}; +let magMenu = { + "": { "title" : "- Magnetometer -" }, + "State": { + value: isMagEnabled, + format: v => v ? "On" : "Off", + onchange: v => { isMagEnabled = v; Bangle.setCompassPower(v, APP_ID); } + }, + "x": { value: null }, + "y": { value: null }, + "z": { value: null }, + "Heading": { value: null }, + "<-": function() { E.showMenu(mainMenu); isMagMenu = false; }, +}; + + +// Update acceleration +Bangle.on('accel', function(newAcc) { + acc = newAcc; + + if(isAccMenu) { + accMenu.x.value = acc.x.toFixed(2); + accMenu.y.value = acc.y.toFixed(2); + accMenu.z.value = acc.z.toFixed(2); + E.showMenu(accMenu); + } +}); + +// Update barometer +Bangle.on('pressure', function(newBar) { + bar = newBar; + + if(isBarMenu) { + barMenu.Altitude.value = bar.altitude.toFixed(1) + 'm'; + barMenu.Press.value = bar.pressure.toFixed(1) + 'mbar'; + barMenu.Temp.value = bar.temperature.toFixed(1) + 'C'; + E.showMenu(barMenu); + } +}); + +// Update GPS +Bangle.on('GPS', function(newGps) { + gps = newGps; + + if(isGpsMenu) { + gpsMenu.Lat.value = gps.lat.toFixed(4); + gpsMenu.Lon.value = gps.lon.toFixed(4); + gpsMenu.Altitude.value = gps.alt + 'm'; + gpsMenu.Satellites.value = gps.satellites; + gpsMenu.HDOP.value = (gps.hdop * 5).toFixed(1) + 'm'; + E.showMenu(gpsMenu); + } +}); + +// Update heart rate monitor +Bangle.on('HRM', function(newHrm) { + hrm = newHrm; + + if(isHrmMenu) { + hrmMenu.BPM.value = hrm.bpm; + hrmMenu.Confidence.value = hrm.confidence + '%'; + E.showMenu(hrmMenu); + } +}); + +// Update magnetometer +Bangle.on('mag', function(newMag) { + mag = newMag; + + if(isMagMenu) { + magMenu.x.value = mag.x; + magMenu.y.value = mag.y; + magMenu.z.value = mag.z; + magMenu.Heading.value = mag.heading.toFixed(1); + E.showMenu(magMenu); + } +}); + + +// On start: enable sensors and display main menu +g.clear(); +Bangle.setBarometerPower(isBarEnabled, APP_ID); +Bangle.setGPSPower(isGpsEnabled, APP_ID); +Bangle.setHRMPower(isHrmEnabled, APP_ID); +Bangle.setCompassPower(isMagEnabled, APP_ID); +E.showMenu(mainMenu); \ No newline at end of file diff --git a/apps/sensible/sensible.png b/apps/sensible/sensible.png new file mode 100644 index 000000000..d3e3dfbef Binary files /dev/null and b/apps/sensible/sensible.png differ