diff --git a/apps/impwclock/ChangeLog b/apps/impwclock/ChangeLog index 7bc119426..6555fcc8f 100644 --- a/apps/impwclock/ChangeLog +++ b/apps/impwclock/ChangeLog @@ -2,3 +2,4 @@ 0.02: Stopped watchface from flashing every interval 0.03: Move to Bangle.setUI to launcher support 0.04: Tweaks for compatibility with BangleJS2 +0.05: Time-word now readable on Bangle.js 2 diff --git a/apps/impwclock/clock-impword.js b/apps/impwclock/clock-impword.js index 8bb5da6ba..c42dbda44 100644 --- a/apps/impwclock/clock-impword.js +++ b/apps/impwclock/clock-impword.js @@ -46,7 +46,7 @@ const dy = big ? 22 : 16; const fontSize = big ? 3 : 2; // "6x8" const passivColor = 0x3186 /*grey*/ ; const activeColorNight = 0xF800 /*red*/ ; -const activeColorDay = 0xFFFF /* white */; +const activeColorDay = g.theme.fg; var hidxPrev; var showDigitalTime = false; diff --git a/apps/impwclock/metadata.json b/apps/impwclock/metadata.json index 6bf5183f4..120fbe795 100644 --- a/apps/impwclock/metadata.json +++ b/apps/impwclock/metadata.json @@ -1,7 +1,7 @@ { "id": "impwclock", "name": "Imprecise Word Clock", - "version": "0.04", + "version": "0.05", "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", "icon": "clock-impword.png", "type": "clock", diff --git a/apps/sensible/ChangeLog b/apps/sensible/ChangeLog index 33e44b70c..0699954d7 100644 --- a/apps/sensible/ChangeLog +++ b/apps/sensible/ChangeLog @@ -2,4 +2,5 @@ 0.02: Corrected variable initialisation 0.03: Advertise app name, added screenshots 0.04: Advertise bar, GPS, HRM and mag services -0.05: Refactored for efficiency, corrected sensor value inaccuracies \ No newline at end of file +0.05: Refactored for efficiency, corrected sensor value inaccuracies +0.06: User settings are written to persistent storage, loaded on app start \ No newline at end of file diff --git a/apps/sensible/README.md b/apps/sensible/README.md index fcff3b0f9..8bf21ae8a 100644 --- a/apps/sensible/README.md +++ b/apps/sensible/README.md @@ -5,7 +5,9 @@ Collect all the sensor data from the Bangle.js 2, display the live readings in m ## 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. +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. See our [Bangle.js Development Guide](https://reelyactive.github.io/diy/banglejs-dev/) for details. Also convenient for testing individual sensors of the Bangle.js 2 via the menu interface. + +![SensiBLE in Pareto Anywhere](/BangleApps/apps/sensible/screenshot-pareto-anywhere.png) ## Features @@ -22,7 +24,7 @@ in the menu display, and broadcasts all sensor data readings _except_ accelerati ## Controls -Browse and control sensors using the standard Espruino menu interface. +Browse and control sensors using the standard Espruino menu interface. By default, all sensors _except_ the accelerometer are disabled. Sensors can be individually enabled/disabled via the menu. These settings are written to persistent storage (flash) and will be applied each time the SensiBLE app is loaded. ## Requests diff --git a/apps/sensible/metadata.json b/apps/sensible/metadata.json index df0421441..6715e2538 100644 --- a/apps/sensible/metadata.json +++ b/apps/sensible/metadata.json @@ -1,25 +1,28 @@ { -"id": "sensible", -"name": "SensiBLE", -"shortName": "SensiBLE", -"version": "0.05", -"description": "Collect, display and advertise real-time sensor data.", -"icon": "sensible.png", -"screenshots": [ - { "url": "screenshot-top.png" }, - { "url": "screenshot-acc.png" }, - { "url": "screenshot-bar.png" }, - { "url": "screenshot-gps.png" }, - { "url": "screenshot-hrm.png" }, - { "url": "screenshot-mag.png" } -], -"type": "app", -"tags": "tool,sensors,bluetooth", -"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 } -] + "id": "sensible", + "name": "SensiBLE", + "shortName": "SensiBLE", + "version": "0.06", + "description": "Collect, display and advertise real-time sensor data.", + "icon": "sensible.png", + "screenshots": [ + { "url": "screenshot-top.png" }, + { "url": "screenshot-acc.png" }, + { "url": "screenshot-bar.png" }, + { "url": "screenshot-gps.png" }, + { "url": "screenshot-hrm.png" }, + { "url": "screenshot-mag.png" } + ], + "type": "app", + "tags": "tool,sensors,bluetooth", + "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 } + ], + "data": [ + { "name": "sensible.data.json", "url": "settings.json", "storageFile": true } + ] } diff --git a/apps/sensible/screenshot-pareto-anywhere.png b/apps/sensible/screenshot-pareto-anywhere.png new file mode 100644 index 000000000..c411bca8a Binary files /dev/null and b/apps/sensible/screenshot-pareto-anywhere.png differ diff --git a/apps/sensible/sensible.js b/apps/sensible/sensible.js index 73c348556..8ec7d93d4 100644 --- a/apps/sensible/sensible.js +++ b/apps/sensible/sensible.js @@ -1,5 +1,5 @@ /** - * Copyright reelyActive 2021 + * Copyright reelyActive 2021-2022 * We believe in an open Internet of Things */ @@ -7,6 +7,8 @@ // Non-user-configurable constants const APP_ID = 'sensible'; const ESPRUINO_COMPANY_CODE = 0x0590; +const SETTINGS_FILENAME = 'sensible.data.json'; +const UPDATE_MILLISECONDS = 1000; const APP_ADVERTISING_DATA = [ 0x12, 0xff, 0x90, 0x05, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x7d ]; @@ -19,16 +21,12 @@ let isBarMenu = false; let isGpsMenu = false; let isHrmMenu = false; let isMagMenu = false; -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; - +let settings = require('Storage').readJSON(SETTINGS_FILENAME); // Menus @@ -51,9 +49,9 @@ let accMenu = { let barMenu = { "": { "title" : "- Barometer -" }, "State": { - value: isBarEnabled, + value: settings.isBarEnabled, format: v => v ? "On" : "Off", - onchange: v => { isBarEnabled = v; Bangle.setBarometerPower(v, APP_ID); } + onchange: v => { updateSetting('isBarEnabled', v); } }, "Altitude": { value: null }, "Press": { value: null }, @@ -63,9 +61,9 @@ let barMenu = { let gpsMenu = { "": { "title" : "- GPS -" }, "State": { - value: isGpsEnabled, + value: settings.isGpsEnabled, format: v => v ? "On" : "Off", - onchange: v => { isGpsEnabled = v; Bangle.setGPSPower(v, APP_ID); } + onchange: v => { updateSetting('isGpsEnabled', v); } }, "Lat": { value: null }, "Lon": { value: null }, @@ -77,9 +75,9 @@ let gpsMenu = { let hrmMenu = { "": { "title" : "- Heart Rate -" }, "State": { - value: isHrmEnabled, + value: settings.isHrmEnabled, format: v => v ? "On" : "Off", - onchange: v => { isHrmEnabled = v; Bangle.setHRMPower(v, APP_ID); } + onchange: v => { updateSetting('isHrmEnabled', v); } }, "BPM": { value: null }, "Confidence": { value: null }, @@ -88,9 +86,9 @@ let hrmMenu = { let magMenu = { "": { "title" : "- Magnetometer -" }, "State": { - value: isMagEnabled, + value: settings.isMagEnabled, format: v => v ? "On" : "Off", - onchange: v => { isMagEnabled = v; Bangle.setCompassPower(v, APP_ID); } + onchange: v => { updateSetting('isMagEnabled', v); } }, "x": { value: null }, "y": { value: null }, @@ -124,7 +122,7 @@ function transmitUpdatedSensorData() { isNewMagData = false; } - let interval = 1000 / data.length; + let interval = UPDATE_MILLISECONDS / data.length; NRF.setAdvertising(data, { showName: false, interval: interval }); } @@ -190,6 +188,23 @@ function toByteArray(value, numberOfBytes, isSigned) { } +// Enable the sensors as per the current settings +function enableSensors() { + Bangle.setBarometerPower(settings.isBarEnabled, APP_ID); + Bangle.setGPSPower(settings.isGpsEnabled, APP_ID); + Bangle.setHRMPower(settings.isHrmEnabled, APP_ID); + Bangle.setCompassPower(settings.isMagEnabled, APP_ID); +} + + +// Update the given setting and write to persistent storage +function updateSetting(name, value) { + settings[name] = value; + require('Storage').writeJSON(SETTINGS_FILENAME, settings); + enableSensors(); +} + + // Update acceleration Bangle.on('accel', function(newAcc) { acc = newAcc; @@ -260,9 +275,6 @@ Bangle.on('mag', function(newMag) { // 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); +enableSensors(); E.showMenu(mainMenu); -setInterval(transmitUpdatedSensorData, 1000); \ No newline at end of file +setInterval(transmitUpdatedSensorData, UPDATE_MILLISECONDS); \ No newline at end of file diff --git a/apps/sensible/settings.json b/apps/sensible/settings.json new file mode 100644 index 000000000..90340a201 --- /dev/null +++ b/apps/sensible/settings.json @@ -0,0 +1,6 @@ +{ + "isBarEnabled": false, + "isGpsEnabled": false, + "isHrmEnabled": false, + "isMagEnabled": false +} \ No newline at end of file diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog index 47448167e..dbc3a0b82 100644 --- a/apps/sleepphasealarm/ChangeLog +++ b/apps/sleepphasealarm/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Respect Quiet Mode +0.03: Add compatibility for Bangle.js 2 and new firmware, added "Alarm at " for the alarm time diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index 0de0b9afc..39f9b59db 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -1,3 +1,4 @@ +const BANGLEJS2 = process.env.HWVERSION == 2; //# check for bangle 2 const alarms = require("Storage").readJSON("alarm.json",1)||[]; const active = alarms.filter(a=>a.on); @@ -52,21 +53,21 @@ active.forEach(alarm => { } }); -function drawString(s, x, y) { - g.clearRect(0,y-15,239,y+15); - g.reset(); - g.setFont("Vector",20); - g.setFontAlign(0,0); // align right bottom - g.drawString(s, x, y); +function drawString(s, y) { //# replaced x: always centered + g.reset(); //# moved up to prevent blue background + g.clearRect(0, y - 12, 239, y + 8); //# minimized upper+lower clearing + g.setFont("Vector", 20); + g.setFontAlign(0, 0); // align centered + g.drawString(s, g.getWidth() / 2, y); //# set x to center } function drawApp() { - g.clearRect(0,24,239,215); + g.clearRect(0,24,239,215); //# no problem var alarmHour = nextAlarm.getHours(); var alarmMinute = nextAlarm.getMinutes(); if (alarmHour < 10) alarmHour = "0" + alarmHour; if (alarmMinute < 10) alarmMinute = "0" + alarmMinute; - const s = alarmHour + ":" + alarmMinute + "\n\n"; + const s = "Alarm at " + alarmHour + ":" + alarmMinute + "\n\n"; //# make distinct to time E.showMessage(s, "Sleep Phase Alarm"); function drawTime() { @@ -78,12 +79,20 @@ function drawApp() { if (nowHour < 10) nowHour = "0" + nowHour; if (nowMinute < 10) nowMinute = "0" + nowMinute; if (nowSecond < 10) nowSecond = "0" + nowSecond; - const time = nowHour + ":" + nowMinute + ":" + nowSecond; - drawString(time, 120, 140); + const time = nowHour + ":" + nowMinute + (BANGLEJS2 ? "" : ":" + nowSecond); //# hide seconds on bangle 2 + drawString(time, BANGLEJS2 ? 85 : 105); //# remove x, adjust height for bangle 2 an newer firmware } } - setInterval(drawTime, 500); // 2Hz + if (BANGLEJS2) { + drawTime(); + setTimeout(_ => { + drawTime(); + setInterval(drawTime, 60000); + }, 60000 - Date.now() % 60000); //# every new minute on bangle 2 + } else { + setInterval(drawTime, 500); // 2Hz + } } var buzzCount = 19; @@ -104,8 +113,8 @@ function buzz() { var minAlarm = new Date(); var measure = true; if (nextAlarm !== undefined) { + Bangle.loadWidgets(); //# correct widget load draw order Bangle.drawWidgets(); - Bangle.loadWidgets(); // minimum alert 30 minutes early minAlarm.setTime(nextAlarm.getTime() - (30*60*1000)); @@ -116,7 +125,7 @@ if (nextAlarm !== undefined) { if (swest !== undefined) { if (Bangle.isLCDOn()) { - drawString(swest ? "Sleep" : "Awake", 120, 180); + drawString(swest ? "Sleep" : "Awake", BANGLEJS2 ? 150 : 180); //# remove x, adjust height } } @@ -133,6 +142,6 @@ if (nextAlarm !== undefined) { E.showMessage('No Alarm'); setTimeout(load, 1000); } -// BTN2 to menu, BTN3 to main -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); -setWatch(() => load(), BTN3, { repeat: false, edge: "falling" }); +// BTN2 to menu, BTN3 to main # on bangle 2 only BTN to main +if (!BANGLEJS2) setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +setWatch(() => load(), BANGLEJS2 ? BTN : BTN3, { repeat: false, edge: "falling" }); diff --git a/apps/sleepphasealarm/metadata.json b/apps/sleepphasealarm/metadata.json index f74c97b54..ed0f21028 100644 --- a/apps/sleepphasealarm/metadata.json +++ b/apps/sleepphasealarm/metadata.json @@ -2,11 +2,11 @@ "id": "sleepphasealarm", "name": "SleepPhaseAlarm", "shortName": "SleepPhaseAlarm", - "version": "0.02", + "version": "0.03", "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", "icon": "app.png", "tags": "alarm", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"sleepphasealarm.app.js","url":"app.js"}, {"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true}