diff --git a/apps/ios/ChangeLog b/apps/ios/ChangeLog index 43233dfdf..7952d546b 100644 --- a/apps/ios/ChangeLog +++ b/apps/ios/ChangeLog @@ -19,3 +19,4 @@ 0.18: Fix UTF8 conversion (check for `font` library, not `fonts`) 0.19: Convert numeric weather values to int from BangleDumpWeather shortcut 0.20: Add feels-like temperature data field to weather parsing from BangleDumpWeather shortcut. +0.21: Add BangleDumpLocation shortcut, to update location data on watch without needing to use the watch's GPS, and added more app names/ ids. diff --git a/apps/ios/README.md b/apps/ios/README.md index 79ab1e7a1..dd96b9cd6 100644 --- a/apps/ios/README.md +++ b/apps/ios/README.md @@ -35,20 +35,21 @@ for now. It's just a few bucks/pounds/euro's. If you like to try a free app first, you can always use NRF Toolbox or Bluetooth BLE Device Finder to find and connect your Bangle. -### Weather and Calendar +### Weather, Calendar, and Location -By using the `Shortcuts` app on your phone, you can send weather and calendar data to your watch. This works by sending a notification, which is read by the watch through ANCS. The watch then parses the notification for the data. +By using the `Shortcuts` app on your phone, you can send weather, calendar, and location data to your watch. This works by sending a notification, which is read by the watch through ANCS. The watch then parses the notification for the data. -While you may write your own shortcuts if you prefer (for example, to get weather from a different source), two are provided: +While you may write your own shortcuts if you prefer (for example, to get weather from a different source), three are provided: -- Calendar shortcut: https://www.icloud.com/shortcuts/4eac12548b4c424dbcdb1bd58cff338f -- Weather shortcut: https://www.icloud.com/shortcuts/106c68bfac3746fe9a55761a3be8d092 +- [Calendar shortcut](https://www.icloud.com/shortcuts/4eac12548b4c424dbcdb1bd58cff338f) +- [Weather shortcut](https://www.icloud.com/shortcuts/106c68bfac3746fe9a55761a3be8d092) +- [Location shortcut](https://www.icloud.com/shortcuts/853c41e09a8e491f893a63b464d73ea1) -The weather shortcut requires an OpenWeatherMap api key, which you can get for free from https://openweathermap.org/api. The shortcut will prompt you for this when you add it to your phone. +Note: The shortcuts must keep the names defaulted by the shortcut in order for the watch to detect the weather, calender, or location data. If you rename it from `BangleDump...` to something else, it will no longer get the info, and just display it as a notification on the watch. These shortcuts can also be automated to run periodically, for example every hour, using the `Automation` tab in the Shortcuts app. -The shortcuts will send a notification, which can be annoying. One potential workaround for this would be to create a focus mode, and have an automation: +The shortcuts will send a notification. Even though the notification is deleted as soon as Bangle.js receives it, it can be quite annoying. One potential workaround for this would be to create a focus mode, and have an automation: - activate the focus mode (hiding notifications from the shortcut) - run the shortcut - deactivate the focus mode @@ -60,4 +61,9 @@ Please file any issues on https://github.com/espruino/BangleApps/issues/new?titl ## Creator -Gordon Williams +- Gordon Williams + +## Contributors + +- RKBoss6 +- stweedo diff --git a/apps/ios/boot.js b/apps/ios/boot.js index 32fda1380..e3b6fa677 100644 --- a/apps/ios/boot.js +++ b/apps/ios/boot.js @@ -78,28 +78,56 @@ E.on('notify',msg=>{ "com.apple.reminders": "Reminders", "com.apple.shortcuts": "Shortcuts", "com.apple.TestFlight": "TestFlight", - "com.apple.ScreenTimeNotifications": "ScreenTime", + "com.apple.ScreenTimeNotifications": "Screen Time", "com.apple.wifid.usernotification": "WiFi", + "com.apple.Maps": "Maps", + "com.apple.Music": "Apple Music", + "com.apple.AppStore": "App Store", + "com.apple.Preferences": "Settings", + "com.apple.calculator": "Calculator", + "com.apple.camera": "Camera", + "com.apple.weather": "Weather", + "com.apple.VoiceMemos": "Voice Memos", + "com.apple.News": "News", + "com.apple.tv": "Apple TV", + "com.apple.findmy": "Find My", + "com.apple.compass": "Compass", + "com.apple.measure": "Measure", "com.atebits.Tweetie2": "Twitter", - "com.burbn.instagram" : "Instagram", + "com.burbn.instagram": "Instagram", "com.facebook.Facebook": "Facebook", "com.facebook.Messenger": "Messenger", - "com.google.Chromecast" : "Google Home", - "com.google.Gmail" : "GMail", - "com.google.hangouts" : "Hangouts", - "com.google.ios.youtube" : "YouTube", - "com.hammerandchisel.discord" : "Discord", - "com.ifttt.ifttt" : "IFTTT", - "com.jumbo.app" : "Jumbo", - "com.linkedin.LinkedIn" : "LinkedIn", + "com.google.Chromecast": "Google Home", + "com.google.Gmail": "GMail", + "com.google.hangouts": "Hangouts", + "com.google.ios.youtube": "YouTube", + "com.google.ios.chrome": "Google Chrome", + "com.google.Maps": "Google Maps", + "com.google.Drive": "Google Drive", + "com.google.GoogleMobile": "Google", + "com.hammerandchisel.discord": "Discord", + "com.ifttt.ifttt": "IFTTT", + "com.jumbo.app": "Jumbo", + "com.linkedin.LinkedIn": "LinkedIn", "com.marktplaats.iphone": "Marktplaats", - "com.microsoft.Office.Outlook" : "Outlook Mail", - "com.nestlabs.jasper.release" : "Nest", - "com.netflix.Netflix" : "Netflix", - "com.reddit.Reddit" : "Reddit", + "com.microsoft.Office.Outlook": "Outlook Mail", + "com.microsoft.Office.Word": "Microsoft Word", + "com.microsoft.Office.Excel": "Microsoft Excel", + "com.microsoft.Office.Powerpoint": "Microsoft PowerPoint", + "com.nestlabs.jasper.release": "Nest", + "com.netflix.Netflix": "Netflix", + "com.reddit.Reddit": "Reddit", "com.skype.skype": "Skype", "com.skype.SkypeForiPad": "Skype", "com.spotify.client": "Spotify", + "com.soundcloud.TouchApp": "SoundCloud", + "com.disney.disneyplus": "Disney+", + "com.hbo.hbonow": "HBO Max", + "com.amazon.Amazon": "Amazon Shopping", + "com.amazon.AmazonVideo": "Prime Video", + "com.dropbox.Dropbox": "Dropbox", + "com.evernote.iPhone.Evernote": "Evernote", + "com.trello": "Trello", "com.storytel.iphone": "Storytel", "com.strava.stravaride": "Strava", "com.tinyspeck.chatlyio": "Slack", @@ -110,20 +138,22 @@ E.on('notify',msg=>{ "com.valvesoftware.Steam": "Steam", "com.vilcsak.bitcoin2": "Coinbase", "com.wordfeud.free": "WordFeud", - "com.yourcompany.PPClient": "PayPal", + "com.paypal.PPClient": "PayPal", "com.zhiliaoapp.musically": "TikTok", + "com.pinterest": "Pinterest", + "com.tumblr.tumblr": "Tumblr", "de.no26.Number26": "N26", "io.robbie.HomeAssistant": "Home Assistant", "net.superblock.Pushover": "Pushover", "net.weks.prowl": "Prowl", "net.whatsapp.WhatsApp": "WhatsApp", - "nl.ah.Appie": "Albert Heijn", "nl.postnl.TrackNTrace": "PostNL", "org.whispersystems.signal": "Signal", "ph.telegra.Telegraph": "Telegram", - "tv.twitch": "Twitch", - // could also use NRF.ancsGetAppInfo(msg.appId) here - }; + "tv.twitch": "Twitch" +}; + + //if (appNames[msg.appId]) msg.a if (msg.title === "BangleDumpCalendar") { @@ -191,7 +221,7 @@ E.on('notify',msg=>{ wind: d.wind, wdir: d.wdir, loc: d.loc - } + }; // Convert string fields to numbers for iOS weather shortcut const numFields = ['code', 'wdir', 'temp','feels', 'hi', 'lo', 'hum', 'wind', 'uv', 'rain']; numFields.forEach(field => { @@ -201,6 +231,47 @@ E.on('notify',msg=>{ NRF.ancsAction(msg.uid, false); return; } + + if (msg.title === "BangleDumpLocation") { + + const d = JSON.parse(msg.message); + + /* Example: + {"lat":"2912.0744", "lon":"2333.332", "city":"Chicago"}*/ + let locationJson = { + t: "location", + lat:d.lat, + lon:d.lon, + city:d.city + + }; + // Convert string fields to numbers + const numFields = ['lat', 'lon']; + numFields.forEach(field => { + if (locationJson[field] != null) locationJson[field] = +locationJson[field]; + }); + + //load mylocation file + let myLocationJson = Object.assign({ + lat: d.lat, + lon: d.lon, + location:d.city + }, require("Storage").readJSON("mylocation.json", true) || {}); + //remove notification from phone + NRF.ancsAction(msg.uid, false); + if(Math.abs(myLocationJson.lat - locationJson.lat) < 0.0001 && Math.abs(myLocationJson.lon -locationJson.lon) < 0.0001){ + //same location, do not write + return; + } + + myLocationJson.lon=locationJson.lon; + myLocationJson.lat=locationJson.lat; + myLocationJson.location=locationJson.city; + require("Storage").write("mylocation.json",myLocationJson); + + + return; + } require("messages").pushMessage({ t : msg.event, diff --git a/apps/ios/metadata.json b/apps/ios/metadata.json index c18fa7002..b549abb4c 100644 --- a/apps/ios/metadata.json +++ b/apps/ios/metadata.json @@ -1,11 +1,12 @@ { "id": "ios", "name": "iOS Integration", - "version": "0.20", - "description": "Display/pull notifications, music, weather, and agenda from iOS devices", + "version": "0.21", + "description": "Display/pull notifications, music, weather, location, and agenda from iOS devices", "icon": "app.png", "tags": "tool,system,ios,apple,messages,notifications", "dependencies": {"messages":"module"}, + "dependencies" : {"mylocation":"app" }, "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ diff --git a/apps/powermanager/ChangeLog b/apps/powermanager/ChangeLog index d5abdc79b..d660ed56d 100644 --- a/apps/powermanager/ChangeLog +++ b/apps/powermanager/ChangeLog @@ -14,3 +14,4 @@ Log additional timestamp for trace log 0.11: Minor code improvements 0.12: Round monotonic percentage, rename to stable percentage/voltage +0.13: Fix stable percentage not updating diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js index 64267daa7..898b75cbc 100644 --- a/apps/powermanager/boot.js +++ b/apps/powermanager/boot.js @@ -3,7 +3,7 @@ require('Storage').readJSON("powermanager.default.json", true) || {}, require('Storage').readJSON("powermanager.json", true) || {} ); - + if (settings.log) { let logFile = require('Storage').open("powermanager.log","a"); let def = require('Storage').readJSON("powermanager.def.json", true) || {}; @@ -12,7 +12,7 @@ let hw = require('Storage').readJSON("powermanager.hw.json", true) || {}; if (!hw.start) hw.start = Date.now(); if (!hw.power) hw.power = {}; - + const saveEvery = 1000 * 60 * 5; const TO_WRAP = ["GPS","Compass","Barometer","HRM","LCD"]; @@ -28,9 +28,7 @@ require('Storage').writeJSON("powermanager.hw.json", hw); } } - - - + setInterval(save, saveEvery); E.on("kill", ()=>{ @@ -77,7 +75,6 @@ })(Bangle[functionName]); } - let wrapDeferred = ((o,t) => (a) => { if (a == eval || typeof a == "string") { return o.apply(this, arguments); @@ -133,25 +130,19 @@ handleCharging(Bangle.isCharging()); } - var savedBatPercent=E.getBattery(); if (settings.forceMonoPercentage){ - var newPercent =Math.round((E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery())/6); - + var p = Math.round((E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery())/4); + var op = E.getBattery; E.getBattery = function() { - - if(Bangle.isCharging()){ - if(newPercent > savedBatPercent) - savedBatPercent = newPercent; - }else{ - if(newPercent < savedBatPercent) - savedBatPercent = newPercent; - } - return savedBatPercent; - }; + var current = Math.round((op()+op()+op()+op())/4); + if (Bangle.isCharging() && current > p) p = current; + if (!Bangle.isCharging() && current < p) p = current; + return p; + }; } if (settings.forceMonoVoltage){ - var v = (NRF.getBattery()+NRF.getBattery()+NRF.getBattery()+NRF.getBattery()+NRF.getBattery()+NRF.getBattery())/6; + var v = (NRF.getBattery()+NRF.getBattery()+NRF.getBattery()+NRF.getBattery())/4; var ov = NRF.getBattery; NRF.getBattery = function() { var current = (ov()+ov()+ov()+ov())/4; diff --git a/apps/powermanager/metadata.json b/apps/powermanager/metadata.json index fed7e3bb3..49c77c9d8 100644 --- a/apps/powermanager/metadata.json +++ b/apps/powermanager/metadata.json @@ -2,7 +2,7 @@ "id": "powermanager", "name": "Power Manager", "shortName": "Power Manager", - "version": "0.12", + "version": "0.13", "description": "Allow configuration of warnings for battery charging, stabilization of voltage, stabilization of battery percentage, and battery logging.", "icon": "app.png", "type": "bootloader", diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index f5c0803bb..8042370f9 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -60,4 +60,5 @@ Lower accuracy of barometer data to ~1cm (saves about 15b/record) 0.47: Fix 'blip' on speed map on some recordings Ensure Battery voltage is only stored to 0.01v - Add graphs for Steps+Battery \ No newline at end of file + Add graphs for Steps+Battery +0.48: Add ability to log average acceleration values \ No newline at end of file diff --git a/apps/recorder/README.md b/apps/recorder/README.md index 9c283bb7e..52e598d93 100644 --- a/apps/recorder/README.md +++ b/apps/recorder/README.md @@ -19,6 +19,7 @@ You can record * **BAT** Battery percentage and voltage * **Steps** Steps counted by the step counter * **Baro** (Bangle.js 2) Using the built-in barometer to record Temperature, Pressure and Altitude +* **Accel** Average acceleration values in X,Y and Z * **Core** CoreTemp body temperature *if* you have a CoreTemp device and the https://banglejs.com/apps/?id=coretemp app installed You can then start/stop recording from the Recorder app itself (and as long as widgets are @@ -29,12 +30,29 @@ Some apps like the [Run app](https://banglejs.com/apps/?id=run) are able to auto as well. They need to define a `foobar.recorder.js` file - see the `getRecorders` function in `lib.js` for more information. -## Graphing +## Viewing and Downloading Data -You can download the information to the PC using [the App Loader](https://banglejs.com/apps/?id=recorder). Connect -to your Bangle, then in `My Apps` click the disk icon next to the `Recorder` app to download data. +You can download and visualize the information using [the App Loader](https://banglejs.com/apps/?id=recorder). Connect +to your Bangle, then in `My Apps` click the disk icon next to the `Recorder` app to access the download interface. -You can also view some information on the watch. +### Interactive Web Interface + +The download interface provides individual track visualization with: + +* **Interactive Leaflet maps** - Each GPS track gets its own map using OpenStreetMap tiles +* **Track statistics** - Distance, duration, and track points automatically calculated +* **Start/End markers** - Green circles mark track start, red circles mark end points +* **Interactive track points** - Click anywhere along the GPS track to see detailed data at that point +* **Data popups** - View available data for each point (time, heart rate, altitude, speed, steps, battery, barometer - if recorded) +* **Interactive charts** - Collapsible graphs for heart rate, battery, steps, elevation, speed, and barometer data with PNG export +* **Download options** - KML, GPX, and CSV formats for individual tracks or all at once +* **Settings** - Option to include/exclude entries without GPS coordinates +* **Unit preferences** - Choose between metric, imperial, or auto-detect based on your locale +* **Mobile responsive** - Works well on all devices + +### On-Watch Visualization + +You can also view some information on the watch: * Tap `View Tracks` * Tap on the Track number you're interested in, and you'll see a page with information about that track... diff --git a/apps/recorder/interface.html b/apps/recorder/interface.html index 63f2d0482..5b8ff0b88 100644 --- a/apps/recorder/interface.html +++ b/apps/recorder/interface.html @@ -1,359 +1,925 @@ - -
- - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/apps/recorder/lib.js b/apps/recorder/lib.js index b0f05ead4..6d17c3942 100644 --- a/apps/recorder/lib.js +++ b/apps/recorder/lib.js @@ -114,6 +114,28 @@ exports.getRecorders = function() { stop : () => {}, draw : (x,y) => g.reset().drawImage(atob("DAwBAAMMeeeeeeeecOMMAAMMMMAA"),x,y) }; + }, + accel:function() { + var ax=0,ay=0,az=0,n=0; + function onAccel(a) { + ax += a.x; + ay += a.y; + az += a.z; + n++; + } + return { + name : "Accel", + fields : ["Accel X", "Accel Y", "Accel Z"], + getValues : () => { + if (n<1) n=1; + var r = [(ax/n).toFixed(2), (ay/n).toFixed(2), (az/n).toFixed(2)]; + n = ax = ay = az = 0; + return r; + }, + start : () => { Bangle.on('accel', onAccel); }, + stop : () => { Bangle.removeListener('accel', onAccel); }, + draw : (x,y) => g.reset().drawImage(atob("DAwBAAMMeeeeeeeecOMMAAMMMMAA"),x,y) + }; } }; if (Bangle.getPressure){ diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 2d7e54bdd..7d8251a6c 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.47", + "version": "0.48", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget,clkinfo",