Skip to content
Merged
20 changes: 20 additions & 0 deletions apps/phoneremind/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Phone Reminder
This app detects when bluetooth disconnects from the watch and shows you a prompt so you can check if you left your phone behind.
When the prompt shows, you can choose to set the location you are currently at as a familiar location, so it won't alert you whenever you are nearby.

This app uses the `MyLocation` app. To set up dynamic location updating with an iOS device, you can use the `BangleDumpLocation` shortcut to push the lcoation.
For more information on automating this and setup, look [here.](https://banglejs.com/apps/?id=ios&readme)

This app does not use the watch GPS.

## Settings
* <b>Precision</b> - Change how close you need to be to a familiar location in order for it to not alert you.
* <b>Check Delay</b> - Change how long after the phone is disconnected that it alerts you. If your phone randomly disconnects and then reconnects, adjusting this value will ensure it does not get triggered until that time is up and it is still disconnected.
* <b>Delete Locations</b> - Deletes all familiar locations.

## TODO
- Add a setting to use watch GPS to get the location instead of myLocation.
- Make a way to save phone MAC address to know what device is connected

## Creator
RKBoss6
129 changes: 129 additions & 0 deletions apps/phoneremind/boot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{
let locationsFile = "phoneremind.json";
let connected;
let buzzInterval;
let promptShown = false;
let addLocation = function (location) {

let locs = require("Storage").readJSON(locationsFile, 1) || [];
locs.push(location);
require("Storage").writeJSON(locationsFile, locs);

}
let getSettings=function(){
return Object.assign({
precision: 30,
timeDelay:30000
}, require('Storage').readJSON("phoneremind.settings.json", true) || {});
}
let getAllLocations = function () {
return require("Storage").readJSON(locationsFile, 1) || [];
};

let getMyLocation = function () {
if (!require("Storage").read("mylocation.json")) {
require("Storage").writeJSON("mylocation.json", {
location: "Unknown",
lat: 0,
lon: 0
});
}
return require("Storage").readJSON("mylocation.json", 1);
};

let buzz = function () {
Bangle.buzz(230);
}

let convertCoordsToMeters = function (lat, lon) {
return {
lat: 110574 * lat,
lon: 111320 * Math.cos(lat * Math.PI / 180) * lon

}
}




let disconnected = function () {
connected = false;
var myLocation = getMyLocation();
var locs = getAllLocations();
print(locs);
var useGPS = false;
if (!useGPS) {

myLocation = getMyLocation();
var convLoc = convertCoordsToMeters(myLocation.lat, myLocation.lon)
myLocation.lat = convLoc.lat;
myLocation.lon = convLoc.lon;

locs = getAllLocations();

print(myLocation);

for (let location of locs) {
if (Math.abs(myLocation.lat - location.lat) < getSettings().precision && Math.abs(myLocation.lon - location.lon) < getSettings().precision) {
//at a familiar location, no action needed.
return;
}
}
//no location matched the current one...



setTimeout(function(){
if(connected==true)return;
buzz();
if (require("Storage").readJSON("setting.json", true).quiet != 2) {

setTimeout(function () {
buzzInterval = setInterval(buzz, 850);
}, 750);
}
promptShown = true;
E.showPrompt("Phone was disconnected. It may have been left in " + myLocation.location + ".", {

title: "Phone Left Behind",
buttons: { "Ok": true, "Save Location": false }

}).then(function (answer) {
promptShown = false;
clearInterval(buzzInterval);
if (answer) {
Bangle.load();
} else {
addLocation({
city: myLocation.location,
lat: myLocation.lat,
lon: myLocation.lon
});
E.showPrompt("Added location in " + myLocation.location + " to familiar locations.", {
title: "Location Saved",
buttons: { "Ok": true }
})
.then(function () {
Bangle.load();
});
}
});
},getSettings().timeDelay)

}
}

let connectHandler = function () {
connected = true;
if (promptShown) {
//prompt is shown, dismiss
if (buzzInterval) clearInterval(buzzInterval);
load();

}

}

NRF.on('disconnect', disconnected);
NRF.on('connect', connectHandler);
}
Binary file added apps/phoneremind/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions apps/phoneremind/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"id": "phoneremind",
"name": "Phone Reminder",
"shortName":"PhoneRemind",
"version":"0.01",
"icon":"icon.png",
"description": "Provides an alert when your phone disconnects, and allows you to set familiar locations where it will not alert. This uses `MyLocation` for location.",
"type":"bootloader",
"tags": "tool,bluetooth",
"author":"RKBoss6",
"supports": ["BANGLEJS2"],
"screenshots" : [ { "url":"scr.png" }],
"dependencies" : { "mylocation":"app"},
"readme":"README.md",
"storage": [
{"name":"phoneremind.boot.js","url":"boot.js"},
{"name":"phoneremind.settings.js","url":"settings.js"}
],
"data": [
{"name":"phoneremind.json"}
]
}
Binary file added apps/phoneremind/scr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
112 changes: 112 additions & 0 deletions apps/phoneremind/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
(function(back) {
var FILE = "phoneremind.settings.json";
// Load settings
var settings = Object.assign({
precision: 30,
timeDelay:30000
}, require('Storage').readJSON(FILE, true) || {});

function writeSettings() {
require('Storage').writeJSON(FILE, settings);
}
function selectPrecisionLevel(lvl){
settings.precision=lvl;
writeSettings();
showMainMenu();

}
function formatTime(ms) {
if (ms < 60000) {
// Less than a minute → show seconds
return Math.round(ms / 1000) + 's';
} else {
// One minute or more → show minutes
return Math.round(ms / 60000) + 'm';
}
}

function showPrecisionMenu(back){

let menu = {
'': { 'title': 'Precision' },
'< Back': back,
'Country': function(){

selectPrecisionLevel(20000);
back();
},
'Large City': function(){

selectPrecisionLevel(1200);
back();
},
'Small City': function(){

selectPrecisionLevel(230);
back();
},
'City Block': function(){

selectPrecisionLevel(60);
back();
},
'Building': function(){

selectPrecisionLevel(30);
back();
},
'Meters': function(){

selectPrecisionLevel(1);
back();
},

}
E.showMenu(menu)
}

function showMainMenu(){
// Show the menu
E.showMenu({
"" : { "title" : "Phone Reminder" },
"< Back" : () => back(),
'Check Delay': {
value: 0|settings.timeDelay,
min: 0, max: 600000,
step:5000,
onchange: v => {
settings.timeDelay = v;
writeSettings();
},
format : v => {
return formatTime(v)
}
},
'Precision Level': function(){
showPrecisionMenu(showMainMenu);

// format: ... may be specified as a function which converts the value to a string
// if the value is a boolean, showMenu() will convert this automatically, which
// keeps settings menus consistent
},



'Delete All Locations': function(){
E.showPrompt("Are you sure you want to delete all familiar locations?", {title:"Confirm"})
.then(function(v) {
if (v) {
require("Storage").erase("phoneremind.json");
E.showMessage("Successfully deleted saved locations!","Cleared");
} else {
showMainMenu();

}
});

}
});
}
showMainMenu()

})