forked from FOSS/BangleApps
Merge branch 'espruino:master' into master
commit
66ec62f0d1
|
@ -4649,7 +4649,7 @@
|
|||
"id": "sensible",
|
||||
"name": "SensiBLE",
|
||||
"shortName": "SensiBLE",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Collect, display and advertise real-time sensor data.",
|
||||
"icon": "sensible.png",
|
||||
"screenshots": [
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Corrected variable initialisation
|
||||
0.03: Advertise app name, added screenshots
|
||||
0.04: Advertise bar, GPS, HRM and mag services
|
||||
|
|
|
@ -17,7 +17,7 @@ Currently implements:
|
|||
- Heart Rate Monitor
|
||||
- Magnetometer
|
||||
|
||||
in the menu display but NOT YET in Bluetooth Low Energy advertising (which will be implemented in a subsequent version).
|
||||
in the menu display, and broadcasts all sensor data readings _except_ acceleration in Bluetooth Low Energy advertising packets as GATT characteristic services.
|
||||
|
||||
|
||||
## Controls
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
// Non-user-configurable constants
|
||||
const APP_ID = 'sensible';
|
||||
const ESPRUINO_COMPANY_CODE = 0x0590;
|
||||
const APP_ADVERTISING_DATA = [ 0x12, 0xff, 0x90, 0x05, 0x7b, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x3a, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x62,
|
||||
0x6c, 0x65, 0x7d ];
|
||||
|
||||
|
||||
// Global variables
|
||||
|
@ -20,6 +23,12 @@ let isBarEnabled = true;
|
|||
let isGpsEnabled = true;
|
||||
let isHrmEnabled = true;
|
||||
let isMagEnabled = true;
|
||||
let isNewAccData = false;
|
||||
let isNewBarData = false;
|
||||
let isNewGpsData = false;
|
||||
let isNewHrmData = false;
|
||||
let isNewMagData = false;
|
||||
|
||||
|
||||
|
||||
// Menus
|
||||
|
@ -91,22 +100,121 @@ let magMenu = {
|
|||
};
|
||||
|
||||
|
||||
// Transmit the app name under the Espruino company code to facilitate discovery
|
||||
function transmitAppName() {
|
||||
let options = {
|
||||
showName: false,
|
||||
manufacturer: ESPRUINO_COMPANY_CODE,
|
||||
manufacturerData: JSON.stringify({ name: APP_ID }),
|
||||
interval: 2000
|
||||
// Check for new sensor data and update the advertising sequence
|
||||
function transmitUpdatedSensorData() {
|
||||
let data = [ APP_ADVERTISING_DATA ]; // Always advertise at least app name
|
||||
|
||||
if(isNewBarData) {
|
||||
data.push(encodeBarServiceData());
|
||||
isNewBarData = false;
|
||||
}
|
||||
|
||||
NRF.setAdvertising({}, options);
|
||||
if(isNewGpsData && gps.lat && gps.lon) {
|
||||
data.push(encodeGpsServiceData());
|
||||
isNewGpsData = false;
|
||||
}
|
||||
|
||||
if(isNewHrmData) {
|
||||
data.push({ 0x2a37: [ 0, hrm.bpm ] });
|
||||
isNewHrmData = false;
|
||||
}
|
||||
|
||||
if(isNewMagData) {
|
||||
data.push(encodeMagServiceData());
|
||||
isNewMagData = false;
|
||||
}
|
||||
|
||||
NRF.setAdvertising(data, { showName: false, interval: 200 });
|
||||
}
|
||||
|
||||
|
||||
// Encode the bar service data to fit in a Bluetooth PDU
|
||||
function encodeBarServiceData() {
|
||||
let tEncoded = Math.round(bar.temperature * 100);
|
||||
let pEncoded = Math.round(bar.pressure * 100);
|
||||
let eEncoded = Math.round(bar.altitude * 100);
|
||||
|
||||
if(bar.temperature < 0) {
|
||||
tEncoded += 0x10000;
|
||||
}
|
||||
if(bar.altitude < 0) {
|
||||
eEncoded += 0x1000000;
|
||||
}
|
||||
|
||||
let t = [ tEncoded & 0xff, (tEncoded >> 8) & 0xff ];
|
||||
let p = [ pEncoded & 0xff, (pEncoded >> 8) & 0xff, (pEncoded >> 16) & 0xff,
|
||||
(pEncoded >> 24) & 0xff ];
|
||||
let e = [ eEncoded & 0xff, (eEncoded >> 8) & 0xff, (eEncoded >> 16) & 0xff ];
|
||||
|
||||
return [
|
||||
0x02, 0x01, 0x06, // Flags
|
||||
0x05, 0x16, 0x6e, 0x2a, t[0], t[1], // Temperature
|
||||
0x07, 0x16, 0x6d, 0x2a, p[0], p[1], p[2], p[3], // Pressure
|
||||
0x06, 0x16, 0x6c, 0x2a, e[0], e[1], e[2] // Elevation
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// Encode the GPS service data using the Location and Speed characteristic
|
||||
function encodeGpsServiceData() {
|
||||
let latEncoded = Math.round(gps.lat * 10000000);
|
||||
let lonEncoded = Math.round(gps.lon * 10000000);
|
||||
let hEncoded = Math.round(gps.course * 100);
|
||||
let sEncoded = Math.round(1000 * gps.speed / 36);
|
||||
|
||||
if(gps.lat < 0) {
|
||||
latEncoded += 0x100000000;
|
||||
}
|
||||
if(gps.lon < 0) {
|
||||
lonEncoded += 0x100000000;
|
||||
}
|
||||
|
||||
let s = [ sEncoded & 0xff, (sEncoded >> 8) & 0xff ];
|
||||
let lat = [ latEncoded & 0xff, (latEncoded >> 8) & 0xff,
|
||||
(latEncoded >> 16) & 0xff, (latEncoded >> 24) & 0xff ];
|
||||
let lon = [ lonEncoded & 0xff, (lonEncoded >> 8) & 0xff,
|
||||
(lonEncoded >> 16) & 0xff, (lonEncoded >> 24) & 0xff ];
|
||||
let h = [ hEncoded & 0xff, (hEncoded >> 8) & 0xff ];
|
||||
|
||||
return [
|
||||
0x02, 0x01, 0x06, // Flags
|
||||
0x11, 0x16, 0x67, 0x2a, 0x95, 0x02, s[0], s[1], lat[0], lat[1], lat[2],
|
||||
lat[3], lon[0], lon[1], lon[2], lon[3], h[0], h[1] // Location and Speed
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// Encode the mag service data using the magnetic flux density 3D characteristic
|
||||
function encodeMagServiceData() {
|
||||
let xEncoded = mag.x; // TODO: units???
|
||||
let yEncoded = mag.y;
|
||||
let zEncoded = mag.z;
|
||||
|
||||
if(xEncoded < 0) {
|
||||
xEncoded += 0x10000;
|
||||
}
|
||||
if(yEncoded < 0) {
|
||||
yEncoded += 0x10000;
|
||||
}
|
||||
if(yEncoded < 0) {
|
||||
yEncoded += 0x10000;
|
||||
}
|
||||
|
||||
let x = [ xEncoded & 0xff, (xEncoded >> 8) & 0xff ];
|
||||
let y = [ yEncoded & 0xff, (yEncoded >> 8) & 0xff ];
|
||||
let z = [ zEncoded & 0xff, (zEncoded >> 8) & 0xff ];
|
||||
|
||||
return [
|
||||
0x02, 0x01, 0x06, // Flags
|
||||
0x09, 0x16, 0xa1, 0x2a, x[0], x[1], y[0], y[1], z[0], z[1] // Mag 3D
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// Update acceleration
|
||||
Bangle.on('accel', function(newAcc) {
|
||||
acc = newAcc;
|
||||
isNewAccData = true;
|
||||
|
||||
if(isAccMenu) {
|
||||
accMenu.x.value = acc.x.toFixed(2);
|
||||
|
@ -119,6 +227,7 @@ Bangle.on('accel', function(newAcc) {
|
|||
// Update barometer
|
||||
Bangle.on('pressure', function(newBar) {
|
||||
bar = newBar;
|
||||
isNewBarData = true;
|
||||
|
||||
if(isBarMenu) {
|
||||
barMenu.Altitude.value = bar.altitude.toFixed(1) + 'm';
|
||||
|
@ -131,6 +240,7 @@ Bangle.on('pressure', function(newBar) {
|
|||
// Update GPS
|
||||
Bangle.on('GPS', function(newGps) {
|
||||
gps = newGps;
|
||||
isNewGpsData = true;
|
||||
|
||||
if(isGpsMenu) {
|
||||
gpsMenu.Lat.value = gps.lat.toFixed(4);
|
||||
|
@ -145,6 +255,7 @@ Bangle.on('GPS', function(newGps) {
|
|||
// Update heart rate monitor
|
||||
Bangle.on('HRM', function(newHrm) {
|
||||
hrm = newHrm;
|
||||
isNewHrmData = true;
|
||||
|
||||
if(isHrmMenu) {
|
||||
hrmMenu.BPM.value = hrm.bpm;
|
||||
|
@ -156,6 +267,7 @@ Bangle.on('HRM', function(newHrm) {
|
|||
// Update magnetometer
|
||||
Bangle.on('mag', function(newMag) {
|
||||
mag = newMag;
|
||||
isNewMagData = true;
|
||||
|
||||
if(isMagMenu) {
|
||||
magMenu.x.value = mag.x;
|
||||
|
@ -169,9 +281,9 @@ Bangle.on('mag', function(newMag) {
|
|||
|
||||
// On start: enable sensors and display main menu
|
||||
g.clear();
|
||||
transmitAppName();
|
||||
Bangle.setBarometerPower(isBarEnabled, APP_ID);
|
||||
Bangle.setGPSPower(isGpsEnabled, APP_ID);
|
||||
Bangle.setHRMPower(isHrmEnabled, APP_ID);
|
||||
Bangle.setCompassPower(isMagEnabled, APP_ID);
|
||||
E.showMenu(mainMenu);
|
||||
E.showMenu(mainMenu);
|
||||
setInterval(transmitUpdatedSensorData, 1000);
|
Loading…
Reference in New Issue