Merge branch 'master' into fixAlarm
|
|
@ -4,4 +4,5 @@
|
|||
0.04: Obey system quiet mode
|
||||
0.05: Battery optimisation, add the pause option, bug fixes
|
||||
0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night
|
||||
0.07: Fix bug on the cutting edge firmware
|
||||
0.07: Fix bug on the cutting edge firmware
|
||||
0.08: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Activity Reminder",
|
||||
"shortName":"Activity Reminder",
|
||||
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
|
||||
"version":"0.07",
|
||||
"version":"0.08",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,activity",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
"< Back": () => back(),
|
||||
'Enable': {
|
||||
value: settings.enabled,
|
||||
format: v => v ? "Yes" : "No",
|
||||
onchange: v => {
|
||||
settings.enabled = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
|
|
@ -38,9 +37,7 @@
|
|||
settings.maxInnactivityMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => {
|
||||
return x + " min";
|
||||
}
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Dismiss delay': {
|
||||
value: settings.dismissDelayMin,
|
||||
|
|
@ -49,9 +46,7 @@
|
|||
settings.dismissDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => {
|
||||
return x + " min";
|
||||
}
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Pause delay': {
|
||||
value: settings.pauseDelayMin,
|
||||
|
|
@ -61,7 +56,7 @@
|
|||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => {
|
||||
return x + " min";
|
||||
return x + "m";
|
||||
}
|
||||
},
|
||||
'Min steps': {
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: AdvCasio first version
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
# Adv Casio Clock
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/2981891/175355586-1dfc0d66-6555-4385-b124-1605fdb71a11.jpg" width="250" />
|
||||
|
||||
An over-engineered clock inspired by Casio watches.<br/>
|
||||
It has a dedicated timer, a scratchpad and can display the weather condition 4 days ahead.<br/>
|
||||
It uses a <a target="_blank" href="https://dotgreg.github.io/advCasioBangleClock/">custom web app</a> to update its content.<br/>
|
||||
Forked from the awesome Cassio Watch.<br/>
|
||||
|
||||
## Todo
|
||||
|
||||
- Improving quality of the background images, right now it is quite blurry.
|
||||
- Improving screenshots quality.
|
||||
- Improving web app look.
|
||||
- Improving bangle app performances (using functions for images and specialized array).
|
||||
|
||||
## Functionalities
|
||||
|
||||
- Current time
|
||||
- Current day and month
|
||||
- Footsteps
|
||||
- Battery
|
||||
- Simple Timer embedded
|
||||
- Weather forecast (7 days)
|
||||
- Scratchpad
|
||||
|
||||
## Screenshots
|
||||
Clock:<br/>
|
||||
<img src="https://user-images.githubusercontent.com/2981891/175519126-049caf93-73d0-4472-9650-33b28f80843c.jpg" width="250" />
|
||||
<img src="https://user-images.githubusercontent.com/2981891/175519128-96926e32-2165-4c61-9364-843440304bb9.jpg" width="250" />
|
||||
<img src="https://user-images.githubusercontent.com/2981891/175519130-4921073c-48fc-4c29-932d-d42acc3b395c.jpg" width="250" />
|
||||
|
||||
Web interface to update weather & scratchpad <br/>
|
||||
<a target="_blank" ref="https://dotgreg.github.io/advCasioBangleClock/">https://dotgreg.github.io/advCasioBangleClock</a>
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/2981891/175519121-851bb209-7192-40db-a014-490c344f7597.jpg" width="250" />
|
||||
|
||||
## Usage
|
||||
### How to update the tasks list / weather
|
||||
- you will need a <a target="_blank" href="https://openweathermap.org/price#weather">free openweathermap.org api key</a>.
|
||||
- go to https://dotgreg.github.io/advCasioBangleClock/
|
||||
- Alternatively you can install it on your own server/heroku/service/github pages, the web-app code is <a target="_blank" href="https://github.com/dotgreg/advCasioBangleClock/tree/master/web-app">here</a>
|
||||
- fill the location and the api key (it will be saved on your browser, no need to do it each time)
|
||||
- edit the scratchpad with what you want
|
||||
- click on sync
|
||||
- reload your clock!
|
||||
|
||||
### How to start/stop the timer
|
||||
- swipe up : add time (+5min)
|
||||
- swipe down : remove time (-5min)
|
||||
- swipe right : start timer
|
||||
- swipe left : stop timer
|
||||
|
||||
## Links
|
||||
### Issues, suggestions and bugtracker
|
||||
<a target="_blank" href="https://github.com/dotgreg/advCasioBangleClock/issues">https://github.com/dotgreg/advCasioBangleClock/issues</a>
|
||||
|
||||
### Code repository (bangle app and web app)
|
||||
<a target="_blank" href="https://github.com/dotgreg/advCasioBangleClock">https://github.com/dotgreg/advCasioBangleClock</a>
|
||||
|
||||
### Creator
|
||||
<a target="_blank" href="https://github.com/dotgreg">https://github.com/dotgreg</a>
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwghC/AH4A/AGsCmUQC6kf/8wC6k///wgEv//zD4PxAQIJBABP//4QBC4IcBh/yEQIXKgP/l4rBl/yGAMP/4iBKJUC/5gBIAQVBBAMR/8gC5IQBAAMQC4IVBFoMjAYIXNmAXBgYXCPgQAJl/xHwPwj/yn5kC/55BUxSlC+JiBVgQ5BUxiDBUIIXBIQQXBcCoA/AH4ADXAUgUAUQBAkPeoTDFgIHBAALQEA4XwC4IOEAAQRBbAQBBCAIgBEYMQC4TnEC4XyeQgBDAAMwC4pIDC4kDAgJLD//xC5QIBNQISCFYIZCC4aEBAQRCDAAPyl4hBOIh3Cn53GNgMRiKxGBAR5BAoYA/AH4A/AH4A5A"))
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
const storage = require('Storage');
|
||||
|
||||
require("Font6x12").add(Graphics);
|
||||
require("Font6x8").add(Graphics);
|
||||
require("Font8x12").add(Graphics);
|
||||
require("Font7x11Numeric7Seg").add(Graphics);
|
||||
|
||||
function bigThenSmall(big, small, x, y) {
|
||||
g.setFont("7x11Numeric7Seg", 2);
|
||||
g.drawString(big, x, y);
|
||||
x += g.stringWidth(big);
|
||||
g.setFont("8x12");
|
||||
g.drawString(small, x, y);
|
||||
}
|
||||
|
||||
function getClockBg() {
|
||||
return require("heatshrink").decompress(atob("icVgf/ABv8v4DBx4CB+PH8F+nAGB48fwEHBwXjxwqBuPH//+nAGBBwIjCAwI2D/wGBgIyDI4QGDwAGBHYX/4AGBn4UFEYQpCEYYpCAAMfMhP4FIgABwJ8OEBIA=="));
|
||||
}
|
||||
|
||||
|
||||
// sun, cloud, rain, thunder
|
||||
var iconsWeather = [
|
||||
require("heatshrink").decompress(atob("i8Ugf/ACcfA434BA/AAwsAv0/8F/BAcDwEHHIpECFI3wn4GC/gOC+PAGoXggEH/+ODQgXBGQv/wAbBBAnguEACIn4gfxI4JXFwJmG/kPBA3jSynw")), require("heatshrink").decompress(atob("i0Ugf/AEXggIGE/0A/kPBAmBCIN/A4Y8CgAICwEHBYoUE/ACCj4sDn4CBC4YyDwBrDCgYA3A")), require("heatshrink").decompress(atob("h8Rgf/AAuBAgf8h4FDCwM/AgPA/gFC/0HgEBBQPwnEfDoWAg4jC/gOCAoQmBAQXjFIV//8f//4IQP4j/+gAIB4EcHII4CAoI+DLQJXF/AA==")), require("heatshrink").decompress(atob("h0Pgf/AA8fAYX+g4EC8EBAgXADAeAgAECgAOC/wrCDQIOBBYfwgAaC/kAn4EB/EAv4aDHAeBIg38"))
|
||||
];
|
||||
|
||||
|
||||
function getBackgroundImage() {
|
||||
return require("heatshrink").decompress(atob("2GwghC/AH4A/AH4AMl////wAwURiQECgUzmcxBQQCBiYUBBARW+LAcCAgcPBYgFBkAIFG7kQiAKIiIKBgISOAAJBD//zKQfxK4vyAoMQCgn/ERBhBBYR5BAwR1DB4Y2DgYPCGIQRCCQcP+EfGJI0FEgRSCGAQCCX4JXCkAhDn4lI+HyK4YWBFIPzJYJXHAIMSK4cwJ4I3CAYMzA4cfcRMBdwytBK4i6FK4IUCMgYAEGIITBK4cCaAPwgJXB+fzK4sAgYtCK5EfA4pXR+AmBaIZYCK6KcCAwSjDEYXx/8vK5QRCK4kPK6cDkJREBIMBfgIrDK5svUAIQBAwIaCK4w+DK4YGBK7IaBboIuCK4gFCJwYBBiBCCCgQhHHYgGDgArBK5IGDAYMgJ4Xwn53BGgLVDmBXKAAinDLpJXCAAYhHR4YODn/wJIPyTYZXDE4RXD+ECNILIDAIPwj4xIAAYNCR4fyVIYLFA4KEBBAglKAGUCmcykEAiMQBIURBYM/BgIUEgcz+bTKAH4A/AH4A/AHP/AGY1d+BWCh5X/LCpW1K74fgG/5X/AH5X/K9Bg/K63wK/5XWgBX/K6pWBK/5XU+BWBh5J/K6auCK/5XTVwRfFAH5XOKwRX/K6auDh5I/K6SuDWP5XSVwYADWX6vXK/5XQWQpW/K6auDJP5XWV35XT+Cu/K7Ku/K65H/K6hW/K7EPI35XWIv5XWAH5X/K/4A/K/5X/K/4A/K9cAAH4A/AFzz/AHRX/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/40VAH4A/AFzLb+EPDm4AdK/5X/K+PwgEAHy5X9HgMAK/5XXH6xX/H65X/K/5X/K98AK7sAgBX3DjBWFO644DSTHwGzJXED4RXaDoLqcK7weWDIQcXK8I6YK77KXK4o8DPbY6ZK7qvDDy6vdR7JXDh60EDyw5BAIRXYSwjMbAgIhUDwJZCHwJX0GwjRWNwIAEHSwBCDSpXFH4pXzDS5XIEARXVSYbQEDaYzCK+6vcKaxXNDypX9HwQkbHS40COSpXKK2A6CHgRXcPIhX0SwpXYVuQ6EgBX/K644YODBXkSDJX/K/5X/DtRX6gA3YOkRWbLDZX4KwYA/AG8F5vdABncKH4AGhpRJAYXNAgPAKP4AF5vMJwoDBAQIKE6BR/AAvc5vO9wAB7oCB9veAoPcAoPcK+kwh8AgcA98An//gH/+sD//wCISgBJ4IABAYpaC9vdK4UP/9AAQNQr/zgHwEYNQFYQAh+EP+FegH+A4QBCMQIKBAAPNK4yxBA4RXCV4YZBE4IjChwCDmApCK8VdmHggHgFYf0SQJXE5nMK4anCAoYHC5pXCaQJXBop+BqAGEK7f/AAQeEKwQrBqCtDAILjBCQfNK4JTCAYZXF7qvD//gV4S2DgEFFIYAECgIACMC8PKoIBB8n1K4ivF5vc5xOCWYZbBAYavHU4RXCr4pEAEMDfoNQGoMEgEwYQPwAoIBBAAPM5ipC7oDCVIIAE7hXCD4SdBiEP+gGBgihCFYIAz5pXBAAnN7oIB7nc5gOBK4QA/K4pNCWgSpCBInNK/4AGhncKIStC7gCBA4QAC4BR/AAysCABZW/AHwA="));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// schedule a draw for the next minute
|
||||
let rocketInterval;
|
||||
var drawTimeout;
|
||||
function queueDraw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
}
|
||||
|
||||
|
||||
function clearIntervals() {
|
||||
if (rocketInterval) clearInterval(rocketInterval);
|
||||
rocketInterval = undefined;
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// TIMER FUNC
|
||||
//
|
||||
var timer_time = 0;
|
||||
var alreadyListenTouch = false;
|
||||
function initTouchTimer () {
|
||||
if (alreadyListenTouch) return;
|
||||
alreadyListenTouch = true;
|
||||
|
||||
Bangle.on('swipe', function(dirX,dirY) {
|
||||
if (canTouch === false) return;
|
||||
var njson = getDataJson();
|
||||
if (!njson) return;
|
||||
|
||||
if (dirX === -1) {
|
||||
timer_time = 0;
|
||||
delete njson.timer;
|
||||
setDataJson(njson);
|
||||
}
|
||||
else if (dirX === 1) {
|
||||
var now = new Date().getTime();
|
||||
njson.timer = now + (timer_time * 1000 * 60);
|
||||
Bangle.setLocked(true);
|
||||
setDataJson(njson);
|
||||
Bangle.buzz(200, 0);
|
||||
timer_time = 0;
|
||||
}
|
||||
else if (dirY === -1) {
|
||||
if (canTouch === false || njson.timer) return;
|
||||
timer_time = timer_time + 5;
|
||||
}
|
||||
else if (dirY === 1) {
|
||||
if (canTouch === false || njson.timer) return;
|
||||
timer_time = timer_time - 5;
|
||||
}
|
||||
draw();
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
initTouchTimer ();
|
||||
});
|
||||
|
||||
function getTimerTime() {
|
||||
// if timer_time !== -1, take it
|
||||
if (timer_time !== 0) {
|
||||
return timer_time + "m";
|
||||
} else {
|
||||
// else, show diff between njsontime and now
|
||||
var njson = getDataJson();
|
||||
if (!njson) return false;
|
||||
var now = new Date().getTime();
|
||||
var diff = Math.round((njson.timer - now) / (1000 * 60));
|
||||
//console.log(123, njson, diff, now, njson.timer - now);
|
||||
if (diff > 0) return diff + "m";
|
||||
else if (njson.timer) {
|
||||
Bangle.buzz(1000, 1);
|
||||
console.log("END OF TIMER");
|
||||
delete njson.timer;
|
||||
setDataJson(njson);
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// if diff is <0, delete timer from json
|
||||
}
|
||||
}
|
||||
function drawTimer() {
|
||||
//g.drawString(getTimerTime(), 100, 100);
|
||||
g.setFont("8x12", 2);
|
||||
var t = 97;
|
||||
var l = 105;
|
||||
var time = getTimerTime();
|
||||
if (time || timer_time !== 0) g.drawString(time, l+5, t+0);
|
||||
if (time && timer_time === 0) g.drawImage(getClockBg(), l-20, t+2, { scale: 1 });
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// DATA READING
|
||||
//
|
||||
function getDataJson(){
|
||||
var res = {"tasks":"", "weather":[]};
|
||||
try {
|
||||
res = storage.readJSON('advcasio.data.json');
|
||||
} catch(ex) {
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
function setDataJson(resJson){
|
||||
try {
|
||||
res = storage.writeJSON('advcasio.data.json', resJson);
|
||||
} catch(ex) {
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
var dataJson = getDataJson();
|
||||
|
||||
////////////////////////////////////////////
|
||||
// WEATHER!
|
||||
//
|
||||
function drawWeather(arr) {
|
||||
g.setFont("6x8", 1);
|
||||
var p = {l: 8, tText: 40, tIcon:20, decal:25};
|
||||
var today = new Date().getTime();
|
||||
var yesterday = today - (1000 * 60 * 60 * 24);
|
||||
var testday = today + (1000 * 60 * 60 * 24 * 2);
|
||||
//12h auj > 12h hier qui est sup a 0h auj
|
||||
//23h59 hier est sup a 0h auj
|
||||
var j = 0;
|
||||
for(var i = 0; i<arr.length;i++) {
|
||||
if (arr[i][2] > yesterday && j < 4) {
|
||||
g.drawString(arr[i][0], p.l + p.decal*j + 4, p.tText);
|
||||
g.drawImage(iconsWeather[arr[i][1]], p.l + p.decal*j, p.tIcon, { scale: 1 });
|
||||
j++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// DRAWING FUNCS
|
||||
//
|
||||
function drawTasks(str) {
|
||||
g.setFont("6x8", 1);
|
||||
var t = 57;
|
||||
var l = 0;
|
||||
g.drawString(str, l+5, t+0);
|
||||
}
|
||||
|
||||
function drawSteps() {
|
||||
g.setFont("8x12", 2);
|
||||
var t = 132;
|
||||
var l = 150;
|
||||
g.drawString(getSteps(), l+5, t+0);
|
||||
}
|
||||
|
||||
|
||||
function drawClock() {
|
||||
g.setFont("7x11Numeric7Seg", 3);
|
||||
g.clearRect(80, 57, 170, 96);
|
||||
g.setColor(255, 255, 255);
|
||||
var l = 77;
|
||||
var t = 57;
|
||||
var w = 170;
|
||||
var h = 116;
|
||||
g.drawRect(l, t, w, h);
|
||||
g.fillRect(l, t, w, h);
|
||||
g.setColor(0, 0, 0);
|
||||
g.drawString(require("locale").time(new Date(), 1), 76, 60);
|
||||
|
||||
// day
|
||||
//g.setFont("8x12", 1);
|
||||
//g.setFont("9x18", 1);
|
||||
//g.drawString(require("locale").dow(new Date(), 2).toUpperCase(), 25, 136);
|
||||
g.setFont("8x12", 2);
|
||||
g.drawString(require("locale").dow(new Date(), 2), 18, 130);
|
||||
|
||||
// month
|
||||
g.setFont("8x12");
|
||||
g.drawString(require("locale").month(new Date(), 2).toUpperCase(), 80, 127);
|
||||
|
||||
// day nb
|
||||
g.setFont("8x12", 2);
|
||||
const time = new Date().getDate();
|
||||
g.drawString(time < 10 ? "0" + time : time, 78, 137);
|
||||
}
|
||||
|
||||
function drawBattery() {
|
||||
bigThenSmall(E.getBattery(), "%", 140, 23);
|
||||
}
|
||||
|
||||
|
||||
function getSteps() {
|
||||
var steps = 0;
|
||||
try{
|
||||
if (WIDGETS.wpedom !== undefined) {
|
||||
steps = WIDGETS.wpedom.getSteps();
|
||||
} else if (WIDGETS.activepedom !== undefined) {
|
||||
steps = WIDGETS.activepedom.getSteps();
|
||||
} else {
|
||||
steps = Bangle.getHealthStatus("day").steps;
|
||||
}
|
||||
} catch(ex) {
|
||||
// In case we failed, we can only show 0 steps.
|
||||
return "? k";
|
||||
}
|
||||
|
||||
steps = Math.round(steps/1000);
|
||||
return steps + "k";
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
queueDraw();
|
||||
|
||||
g.reset();
|
||||
g.clear();
|
||||
g.setColor(255, 255, 255);
|
||||
g.fillRect(0, 0, g.getWidth(), g.getHeight());
|
||||
let background = getBackgroundImage();
|
||||
g.drawImage(background, 0, 0, { scale: 1 });
|
||||
|
||||
|
||||
g.setColor(0, 0, 0);
|
||||
g.setFont("6x12");
|
||||
if(dataJson && dataJson.weather) drawWeather(dataJson.weather);
|
||||
if(dataJson && dataJson.tasks) drawTasks(dataJson.tasks);
|
||||
|
||||
|
||||
g.setFontAlign(0,-1);
|
||||
g.setFont("8x12", 2);
|
||||
|
||||
drawSteps();
|
||||
g.setFontAlign(-1,-1);
|
||||
drawClock();
|
||||
drawBattery();
|
||||
drawTimer();
|
||||
// Hide widgets
|
||||
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
|
||||
}
|
||||
|
||||
// save batt power, does not seem to work although...
|
||||
var canTouch = true;
|
||||
Bangle.on("lcdPower", (on) => {
|
||||
if (on) {
|
||||
draw();
|
||||
} else {
|
||||
canTouch = false;
|
||||
clearIntervals();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Bangle.on("lock", (locked) => {
|
||||
clearIntervals();
|
||||
draw();
|
||||
if (!locked) {
|
||||
canTouch = true;
|
||||
} else {
|
||||
canTouch = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Load widgets, but don't show them
|
||||
Bangle.loadWidgets();
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.reset();
|
||||
g.clear();
|
||||
draw();
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -0,0 +1 @@
|
|||
{"tasks":"", "weather":[]};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{ "id": "advcasio",
|
||||
"name": "Advanced Casio Clock",
|
||||
"shortName":"advcasio",
|
||||
"version":"0.01",
|
||||
"description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.",
|
||||
"icon": "app.png",
|
||||
"tags": "clock",
|
||||
"type": "clock",
|
||||
"screenshots": [
|
||||
{ "url": "screenshot-clock-1.jpg" },
|
||||
{ "url": "screenshot-clock-2.jpg" },
|
||||
{ "url": "screenshot-clock-3.jpg" },
|
||||
{ "url": "screenshot-webapp.jpg" }
|
||||
],
|
||||
"supports" : ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
{"name":"advcasio.app.js","url":"app.js"},
|
||||
{"name":"advcasio.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{ "name": "advcasio.data.json", "url": "data.json", "storageFile": true }
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
|
@ -0,0 +1 @@
|
|||
0.01: First, proof of concept
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# A-GPS Data
|
||||
|
||||
Load assisted GPS data directly to the watch using the new http requests on Android GadgetBridge.
|
||||
|
||||
Make sure:
|
||||
* your GadgetBridge version supports http requests
|
||||
* turn on internet access in GadgetBridge settings
|
||||
|
||||
Currently proof of concept on Bangle2 only. Will eventually add a widget for automatic download.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Creator
|
||||
[@pidajo](https://github.com/pidajo)
|
||||
|
|
@ -0,0 +1 @@
|
|||
atob("MDCEAAAAAAAAAAAAAAAAiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAACIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAACIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAACIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAAiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAIiIOIiIiAAAAAAAAAAAAAAAAAAAAAAAAIiDOIiIiAAAAAAAAAAAAAAAAAAAAAAAAIiDOIiIiIAAAAAAAAAAAAAAAAAAAAAACIiPOIiIiIAAAAAAAAAAAAAAAAAAAAAAiIj/OIiIiIgAAAAAAAAAAAAAAAAAAAAAiI//OIiIiIgAAAAAAAAAAAAAAAAAAAAAiI//OIiIiIiAAAAAAAAAAAAAAAAAAAAAiD//OIiIiIiAAAAAAAAAAAAAAAAAAAAIiP//OIiIiIiAAAAAAAAAAAAAAAAAAAAIg///OIiIiIiIAAAAAAAAAAAAAAAAAACIj///OIiIiIiIAAAAAAAAAAAAAAAAAACIP///OIiIiIiIgAAAAAAAAAAAAAAAAACI////OIiIiIiIgAAAAAAAAAAAAAAAAAiD////OIiIiIiIiAAAAAAAAAAAAAAAAAiP////OIiIiIiIiAAAAAAAAAAAAAAAAIiP////OIiIiIiIiIAAAAAAAAAAAAAAAIj/////OIiIiIiIiIAAAAAAAAAAAAAACIj/////OIiIiIiIiIgAAAAAAAAAAAAACI//////OIiIiIiIiIgAAAAAAAAAAAAAiI//////OIiIiIiIiIgAAAAAAAAAAAAAiIiIiIiIgzMzMzMziIiAAAAAAAAAAAAAiIiIiIiIj///////+IiAAAAAAAAAAAAIiIiIiIiIj////////4iIAAAAAAAAAAAIiIiIiIiIgzMzMzMzM4iIAAAAAAAAAACIP///////OIiIiIiIiIiIgAAAAAAAAACI////////OIiIiIiIiIiIgAAAAAAAAAiI////////OIiIiIiIiIiIiAAAAAAAAAiP////////OIiIiIiIiIiIiAAAAAAAAIiP////////OIiIiIiIiIiIiIAAAAAAAIj/////////OIiIiIiIiIiIiIAAAAAACIj////////ziIiIiIiIiIiIiIgAAAAACIP///////+IiIiIiIiIiIiIiIgAAAAACI//////84gYiIiIiIiIiIiIiIgAAAAAiD////84iIiAAAiIiIiIiIiIiIiAAAAAiP///ziIiIAAAAAIiIiIiIiIiIiAAAAIg/8ziIiIAAAAAAAAAIiIiIiIiIiIAAAIj/iIiIAAAAAAAAAAAAAIiIiIiIiIAACIiIiBgAAAAAAAAAAAAAAACIiIiIiIgACIiIgAAAAAAAAAAAAAAAAAAACIiIiIgACIgAAAAAAAAAAAAAAAAAAAAAAAiIiIgA==")
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
|
|
@ -0,0 +1,125 @@
|
|||
var _GB = global.GB;
|
||||
var counter = 0;
|
||||
|
||||
function GB(msg) {
|
||||
console.log(msg);
|
||||
if (msg.t == "http") {
|
||||
display("Received", "(" + msg.resp.length + ") Touch to apply", () => {
|
||||
display("Apply data..", "");
|
||||
setTimeout(() => {
|
||||
if (setAGPS(msg.resp)) {
|
||||
display("Success", "Touch for restart", httpTest);
|
||||
}
|
||||
else {
|
||||
display("Error", "Touch for restart", httpTest);
|
||||
}
|
||||
}, 1);
|
||||
});
|
||||
}
|
||||
if (_GB) {
|
||||
_GB(msg);
|
||||
}
|
||||
}
|
||||
|
||||
function setAGPS(data) {
|
||||
var js = jsFromBase64(data);
|
||||
console.log(js);
|
||||
try {
|
||||
eval(js);
|
||||
return true;
|
||||
}
|
||||
catch(e) {
|
||||
console.log("Error:", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function jsFromBase64(b64) {
|
||||
var bin = atob(b64);
|
||||
var chunkSize = 128;
|
||||
var js = "Bangle.setGPSPower(1);\n"; // turn GPS on
|
||||
var gnss_select="1";
|
||||
js += `Serial1.println("${CASIC_CHECKSUM("$PCAS04,"+gnss_select)}")\n`; // set GNSS mode
|
||||
// What about:
|
||||
// NAV-TIMEUTC (0x01 0x10)
|
||||
// NAV-PV (0x01 0x03)
|
||||
// or AGPS.zip uses AID-INI (0x0B 0x01)
|
||||
|
||||
for (var i=0;i<bin.length;i+=chunkSize) {
|
||||
var chunk = bin.substr(i,chunkSize);
|
||||
js += `Serial1.write(atob("${btoa(chunk)}"))\n`;
|
||||
}
|
||||
return js;
|
||||
}
|
||||
|
||||
function CASIC_CHECKSUM(cmd) {
|
||||
var cs = 0;
|
||||
for (var i=1;i<cmd.length;i++)
|
||||
cs = cs ^ cmd.charCodeAt(i);
|
||||
return cmd+"*"+cs.toString(16).toUpperCase().padStart(2, '0');
|
||||
}
|
||||
|
||||
function display(text1, text2, next) {
|
||||
g.reset();
|
||||
g.clear();
|
||||
var img = require("Storage").read("agpsdata.img");
|
||||
if (img) {
|
||||
g.drawImage(img, g.getWidth() - 48, g.getHeight()-48-24);
|
||||
}
|
||||
g.setFont("Vector", 30);
|
||||
g.setFontAlign(0, 1);
|
||||
g.drawString(text1, g.getWidth() / 2, g.getHeight() / 3 + 24);
|
||||
g.setFont("Vector", 15);
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString(text2, 0, g.getHeight() / 3 + 29);
|
||||
Bangle.drawWidgets();
|
||||
nextStep = null;
|
||||
if (next) {
|
||||
nextStep = next;
|
||||
}
|
||||
}
|
||||
|
||||
function httpTest() {
|
||||
counter++;
|
||||
display("AGPS Data", "Touch for start", () => {
|
||||
display("Request...", "Touch for restart", httpTest);
|
||||
if (Bluetooth.println) {
|
||||
console.log("On device");
|
||||
Bluetooth.println(JSON.stringify({t:"info", msg:"HTTP Request"}));
|
||||
Bluetooth.println(JSON.stringify({t:"http", url:"https://www.espruino.com/agps/casic.base64"}));
|
||||
}
|
||||
else {
|
||||
console.log("Testing on Emulator");
|
||||
setTimeout(() => {
|
||||
GB({t:"http", resp:testData});
|
||||
}, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var nextStep = null;
|
||||
|
||||
Bangle.on("touch", () => {
|
||||
if (nextStep) {
|
||||
nextStep();
|
||||
}
|
||||
});
|
||||
|
||||
httpTest();
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
|
||||
/*
|
||||
require("Storage").write("httptest.info",{
|
||||
"id":"httptest",
|
||||
"name":"Http Test",
|
||||
"src":"httptest.js",
|
||||
"icon":"wristlight.img"
|
||||
});
|
||||
*/
|
||||
|
||||
var testData = "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";
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{ "id": "agpsdata",
|
||||
"name": "A-GPS Data",
|
||||
"shortName":"AGPS Data",
|
||||
"icon": "agpsdata.png",
|
||||
"version":"0.01",
|
||||
"description": "Download assisted GPS data directly to watch",
|
||||
"tags": "assisted,gps,agps,http",
|
||||
"allow_emulator":true,
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme":"README.md",
|
||||
"screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot2.png" }, { "url":"screenshot3.png" }, { "url":"screenshot4.png" }, { "url":"screenshot5.png" } ],
|
||||
"storage": [
|
||||
{"name":"agpsdata.app.js","url":"app.js"},
|
||||
{"name":"agpsdata.img","url":"agpsdata-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 959 B |
|
After Width: | Height: | Size: 613 B |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 578 B |
|
|
@ -32,3 +32,5 @@
|
|||
0.30: Fix "Enable All"
|
||||
0.31: Add seconds to timers
|
||||
0.32: Fix wrong hidden filter
|
||||
Add option for auto-delete a timer after it expires
|
||||
|
||||
|
|
|
|||
|
|
@ -280,6 +280,10 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
|
|||
value: timer.on,
|
||||
onchange: v => timer.on = v
|
||||
},
|
||||
/*LANG*/"Delete After Expiration": {
|
||||
value: timer.del,
|
||||
onchange: v => timer.del = v
|
||||
},
|
||||
/*LANG*/"Vibrate": require("buzz_menu").pattern(timer.vibrate, v => timer.vibrate = v),
|
||||
/*LANG*/"Cancel": () => showMainMenu()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@
|
|||
0.08: Handling of alarms
|
||||
0.09: Alarm vibration, repeat, and auto-snooze now handled by sched
|
||||
0.10: Fix SMS bug
|
||||
0.11: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "android",
|
||||
"name": "Android Integration",
|
||||
"shortName": "Android",
|
||||
"version": "0.11",
|
||||
"version": "0.12",
|
||||
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
}),
|
||||
/*LANG*/"Keep Msgs" : {
|
||||
value : !!settings.keep,
|
||||
format : v=>v?/*LANG*/"Yes":/*LANG*/"No",
|
||||
onchange: v => {
|
||||
settings.keep = v;
|
||||
updateSettings();
|
||||
|
|
|
|||
|
|
@ -9,4 +9,5 @@
|
|||
when weekday name and calendar weeknumber are on then display is <weekday short> #<calweek>
|
||||
week is buffered until date or timezone changes
|
||||
0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users)
|
||||
0.08: fixed calendar weeknumber not shortened to two digits
|
||||
0.08: fixed calendar weeknumber not shortened to two digits
|
||||
0.09: Use default Bangle formatter for booleans
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "antonclk",
|
||||
"name": "Anton Clock",
|
||||
"version": "0.08",
|
||||
"version": "0.09",
|
||||
"description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.",
|
||||
"readme":"README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
(function(back) {
|
||||
var FILE = "antonclk.json";
|
||||
// Load settings
|
||||
var settings = Object.assign({
|
||||
secondsOnUnlock: false,
|
||||
}, require('Storage').readJSON(FILE, true) || {});
|
||||
|
|
@ -41,7 +40,6 @@
|
|||
"Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]),
|
||||
"Show Weekday": {
|
||||
value: (settings.weekDay !== undefined ? settings.weekDay : true),
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.weekDay = v;
|
||||
writeSettings();
|
||||
|
|
@ -49,7 +47,6 @@
|
|||
},
|
||||
"Show CalWeek": {
|
||||
value: (settings.calWeek !== undefined ? settings.calWeek : false),
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.calWeek = v;
|
||||
writeSettings();
|
||||
|
|
@ -57,7 +54,6 @@
|
|||
},
|
||||
"Uppercase": {
|
||||
value: (settings.upperCase !== undefined ? settings.upperCase : true),
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.upperCase = v;
|
||||
writeSettings();
|
||||
|
|
@ -65,7 +61,6 @@
|
|||
},
|
||||
"Vector font": {
|
||||
value: (settings.vectorFont !== undefined ? settings.vectorFont : false),
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.vectorFont = v;
|
||||
writeSettings();
|
||||
|
|
@ -82,7 +77,6 @@
|
|||
"Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]),
|
||||
"With \":\"": {
|
||||
value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true),
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.secondsWithColon = v;
|
||||
writeSettings();
|
||||
|
|
@ -90,7 +84,6 @@
|
|||
},
|
||||
"Color": {
|
||||
value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true),
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.secondsColoured = v;
|
||||
writeSettings();
|
||||
|
|
@ -99,9 +92,6 @@
|
|||
"Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"])
|
||||
};
|
||||
|
||||
// Actually display the menu
|
||||
E.showMenu(mainmenu);
|
||||
|
||||
});
|
||||
|
||||
// end of file
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Barometer altitude adjustment setting
|
||||
0.03: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "bikespeedo",
|
||||
"name": "Bike Speedometer (beta)",
|
||||
"shortName": "Bike Speedometer",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Shows GPS speed, GPS heading, Compass heading, GPS altitude and Barometer altitude from internal sources",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"Screenshot.png"}],
|
||||
|
|
|
|||
|
|
@ -33,12 +33,10 @@
|
|||
'< Back': function() { E.showMenu(appMenu); },
|
||||
'Speed' : {
|
||||
value : settings.spdFilt,
|
||||
format : v => v?"On":"Off",
|
||||
onchange : () => { settings.spdFilt = !settings.spdFilt; writeSettings(); }
|
||||
},
|
||||
'Altitude' : {
|
||||
value : settings.altFilt,
|
||||
format : v => v?"On":"Off",
|
||||
onchange : () => { settings.altFilt = !settings.altFilt; writeSettings(); }
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,3 +22,4 @@
|
|||
Restructure the settings menu
|
||||
0.08: Allow scanning for devices in settings
|
||||
0.09: Misc Fixes and improvements (https://github.com/espruino/BangleApps/pull/1655)
|
||||
0.10: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "bthrm",
|
||||
"name": "Bluetooth Heart Rate Monitor",
|
||||
"shortName": "BT HRM",
|
||||
"version": "0.09",
|
||||
"version": "0.10",
|
||||
"description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
|||
|
|
@ -85,14 +85,12 @@
|
|||
'< Back': function() { E.showMenu(buildMainMenu()); },
|
||||
'Alert on disconnect': {
|
||||
value: !!settings.warnDisconnect,
|
||||
format: v => settings.warnDisconnect ? "On" : "Off",
|
||||
onchange: v => {
|
||||
writeSettings("warnDisconnect",v);
|
||||
}
|
||||
},
|
||||
'Debug log': {
|
||||
value: !!settings.debuglog,
|
||||
format: v => settings.debuglog ? "On" : "Off",
|
||||
onchange: v => {
|
||||
writeSettings("debuglog",v);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@
|
|||
0.08: Do not register as watch, manually start clock on button
|
||||
read start of week from system settings
|
||||
0.09: Fix scope of let variables
|
||||
0.10: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "calendar",
|
||||
"name": "Calendar",
|
||||
"version": "0.09",
|
||||
"version": "0.10",
|
||||
"description": "Simple calendar",
|
||||
"icon": "calendar.png",
|
||||
"screenshots": [{"url":"screenshot_calendar.png"}],
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
"< Back": () => back(),
|
||||
'B2 Colors': {
|
||||
value: settings.ndColors,
|
||||
format: v => v ? "Yes" : "No",
|
||||
onchange: v => {
|
||||
settings.ndColors = v;
|
||||
writeSettings();
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
1.00: New App!
|
||||
1.01: Use fractional numbers and scale the points to keep working consistently on whole screen
|
||||
0.01: New App!
|
||||
0.02: Use fractional numbers and scale the points to keep working consistently on whole screen
|
||||
0.03: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Touchscreen Calibration",
|
||||
"shortName":"Calibration",
|
||||
"icon": "calibration.png",
|
||||
"version":"1.01",
|
||||
"version":"0.03",
|
||||
"description": "A simple calibration app for the touchscreen",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
"< Back" : () => back(),
|
||||
'Active': {
|
||||
value: !!settings.active,
|
||||
format: v => v? "On":"Off",
|
||||
onchange: v => {
|
||||
settings.active = v;
|
||||
writeSettings();
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@
|
|||
0.04: Change to 7 segment font, move to top widget bar
|
||||
Better auto-update behaviour, less RAM used
|
||||
0.05: Fix error running app on new firmwares (fix #1140)
|
||||
0.06: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ function showMenu() {
|
|||
},
|
||||
'Timer on': {
|
||||
value: settingsChronowid.started,
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settingsChronowid.started = v;
|
||||
updateSettings();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "chronowid",
|
||||
"name": "Chrono Widget",
|
||||
"shortName": "Chrono Widget",
|
||||
"version": "0.05",
|
||||
"version": "0.06",
|
||||
"description": "Chronometer (timer) which runs as widget.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,widget",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: Initial upload
|
||||
0.02: Added scrollable calendar and swipe gestures
|
||||
0.03: Configurable drag gestures
|
||||
0.04: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "clockcal",
|
||||
"name": "Clock & Calendar",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Clock with Calendar",
|
||||
"readme":"README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
"< Back": () => back(),
|
||||
'Buzz(dis)conn.?': {
|
||||
value: settings.BUZZ_ON_BT,
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.BUZZ_ON_BT = v;
|
||||
writeSettings();
|
||||
|
|
@ -59,7 +58,6 @@
|
|||
},
|
||||
'Red Saturday?': {
|
||||
value: settings.REDSAT,
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.REDSAT = v;
|
||||
writeSettings();
|
||||
|
|
@ -67,7 +65,6 @@
|
|||
},
|
||||
'Red Sunday?': {
|
||||
value: settings.REDSUN,
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
settings.REDSUN = v;
|
||||
writeSettings();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New app
|
||||
0.02: Cleanup interface and add settings, widget, add skin temp reporting.
|
||||
0.03: Move code for recording to this app
|
||||
0.04: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "coretemp",
|
||||
"name": "CoreTemp",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Display CoreTemp device sensor data",
|
||||
"icon": "coretemp.png",
|
||||
"type": "app",
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ const menu = {
|
|||
'< Back' : back,
|
||||
'Enabled' : {
|
||||
value : !!s.enabled,
|
||||
format : v => v ? "Yes" : "No",
|
||||
onchange : v => {
|
||||
s.enabled = v;
|
||||
updateSettings();
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@
|
|||
0.04: added heart rate which is switched on when cycled to it through up/down touch on rhs
|
||||
0.05: changed text to uppercase, just looks better, removed colons on text
|
||||
0.06: better contrast for light theme, use fg color instead of dithered for ring
|
||||
0.07: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "daisy",
|
||||
"name": "Daisy",
|
||||
"version":"0.06",
|
||||
"version":"0.07",
|
||||
"dependencies": {"mylocation":"app"},
|
||||
"description": "A beautiful digital clock with large ring guage, idle timer and a cyclic information line that includes, day, date, steps, battery, sunrise and sunset times",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
},
|
||||
'Idle Warning': {
|
||||
value: !!s.idle_check,
|
||||
format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
|
||||
onchange: v => {
|
||||
s.idle_check = v;
|
||||
save();
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@
|
|||
0.04: Move code to Arwes Module
|
||||
0.05: Add icon
|
||||
0.06: remove app image as it is unused
|
||||
0.07: Bump version number for change to apps.json causing 404 on upload
|
||||
0.07: Bump version number for change to apps.json causing 404 on upload
|
||||
0.08: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "dane_tcr",
|
||||
"name": "DANE Touch Launcher",
|
||||
"shortName": "DANE Toucher",
|
||||
"version": "0.07",
|
||||
"version": "0.08",
|
||||
"description": "Touch enable left to right launcher in the style of the DANE Watchface",
|
||||
"icon": "app.png",
|
||||
"type": "launch",
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
},
|
||||
"Animation" : {
|
||||
value : settings.animation,
|
||||
format : v => v?"On":"Off",
|
||||
onchange : saveChange('animation')
|
||||
},
|
||||
"Frame rate" : {
|
||||
|
|
@ -51,7 +50,6 @@
|
|||
},
|
||||
"Debug" : {
|
||||
value : settings.debug,
|
||||
format : v => v?"On":"Off",
|
||||
onchange : saveChange('debug')
|
||||
},
|
||||
'< Back': back
|
||||
|
|
|
|||
|
|
@ -13,3 +13,4 @@
|
|||
0.13: Added swipeExit setting so that left-right to exit is an option
|
||||
0.14: Don't move pages when doing exit swipe - Bangle 2.
|
||||
0.15: 'Swipe to exit'-code is slightly altered to be more reliable - Bangle 2.
|
||||
0.16: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "dtlaunch",
|
||||
"name": "Desktop Launcher",
|
||||
"version": "0.15",
|
||||
"version": "0.16",
|
||||
"description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.",
|
||||
"screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}],
|
||||
"icon": "icon.png",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
"< Back" : () => back(),
|
||||
'Show clocks': {
|
||||
value: settings.showClocks,
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.showClocks = v;
|
||||
writeSettings();
|
||||
|
|
@ -23,7 +22,6 @@
|
|||
},
|
||||
'Show launchers': {
|
||||
value: settings.showLaunchers,
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.showLaunchers = v;
|
||||
writeSettings();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
"< Back" : () => back(),
|
||||
'Show clocks': {
|
||||
value: settings.showClocks,
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.showClocks = v;
|
||||
writeSettings();
|
||||
|
|
@ -26,7 +25,6 @@
|
|||
},
|
||||
'Show launchers': {
|
||||
value: settings.showLaunchers,
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.showLaunchers = v;
|
||||
writeSettings();
|
||||
|
|
@ -34,7 +32,6 @@
|
|||
},
|
||||
'Direct launch': {
|
||||
value: settings.direct,
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.direct = v;
|
||||
writeSettings();
|
||||
|
|
@ -42,7 +39,6 @@
|
|||
},
|
||||
'Swipe Exit': {
|
||||
value: settings.swipeExit,
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.swipeExit = v;
|
||||
writeSettings();
|
||||
|
|
@ -50,7 +46,6 @@
|
|||
},
|
||||
'One click exit': {
|
||||
value: settings.oneClickExit,
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.oneClickExit = v;
|
||||
writeSettings();
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: Created the app. The logo bounces and buzz when it hits the angles.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Bouncing DVD logo
|
||||
|
||||
Have you ever wanted to admire the bouncing DVD logo on your watch? Now you can! Let's hope it touches an angle.
|
||||
|
||||

|
||||
|
||||
## Creator
|
||||
|
||||
I'm [TrinTragula](https://github.com/TrinTragula) on Github. Feel free to reach me.
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwhC/AH4A/AH4A/ACWIAA4MJwAXPhALKC5AlCBZYADE4gXELQ4SDC4gCBC4IDCAwYTEBAghCBYYCEC5YUFAooOIBBAKDMwwIFCwQIDNIZtGTRANEEIiyMVYrYHLIq0GQA4OGABIPPAA77GC8CDGABAfFBAbpCAIIfCAQqmJhAXDhB4CCIMIEgIYETAoaCC5zYHIIRQDDATAKPJasWAH4A/AH4A/AE4"))
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// The DVD logo
|
||||
var dvdLogo = require("heatshrink").decompress(atob("3dTwIFC/4AG/ALCgYJEwAcDj4XHBgYJF4AJCg4WH8AMCn4KFF4YWH/wLCh4KJIpA7CgIKG+BnHOg1/BYxGCCw4LDHQ/8IpQ6CQBBRBIpBpDBY4uCKA6jDUQy8FTIn3EQYIBGYSQDBYTVF/x0DKITMGFwh4D96jDKILuDDoSvDEAn9AQIeDB4glCwA5ELwW/FIRNB/x2BVQSvDHIgIB+ZvCNwWPOwZ7DAYKEFDwJoBAYPhHgYeC8ADCP4QEB85YCEQRFELoIqBBA5oFL4SMEwBFEBAWfDwQFB4K1EJoPwIooIB+InCHIQ8EOgYIHA4PAIQP8IogqCBYQIFw4TBAoRICIoQiB/AaDBAfwJAOAUwTrEFQZFHAQPwCYPwCIIxBWIZFIwICBSIIKBIo4IHFYXgSwRFKBARFCFYLlC8DDCRZTaDOIPPHgngaIhFFBoQfB/YhCIojRDBAg/B/gaCGYRFEHgaUED4IEBD4JBDIAIDBLgQEBIoYbC4AMCHAQcBG4IbCAgJFDCQRlBJIIzCIogJCBAgWCD4IICHARFDCwQIEIAY7DGYRmBEAIWCBAJOCNwYfBPAQSBEIWDMog8DAAQfBUYYzEAATkCBAq+CGgQzEYQgIGD4Q3CGYJnDKYhFGCwLtEVAjQDIow2BawY8HNQQIFCwR0CfYgWFBAoWDEAJ5CIogWCIooHCEAR5CJQQWFIoYPCOgg0BHgiJBIooHDUYaCCIoRLCABl/CB4AFg5MFACBNGAB8fQYYARgL/CACc/CysHLisAuAWVhgWVgL/BCyn/WyX/AAx4Mv4VHAARLJFZAAEbA5VBABwWFh4WPJAs/CZoODOA3A/8H/k//BNBK4N/AQQPB/wWF/kf4P/w4jBg4+BKIMAgYuC/BEF4P4n/w//gEIPwCYJYBCAYLBT4f4n0P/0f/k+g/+FoPwn4uDHQYACwZFB4ZHB8A2BKAQYBCAXwW4nwuF//BCBFgJ3CwZ/BCAR1BUIkEJYJHCFgINB+F/GgIAC4BLENgXhI4J5B8BfCI4KMEFwY0BKoK6BvwSDYoIoDCAIuE8APBXQMPwJaC/kPDALqEGgf8NAK6NAoLpDTYS6CCAKCCAoK+BCwhYBMYQiBXQOALQQ2BAQQWFXggAMGoIAECx6gBAArVEABJDDAAhQDABCTBABIYJ4AVKAAbCDChYA="));
|
||||
|
||||
// Screen width
|
||||
const WIDTH = g.getWidth();
|
||||
// Screen height
|
||||
const HEIGHT = g.getHeight();
|
||||
// dvd logo image width
|
||||
const IMG_WIDTH = 94;
|
||||
/// dvd logo image height
|
||||
const IMG_HEIGHT = 42;
|
||||
|
||||
// Assign a random X and Y initial speed between 1.5 and 1
|
||||
var speedX = 1.5 - Math.random() / 2;
|
||||
var speedY = 1.5 - Math.random() / 2;
|
||||
// The logo X and Y position
|
||||
var posX = 0;
|
||||
var posY = 0;
|
||||
|
||||
// The current logo color
|
||||
var currentColor = "#ff00ff";
|
||||
|
||||
// Get a random value between "ff" and "00"
|
||||
function getHexColor() {
|
||||
if (Math.round(Math.random())) {
|
||||
return "ff";
|
||||
} else {
|
||||
return "00";
|
||||
}
|
||||
}
|
||||
|
||||
// Get a new 8 bit color
|
||||
function getNewColor() {
|
||||
return "#" + getHexColor() + getHexColor() + getHexColor();
|
||||
}
|
||||
|
||||
// Change the dvd logo color on impact
|
||||
// Only allow colors different from the current one
|
||||
// and different from the bg
|
||||
function changeColor() {
|
||||
var newColor = getNewColor();
|
||||
while (newColor == currentColor || newColor == "#000000") {
|
||||
newColor = getNewColor();
|
||||
}
|
||||
currentColor = newColor;
|
||||
g.setColor(newColor);
|
||||
}
|
||||
|
||||
// Draw the logo
|
||||
function draw() {
|
||||
// Move it
|
||||
posX += speedX;
|
||||
posY += speedY;
|
||||
|
||||
var collisions = 0;
|
||||
// Collision detection
|
||||
if (posX <= 0) {
|
||||
speedX = -speedX;
|
||||
posX = 0;
|
||||
collisions++;
|
||||
}
|
||||
if (posY <= 0) {
|
||||
speedY = -speedY;
|
||||
posY = 0;
|
||||
collisions++;
|
||||
}
|
||||
if (posX >= (WIDTH - IMG_WIDTH)) {
|
||||
speedX = -speedX;
|
||||
posX = WIDTH - IMG_WIDTH;
|
||||
collisions++;
|
||||
}
|
||||
if (posY >= (HEIGHT - IMG_HEIGHT)) {
|
||||
speedY = -speedY;
|
||||
posY = HEIGHT - IMG_HEIGHT;
|
||||
collisions++;
|
||||
}
|
||||
|
||||
// If we detected 2 collisions, we touched an angle, HURRAY!
|
||||
if (collisions > 1) {
|
||||
Bangle.buzz();
|
||||
}
|
||||
|
||||
// Change logo color on collision
|
||||
if (collisions > 0) {
|
||||
changeColor();
|
||||
}
|
||||
|
||||
// Actually draw the logo
|
||||
g.clear();
|
||||
g.drawImage(dvdLogo, posX, posY, {
|
||||
scale: 0.5
|
||||
});
|
||||
setTimeout(function () {
|
||||
draw();
|
||||
}, 15);
|
||||
}
|
||||
|
||||
// Set the background to black
|
||||
g.setBgColor(0, 0, 0);
|
||||
// Start from purple
|
||||
g.setColor(currentColor);
|
||||
// Clear the screen
|
||||
g.clear();
|
||||
// Start drawing
|
||||
draw();
|
||||
|
||||
// Exit on button press
|
||||
setWatch(Bangle.showLauncher, BTN, { repeat: false, edge: "falling" });
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id": "dvdbounce",
|
||||
"name": "Bouncing DVD logo",
|
||||
"shortName": "Bouncing DVD",
|
||||
"version": "0.01",
|
||||
"description": "Have you ever wanted to admire the bouncing DVD logo on your watch? Now you can! Let's hope it touches an angle.",
|
||||
"icon": "dvdbounce.png",
|
||||
"tags": "game",
|
||||
"supports": [
|
||||
"BANGLEJS",
|
||||
"BANGLEJS2"
|
||||
],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{
|
||||
"name": "dvdbounce.app.js",
|
||||
"url": "dvdbounce.app.js"
|
||||
},
|
||||
{
|
||||
"name": "dvdbounce.img",
|
||||
"url": "dvdbounce-icon.js",
|
||||
"evaluate": true
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
{
|
||||
"url": "screenshot.gif"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 116 KiB |
|
|
@ -1,7 +1,5 @@
|
|||
const store = require('Storage');
|
||||
|
||||
const boolFormat = (v) => v ? "On" : "Off";
|
||||
|
||||
function showMainMenu() {
|
||||
const mainmenu = {
|
||||
'': {
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@
|
|||
0.08: Bug fix at end of the game with victorious splash and glorious orchestra
|
||||
0.09: Added settings menu, removed symbol selection button (*), added highscore reset
|
||||
0.10: fixed clockmode in settings
|
||||
0.11: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "game1024",
|
||||
"name": "1024 Game",
|
||||
"shortName" : "1024 Game",
|
||||
"version": "0.10",
|
||||
"version": "0.11",
|
||||
"icon": "game1024.png",
|
||||
"screenshots": [ {"url":"screenshot.png" } ],
|
||||
"readme":"README.md",
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
}
|
||||
},
|
||||
"Exit press:": {
|
||||
value: !settings.clockMode, // ! converts undefined to true
|
||||
value: !settings.clockMode,
|
||||
format: v => v?"short":"long",
|
||||
onchange: v => {
|
||||
settings.clockMode = v;
|
||||
|
|
@ -40,8 +40,7 @@
|
|||
},
|
||||
},
|
||||
"Debug mode:": {
|
||||
value: !!settings.debugMode, // !! converts undefined to false
|
||||
format: v => v?"On":"Off",
|
||||
value: !!settings.debugMode,
|
||||
onchange: v => {
|
||||
settings.debugMode = v;
|
||||
writeSettings();
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@
|
|||
0.09: Move event listener from widget to boot code, stops music from showing up in messages
|
||||
0.10: Simplify touch events
|
||||
Remove date+time
|
||||
0.11: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "gbmusic",
|
||||
"name": "Gadgetbridge Music Controls",
|
||||
"shortName": "Music Controls",
|
||||
"version": "0.10",
|
||||
"version": "0.11",
|
||||
"description": "Control the music on your Gadgetbridge-connected phone",
|
||||
"icon": "icon.png",
|
||||
"screenshots": [{"url":"screenshot_v1_d.png"},{"url":"screenshot_v1_l.png"},
|
||||
|
|
|
|||
|
|
@ -25,19 +25,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
const yesNo = (v) => translate(v ? "Yes" : "No");
|
||||
let menu = {
|
||||
"": {"title": "Music Control"},
|
||||
};
|
||||
menu[translate("< Back")] = back;
|
||||
menu[translate("Auto start")] = {
|
||||
value: !!s.autoStart,
|
||||
format: yesNo,
|
||||
onchange: save("autoStart"),
|
||||
};
|
||||
menu[translate("Simple button")] = {
|
||||
value: !!s.simpleButton,
|
||||
format: yesNo,
|
||||
onchange: save("simpleButton"),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,3 +27,4 @@
|
|||
0.25: workaround call notification
|
||||
Fix inflated step number
|
||||
0.26: Include charging status in battery updates to phone
|
||||
0.27: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "gbridge",
|
||||
"name": "Gadgetbridge",
|
||||
"version": "0.26",
|
||||
"version": "0.27",
|
||||
"description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android Integration' Bangle.js app instead.",
|
||||
"icon": "app.png",
|
||||
"type": "widget",
|
||||
|
|
|
|||
|
|
@ -27,13 +27,11 @@
|
|||
"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" },
|
||||
"Show Icon" : {
|
||||
value: settings().showIcon,
|
||||
format: v => v?"Yes":"No",
|
||||
onchange: setIcon
|
||||
},
|
||||
"Find Phone" : function() { E.showMenu(findPhone); },
|
||||
"Record HRM" : {
|
||||
value: !!settings().hrm,
|
||||
format: v => v?"Yes":"No",
|
||||
onchange: v => updateSetting('hrm', v)
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Set Bangle.js 2 compatible
|
||||
0.03: Add setting to hide the widget
|
||||
0.04: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "gpsautotime",
|
||||
"name": "GPS auto time",
|
||||
"shortName": "GPS auto time",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A widget that automatically updates the Bangle.js time to the GPS time whenever there is a valid GPS fix.",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@
|
|||
E.showMenu({
|
||||
"" : { "title" : "GPS auto time" },
|
||||
"< Back" : () => back(),
|
||||
'Show widget?': {
|
||||
value: !!settings.show, // !! converts undefined to false
|
||||
format: v => v?"Show":"Hide",
|
||||
'Show Widgets': {
|
||||
value: !!settings.show,
|
||||
onchange: v => {
|
||||
settings.show = v;
|
||||
writeSettings();
|
||||
|
|
|
|||
|
|
@ -30,3 +30,4 @@
|
|||
0.26: Multiple bugfixes
|
||||
0.27: Map drawing with light theme (fix #1023)
|
||||
0.28: Show distance more accurately in conjunction with new locale app (fix #1523)
|
||||
0.29: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ function showMainMenu() {
|
|||
'': { 'title': 'GPS Record' },
|
||||
'RECORD': {
|
||||
value: !!settings.recording,
|
||||
format: v=>v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.recording = v;
|
||||
updateSettings();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "gpsrec",
|
||||
"name": "GPS Recorder",
|
||||
"version": "0.28",
|
||||
"version": "0.29",
|
||||
"description": "(NOT RECOMMENDED) - please use the more flexible 'Recorder' app instead. Application that allows you to record a GPS track. Can run in background",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,outdoors,gps,widget",
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: Release
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# Home Assistant
|
||||
This app integrates your BangleJs into the HomeAssistant.
|
||||
|
||||
# How to use
|
||||
Click on the left and right side of the screen to select the triggers that you
|
||||
configured. Click in the middle of the screen to send the trigger to HomeAssistant.
|
||||
|
||||

|
||||
|
||||
# First Setup
|
||||
1.) First of all, make sure that HomeAssistant and the HomeAssistant Android App works.
|
||||
|
||||
2.) Open your BangleJs Gadgetbridge App, click on the Settings icon of your BangleJs and enable "Allow Intent Access"
|
||||
|
||||
3.) Enable sensor in HomeAssistant Andoird App/Configuration/Companion App/Manage Sensors/LastUpdate Trigger
|
||||
|
||||
4.) At the bottom of the same screen click on "Add New Intent" and enter "com.espruino.gadgetbridge.banglejs.HA"
|
||||
|
||||
5.) The HomeAssistant Android app must be restarted in order to listen for those actions
|
||||
-- a "Force Stop" is necessary (through Android App settings) or restart your phone!
|
||||
|
||||
This setup must be done only once -- now you are ready to configure your BangleJS to
|
||||
control some devices or entities in your HomeAssistant :)
|
||||
|
||||
# Setup Trigger
|
||||
1.) Upload the app and all corresponding triggers through the AppStore UI. You must specify
|
||||
the display name, the trigger as well as an icon.
|
||||
The following icons are currently supported:
|
||||
- ha (default)
|
||||
- light
|
||||
- door
|
||||
- fire
|
||||
|
||||
|
||||
2.) Create an "automation" in the HomeAssistant WebUI for each trigger that you created on your BangleJs in order to tell HomeAssistant what you want to control. A sample configuration is shown in the image below -- I use this trigger to open the door:
|
||||
|
||||

|
||||
|
||||
3.) Don't forget to select the action that should be executed at the bottom of each automation.
|
||||
|
||||
# Default Trigger
|
||||
This app also implements two default trigger that can always be used:
|
||||
- APP_STARTED -- Will be sent whenever the app is started. So you could do some actions already when the app is sarted without the need of any user interaction.
|
||||
- TRIGGER -- Will be sent whenever some trigger is executed. So you could generically listen to that.
|
||||
|
||||
|
||||
# FAQ
|
||||
|
||||
## Sometimes the trigger is not executed
|
||||
While playing and testing a bit I found that it is very important that you allow the android HomeAssistant app, as well as BangleJs Gadgetbridge app to (1) run in background and (2), disable energy optimizations for both apps.
|
||||
Otherwise, Android could stop one of both apps and the trigger will never be sent to HomeAssistant...
|
||||
|
||||
If you still have problems, you can try another trick:
|
||||
Install "MacroDroid" from the Android AppStore and start the HomeAssistant App
|
||||
each time the "com.espruino.gadgetbridge.banglejs.HA" intent is send together
|
||||
with the extra trigger: APP_STARTED. Then whenever you open the app on your BangleJs
|
||||
it is ensured that HomeAssistant is running...
|
||||
|
||||
## Thanks to
|
||||
<a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
|
||||
|
||||
## Creator
|
||||
- [David Peer](https://github.com/peerdavid).
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<h3>Upload Tigger</h3>
|
||||
<p><textarea id="triggers" style="width:500px; height:300px">
|
||||
[
|
||||
{"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"},
|
||||
{"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"},
|
||||
{"display": "Living Room", "trigger": "OVEN", "icon":"fire"}
|
||||
]</textarea></p>
|
||||
<p><button id="upload" class="btn btn-primary">Upload</button></p>
|
||||
|
||||
<script src="../../core/lib/customize.js"></script>
|
||||
|
||||
<script>
|
||||
/*
|
||||
* Load trigger from BangleJs
|
||||
*/
|
||||
console.log("Loading trigger from BangleJs...");
|
||||
try {
|
||||
Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{
|
||||
if(data.length > 0){
|
||||
document.getElementById("triggers").innerHTML = data;
|
||||
console.log("Loaded trigger from BangleJs.");
|
||||
}
|
||||
});
|
||||
} catch(ex) {
|
||||
console.log("(Warning) Could not load trigger from BangleJs.");
|
||||
console.log(ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload trigger to BangleJs
|
||||
*/
|
||||
document.getElementById("upload").addEventListener("click", function() {
|
||||
// get the text to add
|
||||
var triggerText = document.getElementById("triggers").value;
|
||||
// send finished app (in addition to contents of app.json)
|
||||
sendCustomizedApp({
|
||||
storage:[
|
||||
{name:"ha.trigger.json", url:"ha.trigger.json", content:triggerText},
|
||||
]
|
||||
});
|
||||
console.log("Sent ha.trigger.json!");
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
var storage = require("Storage");
|
||||
var W = g.getWidth(), H = g.getHeight();
|
||||
var position=0;
|
||||
|
||||
|
||||
// Note: All icons should have 48x48 pixels
|
||||
function getIcon(icon){
|
||||
if(icon == "light"){
|
||||
return {
|
||||
width : 48, height : 48, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress(atob("AAMBwAFE4AFDgYFJjgFBnAFBjwXBvAFBh4jBuAFCAQPwAQMHAQPgEQQCBEgcf/AvDn/8Aof//5GDAoJOBh+BAoOB+EP8YFB4fwgfnAoPnGANHAoPjHYQFBHYQFd44pDg47C4/gh/DIIZNFLIplGgF//wFIgZ9BRIUHRII7Ch4FBUIUOAoKzCjwFEhgCBmDpIVooFFh4oCAA4LFC5b7BAob1BAYI="))
|
||||
};
|
||||
} else if(icon == "door"){
|
||||
return {
|
||||
width : 48, height : 48, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress(atob("AAM4Aok/4AED///Aov4Aon8DgQGBAv4FpnIFKJv4FweAQFFAgQFB8AFDnADC"))
|
||||
};
|
||||
} else if (icon == "fire"){
|
||||
return {
|
||||
width : 48, height : 48, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress(atob("ABsDAokBwAFE4AFE8AFE+AFE/AFJgf8Aon+AocHAokP/8QAokYAoUfAok//88ApF//4kDAo//AgMQAgIFCjgFEjwFCOYIFFHQIFDn/+AoJ/BAoIqBAoN//xCBAoI5BDIPAgP//gFB8AFChYFBgf//EJAogOBAoSgBAoMHAQIFEFgXAAoJEBv4FCNoQFGVYd/wAFEYYIFIvwCBDoV8UwQCBcgUPwDwDfQMBaIYADA"))
|
||||
};
|
||||
}
|
||||
|
||||
// Default is always the HA icon
|
||||
return {
|
||||
width : 48, height : 48, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA=="))
|
||||
};
|
||||
}
|
||||
|
||||
// Try to read custom actions, otherwise use default
|
||||
var triggers = [
|
||||
{display: "Not found.", trigger: "NOP", icon: "ha"},
|
||||
];
|
||||
|
||||
try{
|
||||
triggers = storage.read("ha.trigger.json");
|
||||
triggers = JSON.parse(triggers);
|
||||
} catch(e) {
|
||||
// In case there are no user triggers yet, we show the default...
|
||||
}
|
||||
|
||||
|
||||
function sendIntent(trigger){
|
||||
var retries=3;
|
||||
|
||||
while(retries > 0){
|
||||
try{
|
||||
// Send a startup trigger such that we could also execute
|
||||
// an action when the app is started :)
|
||||
Bluetooth.println(JSON.stringify({
|
||||
t:"intent",
|
||||
action:"com.espruino.gadgetbridge.banglejs.HA",
|
||||
extra:{
|
||||
trigger: trigger
|
||||
}})
|
||||
);
|
||||
retries = -1;
|
||||
|
||||
} catch(e){
|
||||
retries--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function draw() {
|
||||
g.reset().clearRect(Bangle.appRect);
|
||||
|
||||
var h = 22;
|
||||
g.setFont("Vector", h);
|
||||
var trigger = triggers[position];
|
||||
var w = g.stringWidth(trigger.display);
|
||||
|
||||
g.setFontAlign(-1,-1);
|
||||
var icon = getIcon(trigger.icon);
|
||||
g.setColor(g.theme.fg).drawImage(icon, 12, H/5-2);
|
||||
g.drawString("Home", icon.width + 20, H/5);
|
||||
g.drawString("Assistant", icon.width + 18, H/5+24);
|
||||
|
||||
g.setFontAlign(0,0);
|
||||
var ypos = H/5*3+20;
|
||||
g.drawRect(W/2-w/2-8, ypos-h/2-8, W/2+w/2+5, ypos+h/2+5);
|
||||
g.fillRect(W/2-w/2-6, ypos-h/2-6, W/2+w/2+3, ypos+h/2+3);
|
||||
g.setColor(g.theme.bg).drawString(trigger.display, W/2, ypos);
|
||||
}
|
||||
|
||||
|
||||
Bangle.on('touch', function(btn, e){
|
||||
var left = parseInt(g.getWidth() * 0.3);
|
||||
var right = g.getWidth() - left;
|
||||
var isLeft = e.x < left;
|
||||
var isRight = e.x > right;
|
||||
|
||||
if(isRight){
|
||||
Bangle.buzz(40, 0.6);
|
||||
position += 1;
|
||||
position = position >= triggers.length ? 0 : position;
|
||||
draw();
|
||||
}
|
||||
|
||||
if(isLeft){
|
||||
Bangle.buzz(40, 0.6);
|
||||
position -= 1;
|
||||
position = position < 0 ? triggers.length-1 : position;
|
||||
draw();
|
||||
}
|
||||
|
||||
if(!isRight && !isLeft){
|
||||
|
||||
// Send a default intent that we triggered something.
|
||||
sendIntent("TRIGGER");
|
||||
|
||||
// Now send the selected trigger
|
||||
Bangle.buzz(80, 0.6).then(()=>{
|
||||
sendIntent(triggers[position].trigger);
|
||||
setTimeout(()=>{
|
||||
Bangle.buzz(80, 0.6);
|
||||
}, 250);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Send intent that the we started the app.
|
||||
sendIntent("APP_STARTED");
|
||||
|
||||
// Next load the widgets and draw the app
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
draw();
|
||||
setWatch(_=>load(), BTN1);
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwIjggOAAocH8AFDh/wAocfAok//gFDv/+Aof+vwoD/Ef3gFBgfwh4YCg/xx4FCh/z54FCj4LEn4XEv4jBGAX//k//4uBAokDAofAg/wnk8h/gLoIFE8ccnHH+Ef8+cnPn/EAAoYvB8ARBg4FB+EMmEPAoP4gkgj5BCwA+BAoXAHwIFC8EHAoZfBAoZfBAoZZDAsgAiA=="))
|
||||
|
After Width: | Height: | Size: 980 B |
|
After Width: | Height: | Size: 71 KiB |
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"id": "ha",
|
||||
"name": "HomeAssistant",
|
||||
"version": "0.01",
|
||||
"description": "Integrates your BangleJS into HomeAssistant.",
|
||||
"icon": "ha.png",
|
||||
"type": "app",
|
||||
"tags": "tool",
|
||||
"readme": "README.md",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"custom": "custom.html",
|
||||
"screenshots": [
|
||||
{"url":"screenshot.png"},
|
||||
{"url":"screenshot_2.png"},
|
||||
{"url":"screenshot_3.png"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"ha.trigger.json" }
|
||||
],
|
||||
"storage": [
|
||||
{"name":"ha.app.js","url":"ha.app.js"},
|
||||
{"name":"ha.img","url":"ha.icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
|
@ -1,3 +1,4 @@
|
|||
0.01: Add a number to match to turn off alarm
|
||||
0.02: Respect Quiet Mode
|
||||
0.03: Fix hour/minute wrapping code for new menu system
|
||||
0.04: Use default Bangle formatter for booleans
|
||||
|
|
|
|||
|
|
@ -66,17 +66,14 @@ function editAlarm(alarmIndex) {
|
|||
},
|
||||
/*LANG*/'Enabled': {
|
||||
value: en,
|
||||
format: v=>v?"On":"Off",
|
||||
onchange: v=>en=v
|
||||
},
|
||||
/*LANG*/'Repeat': {
|
||||
value: en,
|
||||
format: v=>v?"Yes":"No",
|
||||
onchange: v=>repeat=v
|
||||
},
|
||||
/*LANG*/'Auto snooze': {
|
||||
value: as,
|
||||
format: v=>v?"Yes":"No",
|
||||
onchange: v=>as=v
|
||||
}
|
||||
};
|
||||
|
|
|
|||