1
0
Fork 0
BangleApps/apps/bluetoothdock/app.js

183 lines
5.5 KiB
JavaScript

var deviceInfo = {};
if (Bangle.getAccel().x < -0.7)
g.setRotation(3); // assume watch in charge cradle
// Tile sizes
var TILESIZE = 60;
// Tiles along width of screen
var TILEX = 4;
// Map devices to nice names...
var deviceNames = {
"eb:44:c1:71:2e:89 random" : "Office",
"c4:7c:8d:6a:ac:79 public" : "Peacelily"
};
var scanHandlers = [
{ filter : {serviceData:{"fe95":{}}}, // Xiaomi
handler : function(device) {
if (!device.serviceData["fe95"]) return;
var d = new DataView(device.serviceData["fe95"]);
var frame = d.getUint16(0,true);
var offset = 5;
if (frame&16) offset+=6; // mac address
if (frame&32) offset+=1; // capabilitities
if (frame&64) { // event
var l = d.getUint8(offset+2);
var code = d.getUint16(offset,true);
if (!deviceInfo[device.id]) deviceInfo[device.id]={id:device.id};
event = deviceInfo[device.id];
switch (code) {
case 0x1004: event.temperature = d.getInt16(offset+3,true)/10; break;
case 0x1006: event.humidity = d.getInt16(offset+3)/10; break;
case 0x100D:
event.temperature = d.getInt16(offset+3,true)/10;
event.humidity = d.getInt16(offset+5)/10; break;
case 0x1008: event.moisture = d.getUint8(offset+3); break;
case 0x1009: event.fertility = d.getUint16(offset+3,true)/10; break;
// case 0x1007: break; // 3 bytes? got 84,0,0 or 68,0,0
default: event.code = code;
event.raw = new Uint8Array(d.buffer, offset+3, l);
break;
}
}}}, {
filter : {serviceData:{"1809":{}}}, // Standard Bluetooth
handler : function(device) {
if (!device.serviceData["1809"]) return;
var d = new DataView(device.serviceData["1809"]);
if (!deviceInfo[device.id]) deviceInfo[device.id]={id:device.id,name:device.name};
event = deviceInfo[device.id];
event.temperature = d.getInt16(0,1)/100;
}}, {
filter : { manufacturerData:{0x0590:{}} }, // Espruino
handler : function(device) {
if (!device.manufacturerData) return;
var j;
try { j = JSON.parse(E.toString(device.manufacturerData)); }
catch (e) { return; } // not JSON
if (!deviceInfo[device.id]) deviceInfo[device.id]={id:device.id,name:device.name};
event = deviceInfo[device.id];
if (j.t) event.temperature = j.t;
if (j.a) event.alert = j.a;
}}
];
function getImgHum() {
return require("heatshrink").decompress(atob("jUoxH+AEtlsoYYDS4ZYDAYaVDLAYFDSQYHDSIZYDBIaPDLAYLDRoZYDBoaLDLAYPDRIZYDCIaHDLAYTDQoZYDCoaDDOQYXAA+JxIYX1utDSwYBAAIzYGiwZUTgpODQpzPGGgY3OdI4aRDIIaMDJIYCDIztDGRwaJP5oaWDAwaRDBAbOC5YcKB5I="));
}
function getImgTemp() {
return require("heatshrink").decompress(atob("iUqxH+AA2sAAQLHCBASMCAoSLCPOBAAQRfI/5Hn3YACy4ACCL4ADCL5H/I/AQHCRAQJCQwQLCQgQNCQYRQCB4A/ADaPjYqTpSCRYQGCZALFA"));
}
function drawAlert(tile,x,y) {
g.setFont("Vector",56).setFontAlign(0,0);
g.drawString("!",x+TILESIZE/2,y+10+TILESIZE/2);
}
function drawMoisture(tile,x,y) {
g.drawImage(getImgHum(),x+2,y+18);
g.setFont("Vector",28);
g.drawString(tile.device.moisture,x+26,y+12);
}
function drawTemperature(tile,x,y) {
g.drawImage(getImgTemp(),x+3,y+16);
g.setFont("Vector",30);
var t = Math.round(tile.device.temperature);
g.drawString(t,x+25,y+13);
}
function getTiles() {
var tiles = [];
Object.keys(deviceInfo).forEach(id=>{
var dev = deviceInfo[id];
if (dev.alert) {
tiles.push({
alert: true, device: dev,
draw: drawAlert
});
}
if (dev.moisture && dev.moisture<40) {
tiles.push({
alert: true, device: dev,
draw: drawMoisture
});
}
if (dev.temperature) {
tiles.push({
device: dev,
draw: drawTemperature
});
}
});
tiles.sort((a,b)=>(b.alert|0)-(a.alert|0))
return tiles;
}
g.clear();
require("Font7x11Numeric7Seg").add(Graphics);
function drawClock() {
var d = new Date();
var size = 3;
var x = (g.getWidth()/2) - size*6,
y = size;
g.reset();
g.setFont("7x11Numeric7Seg",size).setFontAlign(1,-1);
g.drawString(d.getHours(), x, y, true);
g.setFontAlign(-1,-1);
if (d.getSeconds()&1) g.drawString(":", x,y);
g.drawString(("0"+d.getMinutes()).substr(-2),x+size*4,y, true);
// draw seconds
g.setFont("7x11Numeric7Seg",size/2);
g.drawString(("0"+d.getSeconds()).substr(-2),x+size*18,y + size*7, true);
// date
var s = d.toString().split(" ").slice(0,4).join(" ");
g.reset().setFontAlign(0,-1);
g.drawString(s,g.getWidth()/2, y + size*12, true);
// keep screen on
g.flip();
}
function drawTiles() {
// draw tiles
var tiles = getTiles();
for (var i=0;i<6;i++) {
var x = (i%TILEX)*TILESIZE;
var y = TILESIZE + TILESIZE*((i/TILEX)|0);
g.reset();
var tile = tiles[i];
if (tile && tile.alert) {
g.setBgColor(0.5,0,0);
}
g.clearRect(x,y,x+TILESIZE-1,y+TILESIZE-1);
if (tile) {
g.reset().setFont("6x8");
var t = deviceNames[tile.device.id];
if (!t) t = tile.device.name || tile.device.id.substr(0,17);
g.drawString(t,x+2,y+2);
tile.draw(tile, x, y);
if (tile.alert) {
g.setColor(1,1,0);
g.drawRect(x,y,x+TILESIZE-1,y+TILESIZE-1);
}
}
}
g.flip(); // keep forcing display on
}
setInterval(drawClock, 1000);
setInterval(drawTiles, 10000);
drawClock();
drawTiles();
function parseDevice(dev) {
if (!dev.serviceData) dev.serviceData={};
scanHandlers.forEach(s=>s.handler(dev));
}
NRF.setScan(parseDevice, { filters: scanHandlers.map(s=>s.filter), timeout: 2000 });
if (Bangle.isCharging()) {
Bangle.on("charging", isCharging => {
if (!isCharging) load();
});
}