You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

361 lines
18 KiB

// Clock with large digits using the "Anton" bold font
Graphics.prototype.setFontAnton = function(scale) {
// Actual height 69 (68 - 0)
g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16));
};
{ // must be inside our own scope here so that when we are unloaded everything disappears
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
const STATE_IDLE = 0;
const STATE_GRID_OPEN_WAIT = 1;
const STATE_GRID_OPEN = 2;
const STATE_MENU_OPEN = 3;
let watchState = STATE_IDLE;
let myMessage = "";
let temperature = "";
let drawTimer = null;
let gridTimer = null;
let lockTimer = null;
let swipeLockout = false;
let grid = ["Office off", "Office 1/2", "Office on", "Kitchen off", "Kitchen 1/2", "Kitchen on", "Closet off", "Closet 1/2", "Closet on", "Window off", "Window 1/2", "Window on", "LStairs off", "LStairs 1/2", "LStairs on", "Nook off", "Nook 1/2", "Nook on", "SideEnt off", "SideEnt 1/2", "SideEnt on", "Theatre off", "Theatre 1/2", "Theatre on", "FPot off", "FPot 1/2", "FPot on", "SPot off", "SPot 1/2", "SPot on", "GuestBth off", "GuestBth 1/2", "GuestBth on", "Lab off", "Lab on", "Number off", "Number on", "BathFan off", "BathFan on", "VentFan off", "VentFan on", "Grow off", "Grow on", "", "", "Nook Air off", "Nook Air on", "Lab Air off", "Lab Air on", "Seeds off", "Seeds on", "Lamp off", "Lamp on", "Bed Air off", "Bed Air on", "Garage Plug off", "Garage Plug on", "Volume Down", "Volume Up", "Prev", "Next", "Pause", "Play", "", "Show Time", "Movie Time", "Guest 0", "Guest 1", "", "", "Motn Lk 0", "Motn Lk 1", "Refresh Grid", "Mark Time", "Disarm", "Arm Stay", "Arm Away", "Unlock Door", "Garage Door", "Test Alert", "Kill server"];
let gridNum = -1;
let prevNum = -1;
let gridDir = -1;
let menu = {"lights": {"upper": {"closet": {"off": null, "1/4": null, "1/2": null, "on": null}, "window": {"off": null, "1/4": null, "1/2": null, "on": null}, "guest bath": {"off": null, "1/4": null, "1/2": null, "on": null}, "office": {"off": null, "1/4": null, "1/2": null, "on": null}}, "middle": {"kitchen": {"off": null, "1/4": null, "1/2": null, "on": null}, "nook": {"off": null, "1/4": null, "1/2": null, "on": null}, "side ent": {"off": null, "1/4": null, "1/2": null, "on": null}}, "lower": {"lstairs": {"off": null, "1/4": null, "1/2": null, "on": null}, "theatre": {"off": null, "1/4": null, "1/2": null, "on": null}, "lab": {"off": null, "1/4": null, "1/2": null, "on": null}}, "misc": {"fpot": {"off": null, "1/4": null, "1/2": null, "on": null}, "spot": {"off": null, "1/4": null, "1/2": null, "on": null}, "number": {"off": null, "1/4": null, "1/2": null, "on": null}}}, "switches": {"fans": {"bath on": null, "bath off": null, "vent on": null, "vent off": null}, "hydro": {"grow on": null, "grow off": null, "seeds on": null, "seeds off": null}, "living": {"lr on": null, "lr off": null, "lamp on": null, "lamp off": null}, "air": {"bed on": null, "bed off": null, "lab on": null, "lab off": null}}, "states": {"scenes": {"bed time": null, "woke up": null, "show time": null, "movie time": null}, "modes": {"guest on": null, "guest off": null, "mlock on": null, "mlock off": null}}, "commands": {"media": {"prev": null, "next": null, "pause": null, "play": null}, "volume": {"up 10": null, "up 30": null, "down 10": null, "down 30": null}, "util": {"kill server": null, "arm stay": null, "test alert": null, "mark time": null}, "door": {"arm away": null, "disarm": null, "unlock": null, "garage": null}}};
let subMenu = null;
let menuCommand = "";
let paintFace = function() {
if (watchState != STATE_IDLE) return;
var x = g.getWidth() / 2;
var y = g.getHeight() / 2;
g.reset().clearRect(Bangle.appRect); // clear whole background (w/o widgets)
var date = new Date();
var timeStr = require("locale").time(date, 1); // Hour and minute
g.setFontAlign(0, 0).setFont("Anton").drawString(timeStr, x, y+20);
// Show date and day of week
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
var dateStr = date.getDate() + " " + days[date.getDay()] + " " + temperature;
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(dateStr, x, y+70);
//var wrapped = g.wrapString(myMessage, g.getWidth()-10).join("\n");
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(myMessage, x, y-45);
};
// Actually draw the watch face
let draw = function() {
if (Bangle.http){
Bangle.http("https://api.home.dns.t0.vc/bangle", {timeout:3000}).then(event => {
let result = JSON.parse(event.resp);
myMessage = result.context;
temperature = result.temperature;
if (watchState == STATE_IDLE) {
if (paintFace) paintFace();
}
}).catch((e)=>{
myMessage = "GET error";
if (paintFace) paintFace();
});
}
// queue next draw
if (drawTimer) clearTimeout(drawTimer);
drawTimer = setTimeout(function() {
drawTimer = undefined;
draw();
}, 60000 - (Date.now() % 60000));
};
let handleSwipe = function(dir1, dir2) {
var direction;
if (swipeLockout) return;
if (dir1 == 1) {
direction = "right";
} else if (dir1 == -1) {
direction = "left";
} else if (dir2 == 1) {
direction = "down";
} else if (dir2 == -1) {
direction = "up";
} else {
direction = "none";
}
if (Bangle.http){
const options = {timeout:3000, method: "post", body: direction};
Bangle.http("https://api.home.dns.t0.vc/bangle", options).then(event => {
myMessage = "Sent " + direction;
if (paintFace) paintFace();
}).catch((e)=>{
myMessage = "POST error";
if (paintFace) paintFace();
});
}
};
let drawGrid = function(touchX, touchY) {
let x = g.getWidth() / 2;
let y = g.getHeight() / 2;
let text = "";
let rank = "";
g.reset().clearRect(Bangle.appRect);
truncX = Math.floor(touchX/15);
truncY = Math.floor(touchY/15);
gridNum = -1;
gridDir = -1;
if (!grid) {
text = "Grid missing";
} else if (truncX < 2) {
text = "left";
gridDir = "left";
} else if (truncX > 10) {
text = "right";
gridDir = "right";
} else if (truncY < 2) {
text = "Repeat";
gridDir = "top";
} else if (truncY > 10) {
text = "Cancel";
gridDir = "bottom";
} else {
const gridX = truncX - 2;
const gridY = truncY - 2;
gridNum = gridY * 9 + gridX;
rank = "ABCDEFGHI"[gridY];
text = grid[gridNum];
}
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(text, x, y-45);
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(text, x, y+70);
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(rank, x-65, y+15);
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(rank, x+65, y+15);
};
let handleDrag = function(e) {
//console.log(e);
// { "x": 96, "y": 147, "b": 1, "dx": 0, "dy": 1 }
const touchX = e.x;
const touchY = e.y;
const pressed = Boolean(e.b);
if (watchState == STATE_IDLE && pressed) {
watchState = STATE_GRID_OPEN_WAIT;
gridTimer = setTimeout(function() {
watchState = STATE_GRID_OPEN;
drawGrid(touchX, touchY);
swipeLockout = true;
}, 500);
} else if (watchState == STATE_GRID_OPEN_WAIT && !pressed) {
watchState = STATE_IDLE;
if (gridTimer) clearTimeout(gridTimer);
} else if (watchState == STATE_GRID_OPEN && !pressed) {
watchState = STATE_IDLE;
if (lockTimer) clearTimeout(lockTimer);
lockTimer = setTimeout(function() {
swipeLockout = false;
}, 2000);
if (gridNum >= 0 && grid[gridNum]) {
myMessage = grid[gridNum];
prevNum = gridNum;
if (Bangle.http){
const options = {timeout:3000, method: "post", body: gridNum};
Bangle.http("https://api.home.dns.t0.vc/grid", options).then(event => {
myMessage = "ok";
if (paintFace) paintFace();
}).catch((e)=>{
myMessage = "POST error";
if (paintFace) paintFace();
});
}
gridNum = -1;
} else if (gridDir == "top") {
if (prevNum >= 0) {
myMessage = grid[prevNum];
if (Bangle.http){
const options = {timeout:3000, method: "post", body: prevNum};
Bangle.http("https://api.home.dns.t0.vc/grid", options).then(event => {
myMessage = "ok";
if (paintFace) paintFace();
}).catch((e)=>{
myMessage = "POST error";
if (paintFace) paintFace();
});
}
} else {
myMessage = "No repeat";
}
} else if (gridDir == "bottom") {
myMessage = "Cancelled";
Bangle.setLocked(true);
}
if (paintFace) paintFace();
} else if (watchState == STATE_GRID_OPEN && pressed) {
drawGrid(touchX, touchY);
}
};
let drawMenu = function(menu) {
const keys = Object.keys(menu);
g.reset().clearRect(Bangle.appRect);
g.drawLine(88, 0, 88, 175); // |
g.drawLine(0, 88, 175, 88); // --
const wrap = function(text) {
return g.wrapString(text, 80).join("\n");
};
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[0]), 50, 50); // 0
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[1]), 130, 50); // 1
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[2]), 50, 130); // 2
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[3]), 130, 130); // 3
};
let handleTouch = function(button, xy) {
console.log(button, xy);
const touchX = xy.x;
const touchY = xy.y;
const pressed = xy.type == 0;
// 0 1
// 2 3
let quad = -1;
if (touchY < 110) {
if (touchX < 110) {
quad = 0;
} else {
quad = 1;
}
} else {
if (touchX < 110) {
quad = 2;
} else {
quad = 3;
}
}
console.log("quad:", quad);
if (watchState == STATE_IDLE && pressed) {
watchState = STATE_MENU_OPEN;
subMenu = menu;
menuCommand = "";
}
const keys = Object.keys(subMenu);
const key = keys[quad];
subMenu = subMenu[key];
menuCommand += key + ",";
console.log("submenu:", subMenu);
if (subMenu) {
drawMenu(subMenu);
} else {
watchState = STATE_IDLE;
console.log("menuCommand:", menuCommand);
Bangle.drawWidgets();
Bangle.buzz(100, 0.2);
if (Bangle.http){
const options = {timeout:3000, method: "post", body: menuCommand};
Bangle.http("https://api.home.dns.t0.vc/menu", options).then(event => {
myMessage = "ok";
if (paintFace) paintFace();
}).catch((e)=>{
myMessage = "POST error";
if (paintFace) paintFace();
});
}
myMessage = "sent";
if (paintFace) paintFace();
}
};
let handleTwist = function() {
console.log("twisted");
if (watchState == STATE_MENU_OPEN) {
watchState = STATE_IDLE;
myMessage = "cancelled";
if (paintFace) paintFace();
Bangle.drawWidgets();
}
}
if (Bangle.http){
Bangle.http("https://api.home.dns.t0.vc/grid", {timeout:3000}).then(event => {
grid = JSON.parse(event.resp);
//console.log(grid);
}).catch((e)=>{
myMessage = "Grid error";
if (paintFace) paintFace();
});
Bangle.http("https://api.home.dns.t0.vc/menu", {timeout:3000}).then(event => {
menu = JSON.parse(event.resp);
//console.log(grid);
}).catch((e)=>{
myMessage = "Menu error";
if (paintFace) paintFace();
});
}
Bangle.on('swipe', handleSwipe);
Bangle.on('drag', handleDrag);
Bangle.on('touch', handleTouch);
Bangle.on('twist', handleTwist);
// Show launcher when middle button pressed
Bangle.setUI({
mode : "clock",
remove : function() {
// Called to unload all of the clock app
Bangle.removeListener('swipe', handleSwipe);
Bangle.removeListener('drag', handleDrag);
Bangle.removeListener('touch', handleTouch);
Bangle.removeListener('twist', handleTwist);
if (drawTimer) clearTimeout(drawTimer);
drawTimer = undefined;
if (gridTimer) clearTimeout(gridTimer);
gridTimer = undefined;
if (lockTimer) clearTimeout(lockTimer);
lockTimer = undefined;
delete Graphics.prototype.setFontAnton;
paintFace = undefined; // http request may resolve after font's been unloaded, so unset
}});
// Load widgets
Bangle.loadWidgets();
paintFace();
draw();
setTimeout(Bangle.drawWidgets,0);
}