2021-11-04 17:16:02 +00:00
|
|
|
(function() {
|
|
|
|
function gbSend(message) {
|
|
|
|
Bluetooth.println("");
|
|
|
|
Bluetooth.println(JSON.stringify(message));
|
|
|
|
}
|
2022-05-24 12:08:43 +00:00
|
|
|
var lastMsg;
|
2021-11-04 17:16:02 +00:00
|
|
|
|
2022-01-12 10:58:47 +00:00
|
|
|
var settings = require("Storage").readJSON("android.settings.json",1)||{};
|
2022-04-24 07:24:43 +00:00
|
|
|
//default alarm settings
|
|
|
|
if (settings.rp == undefined) settings.rp = true;
|
|
|
|
if (settings.as == undefined) settings.as = true;
|
|
|
|
if (settings.vibrate == undefined) settings.vibrate = "..";
|
|
|
|
require('Storage').writeJSON("android.settings.json", settings);
|
2021-11-04 17:16:02 +00:00
|
|
|
var _GB = global.GB;
|
|
|
|
global.GB = (event) => {
|
|
|
|
// feed a copy to other handlers if there were any
|
|
|
|
if (_GB) setTimeout(_GB,0,Object.assign({},event));
|
|
|
|
|
|
|
|
/* TODO: Call handling, fitness */
|
|
|
|
var HANDLERS = {
|
|
|
|
// {t:"notify",id:int, src,title,subject,body,sender,tel:string} add
|
2022-05-24 12:08:43 +00:00
|
|
|
"notify" : function() {
|
|
|
|
Object.assign(event,{t:"add",positive:true, negative:true});
|
|
|
|
// Detect a weird GadgetBridge bug and fix it
|
|
|
|
// For some reason SMS messages send two GB notifications, with different sets of info
|
|
|
|
if (lastMsg && event.body == lastMsg.body && lastMsg.src == undefined && event.src == "Messages") {
|
|
|
|
// Mutate the other message
|
|
|
|
event.id = lastMsg.id;
|
|
|
|
}
|
|
|
|
lastMsg = event;
|
|
|
|
require("messages").pushMessage(event);
|
|
|
|
},
|
2021-11-04 17:16:02 +00:00
|
|
|
// {t:"notify~",id:int, title:string} // modified
|
|
|
|
"notify~" : function() { event.t="modify";require("messages").pushMessage(event); },
|
|
|
|
// {t:"notify-",id:int} // remove
|
|
|
|
"notify-" : function() { event.t="remove";require("messages").pushMessage(event); },
|
|
|
|
// {t:"find", n:bool} // find my phone
|
|
|
|
"find" : function() {
|
|
|
|
if (Bangle.findDeviceInterval) {
|
|
|
|
clearInterval(Bangle.findDeviceInterval);
|
|
|
|
delete Bangle.findDeviceInterval;
|
|
|
|
}
|
|
|
|
if (event.n) // Ignore quiet mode: we always want to find our watch
|
|
|
|
Bangle.findDeviceInterval = setInterval(_=>Bangle.buzz(),1000);
|
|
|
|
},
|
|
|
|
// {t:"musicstate", state:"play/pause",position,shuffle,repeat}
|
|
|
|
"musicstate" : function() {
|
|
|
|
require("messages").pushMessage({t:"modify",id:"music",title:"Music",state:event.state});
|
|
|
|
},
|
|
|
|
// {t:"musicinfo", artist,album,track,dur,c(track count),n(track num}
|
|
|
|
"musicinfo" : function() {
|
|
|
|
require("messages").pushMessage(Object.assign(event, {t:"modify",id:"music",title:"Music"}));
|
2021-11-23 16:28:34 +00:00
|
|
|
},
|
|
|
|
// {"t":"call","cmd":"incoming/end","name":"Bob","number":"12421312"})
|
2021-11-23 16:31:42 +00:00
|
|
|
"call" : function() {
|
2021-11-23 20:20:37 +00:00
|
|
|
Object.assign(event, {
|
|
|
|
t:event.cmd=="incoming"?"add":"remove",
|
|
|
|
id:"call", src:"Phone",
|
|
|
|
positive:true, negative:true,
|
|
|
|
title:event.name||"Call", body:"Incoming call\n"+event.number});
|
2021-11-23 16:28:34 +00:00
|
|
|
require("messages").pushMessage(event);
|
|
|
|
},
|
2022-04-24 07:24:43 +00:00
|
|
|
"alarm" : function() {
|
|
|
|
//wipe existing GB alarms
|
2022-04-25 13:02:12 +00:00
|
|
|
var sched;
|
|
|
|
try { sched = require("sched"); } catch (e) {}
|
|
|
|
if (!sched) return; // alarms may not be installed
|
|
|
|
var gbalarms = sched.getAlarms().filter(a=>a.appid=="gbalarms");
|
|
|
|
for (var i = 0; i < gbalarms.length; i++)
|
|
|
|
sched.setAlarm(gbalarms[i].id, undefined);
|
|
|
|
var alarms = sched.getAlarms();
|
2022-04-25 12:42:00 +00:00
|
|
|
var time = new Date();
|
|
|
|
var currentTime = time.getHours() * 3600000 +
|
|
|
|
time.getMinutes() * 60000 +
|
|
|
|
time.getSeconds() * 1000;
|
|
|
|
for (var j = 0; j < event.d.length; j++) {
|
|
|
|
// prevents all alarms from going off at once??
|
|
|
|
var dow = event.d[j].rep;
|
|
|
|
if (!dow) dow = 127; //if no DOW selected, set alarm to all DOW
|
|
|
|
var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0;
|
2022-05-18 07:08:11 +00:00
|
|
|
var a = require("sched").newDefaultAlarm();
|
2022-05-18 08:09:12 +00:00
|
|
|
a.id = "gb"+j;
|
|
|
|
a.appid = "gbalarms";
|
|
|
|
a.on = true;
|
|
|
|
a.t = event.d[j].h * 3600000 + event.d[j].m * 60000;
|
|
|
|
a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format
|
|
|
|
a.last = last;
|
2022-04-24 07:24:43 +00:00
|
|
|
alarms.push(a);
|
|
|
|
}
|
2022-04-25 13:02:12 +00:00
|
|
|
sched.setAlarms(alarms);
|
|
|
|
sched.reload();
|
2022-04-24 07:24:43 +00:00
|
|
|
},
|
2022-05-26 13:29:38 +00:00
|
|
|
//TODO perhaps move those in a library (like messages), used also for viewing events?
|
2022-06-03 06:44:13 +00:00
|
|
|
//add and remove events based on activity on phone (pebble-like)
|
2022-05-26 13:29:38 +00:00
|
|
|
"calendar" : function() {
|
2022-05-30 19:36:07 +00:00
|
|
|
var cal = require("Storage").readJSON("android.calendar.json",true);
|
|
|
|
if (!cal || !Array.isArray(cal)) cal = [];
|
2022-06-01 15:39:09 +00:00
|
|
|
var i = cal.findIndex(e=>e.id==event.id);
|
|
|
|
if(i<0)
|
|
|
|
cal.push(event);
|
|
|
|
else
|
|
|
|
cal[i] = event;
|
2022-05-26 13:29:38 +00:00
|
|
|
require("Storage").writeJSON("android.calendar.json", cal);
|
|
|
|
},
|
|
|
|
"calendar-" : function() {
|
2022-05-30 19:36:07 +00:00
|
|
|
var cal = require("Storage").readJSON("android.calendar.json",true);
|
|
|
|
//if any of those happen we are out of sync!
|
|
|
|
if (!cal || !Array.isArray(cal)) return;
|
2022-05-30 18:44:28 +00:00
|
|
|
cal = cal.filter(e=>e.id!=event.id);
|
2022-05-26 13:29:38 +00:00
|
|
|
require("Storage").writeJSON("android.calendar.json", cal);
|
2022-06-08 15:45:39 +00:00
|
|
|
},
|
|
|
|
//triggered by GB, send all ids
|
|
|
|
"force_calendar_sync_start" : function() {
|
|
|
|
var cal = require("Storage").readJSON("android.calendar.json",true);
|
|
|
|
if (!cal || !Array.isArray(cal)) cal = [];
|
|
|
|
gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)});
|
2022-06-28 14:31:57 +00:00
|
|
|
},
|
|
|
|
"http":function() {
|
|
|
|
//get the promise and call the promise resolve
|
|
|
|
if (Bangle.httpRequest === undefined) return;
|
2022-07-02 15:00:23 +00:00
|
|
|
var request=Bangle.httpRequest[event.id];
|
|
|
|
if (request === undefined) return; //already timedout or wrong id
|
2022-06-28 14:31:57 +00:00
|
|
|
delete Bangle.httpRequest[event.id];
|
2022-07-02 15:00:23 +00:00
|
|
|
clearTimeout(request.t); //t = timeout variable
|
2022-06-28 14:31:57 +00:00
|
|
|
if(event.err!==undefined) //if is error
|
2022-07-02 15:00:23 +00:00
|
|
|
request.j(event.err); //r = reJect function
|
2022-06-28 14:31:57 +00:00
|
|
|
else
|
2022-07-02 15:00:23 +00:00
|
|
|
request.r(event); //r = resolve function
|
2022-05-26 13:29:38 +00:00
|
|
|
}
|
2021-11-04 17:16:02 +00:00
|
|
|
};
|
|
|
|
var h = HANDLERS[event.t];
|
|
|
|
if (h) h(); else console.log("GB Unknown",event);
|
|
|
|
};
|
2022-06-28 14:31:57 +00:00
|
|
|
// HTTP request handling - see the readme
|
|
|
|
// options = {id,timeout,xpath}
|
|
|
|
Bangle.http = (url,options)=>{
|
|
|
|
options = options||{};
|
2022-09-28 08:15:04 +00:00
|
|
|
if (!NRF.getSecurityStatus().connected)
|
|
|
|
return Promise.reject("Not connected to Bluetooth");
|
2022-06-28 14:31:57 +00:00
|
|
|
if (Bangle.httpRequest === undefined)
|
|
|
|
Bangle.httpRequest={};
|
|
|
|
if (options.id === undefined) {
|
|
|
|
// try and create a unique ID
|
|
|
|
do {
|
|
|
|
options.id = Math.random().toString().substr(2);
|
|
|
|
} while( Bangle.httpRequest[options.id]!==undefined);
|
|
|
|
}
|
|
|
|
//send the request
|
|
|
|
var req = {t: "http", url:url, id:options.id};
|
|
|
|
if (options.xpath) req.xpath = options.xpath;
|
2022-08-01 09:19:59 +00:00
|
|
|
if (options.method) req.method = options.method;
|
|
|
|
if (options.body) req.body = options.body;
|
|
|
|
if (options.headers) req.headers = options.headers;
|
2022-06-28 14:31:57 +00:00
|
|
|
gbSend(req);
|
|
|
|
//create the promise
|
|
|
|
var promise = new Promise(function(resolve,reject) {
|
|
|
|
//save the resolve function in the dictionary and create a timeout (30 seconds default)
|
|
|
|
Bangle.httpRequest[options.id]={r:resolve,j:reject,t:setTimeout(()=>{
|
|
|
|
//if after "timeoutMillisec" it still hasn't answered -> reject
|
|
|
|
delete Bangle.httpRequest[options.id];
|
|
|
|
reject("Timeout");
|
|
|
|
},options.timeout||30000)};
|
|
|
|
});
|
|
|
|
return promise;
|
|
|
|
}
|
2021-11-04 17:16:02 +00:00
|
|
|
|
|
|
|
// Battery monitor
|
2022-02-01 20:10:15 +00:00
|
|
|
function sendBattery() { gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); }
|
2021-11-04 17:16:02 +00:00
|
|
|
NRF.on("connect", () => setTimeout(sendBattery, 2000));
|
2022-02-01 20:10:15 +00:00
|
|
|
Bangle.on("charging", sendBattery);
|
2022-01-12 10:58:47 +00:00
|
|
|
if (!settings.keep)
|
|
|
|
NRF.on("disconnect", () => require("messages").clearAll()); // remove all messages on disconnect
|
2021-11-04 17:16:02 +00:00
|
|
|
setInterval(sendBattery, 10*60*1000);
|
|
|
|
// Health tracking
|
|
|
|
Bangle.on('health', health=>{
|
|
|
|
gbSend({ t: "act", stp: health.steps, hrm: health.bpm });
|
|
|
|
});
|
|
|
|
// Music control
|
|
|
|
Bangle.musicControl = cmd => {
|
|
|
|
// play/pause/next/previous/volumeup/volumedown
|
2021-11-23 16:28:34 +00:00
|
|
|
gbSend({ t: "music", n:cmd });
|
2021-11-23 20:20:37 +00:00
|
|
|
};
|
|
|
|
// Message response
|
|
|
|
Bangle.messageResponse = (msg,response) => {
|
|
|
|
if (msg.id=="call") return gbSend({ t: "call", n:response?"ACCEPT":"REJECT" });
|
2021-12-13 18:42:14 +00:00
|
|
|
if (isFinite(msg.id)) return gbSend({ t: "notify", n:response?"OPEN":"DISMISS", id: msg.id });
|
2021-11-23 20:20:37 +00:00
|
|
|
// error/warn here?
|
|
|
|
};
|
2022-01-12 10:58:47 +00:00
|
|
|
// remove settings object so it's not taking up RAM
|
|
|
|
delete settings;
|
2021-11-04 17:16:02 +00:00
|
|
|
})();
|