Merge branch 'espruino:master' into Weather-Feels-Like-Updates

master
RKBoss6 2025-08-06 13:09:22 -04:00 committed by GitHub
commit 54f8807af8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 1094 additions and 416 deletions

View File

@ -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.

View File

@ -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

View File

@ -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,

View File

@ -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": [

View File

@ -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

View File

@ -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;

View File

@ -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",

View File

@ -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
Add graphs for Steps+Battery
0.48: Add ability to log average acceleration values

View File

@ -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...

File diff suppressed because it is too large Load Diff

View File

@ -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){

View File

@ -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",