1
0
Fork 0

added kitchen combo app

master
hughbarney 2021-03-25 13:26:58 +00:00
parent 44add51c80
commit 170cf6dff6
11 changed files with 1470 additions and 1 deletions

View File

@ -3013,5 +3013,23 @@
"evaluate": true
}
]
}
},
{ "id": "kitchen",
"name": "Kitchen Combo",
"icon": "kitchen.png",
"version":"0.01",
"description": "Combination of the stepo, walkersclock, arrow and waypointer apps into a multiclock format.",
"tags": "tool,outdoors,gps",
"readme": "README.md",
"interface":"waypoints.html",
"storage": [
{"name":"kitchen.app.js","url":"kitchen.app.js"},
{"name":"stepo.kit.js","url":"stepo.kit.js"},
{"name":"gps.kit.js","url":"gps.kit.js"},
{"name":"digi.kit.js","url":"digi.kit.js"},
{"name":"compass.kit.js","url":"compass.kit.js"},
{"name":"waypoints.json","url":"waypoints.json","evaluate":false},
{"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true}
]
}
]

306
apps/kitchen/compass.kit.js Normal file
View File

@ -0,0 +1,306 @@
(() => {
function getFace(){
var intervalRefSec;
var pal_by;
var pal_bw;
var pal_bb;
var buf1;
var buf2;
var bearing;
var heading;
var oldHeading;
var CALIBDATA;
var previous;
var wp;
var wp_distance;
var wp_bearing;
var loc;
var gpsObject;
function log_debug(o) {
//console.log(o);
}
function init(gps) {
showMem("compass init() START");
gpsObject = gps;
pal_by = new Uint16Array([0x0000,0xFFC0],0,1); // black, yellow
pal_bw = new Uint16Array([0x0000,0xffff],0,1); // black, white
pal_bb = new Uint16Array([0x0000,0x07ff],0,1); // black, blue
buf1 = Graphics.createArrayBuffer(128,128,1,{msb:true});
buf2 = Graphics.createArrayBuffer(80,40,1,{msb:true});
intervalRefSec = undefined;
bearing = 0; // always point north if GPS is off
heading = 0;
oldHeading = 0;
previous = {bs:"-", dst:"-", wp_name:"-", course:999};
loc = require("locale");
CALIBDATA = require("Storage").readJSON("magnav.json",1)||null;
getWaypoint();
/*
* compass should be powered on before startDraw is called
* otherwise compass power widget will not come on
*/
if (!Bangle.isCompassOn()) Bangle.setCompassPower(1);
gps.determineGPSState();
showMem("compass init() END");
}
function freeResources() {
showMem("compass freeResources() START");
gpsObject = undefined;
pal_by = undefined;
pal_bw = undefined;
pal_bb = undefined;
buf1 = undefined;
buf2 = undefined;
intervalRefSec = undefined;
previous = undefined;
bearing = 0;
heading = 0;
oldHeading = 0;
loc = undefined;
CALIBDATA = undefined;
wp = undefined;
if (Bangle.isCompassOn()) Bangle.setCompassPower(0);
showMem("compass freeResources() END");
}
function flip1(x,y) {
g.drawImage({width:128,height:128,bpp:1,buffer:buf1.buffer, palette:pal_by},x ,y);
buf1.clear();
}
function flip2_bw(x,y) {
g.drawImage({width:80,height:40,bpp:1,buffer:buf2.buffer, palette:pal_bw},x ,y);
buf2.clear();
}
function flip2_bb(x,y) {
g.drawImage({width:80,height:40,bpp:1,buffer:buf2.buffer, palette:pal_bb},x ,y);
buf2.clear();
}
function startTimer() {
log_debug("startTimer()");
if (!Bangle.isCompassOn()) Bangle.setCompassPower(1);
resetPrevious();
draw();
intervalRefSec = setInterval(draw, 500);
}
function stopTimer() {
log_debug("stopTimer()");
if(intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);}
if (Bangle.isCompassOn()) Bangle.setCompassPower(0);
}
function showMem(msg) {
var val = process.memory();
var str = msg + " " + Math.round(val.usage*100/val.total) + "%";
log_debug(str);
}
function onButtonShort(btn) {
switch(btn) {
case 1:
log_debug("prev waypoint");
gpsObject.nextWaypoint(-1);
break;
case 2:
log_debug("next waypoint");
gpsObject.nextWaypoint(1);
break;
case 3:
default:
break;
}
resetPrevious();
getWaypoint();
drawGPSData();
}
function onButtonLong(btn) {
log_debug("markWaypoint()");
if (btn !== 1) return;
if (gpsObject.getState() !== gpsObject.GPS_RUNNING) return;
log_debug("markWaypoint()");
gpsObject.markWaypoint();
resetPrevious();
getWaypoint();
drawGPSData();
}
function getWaypoint() {
log_debug("getWaypoint()");
wp = gpsObject.getCurrentWaypoint();
wp_distance = gpsObject.getWPdistance();
wp_bearing = gpsObject.getWPbearing();
log_debug(wp);
log_debug(wp_distance);
log_debug(wp_bearing);
}
// takes 32ms
function drawCompass(hd) {
if (Math.abs(hd - oldHeading) < 2) return 0;
hd=hd*Math.PI/180;
var p = [0, 1.1071, Math.PI/4, 2.8198, 3.4633, 7*Math.PI/4 , 5.1760];
var poly = [
64+60*Math.sin(hd+p[0]), 64-60*Math.cos(hd+p[0]),
64+44.7214*Math.sin(hd+p[1]), 64-44.7214*Math.cos(hd+p[1]),
64+28.2843*Math.sin(hd+p[2]), 64-28.2843*Math.cos(hd+p[2]),
64+63.2455*Math.sin(hd+p[3]), 64-63.2455*Math.cos(hd+p[3]),
64+63.2455*Math.sin(hd+p[4]), 64-63.2455*Math.cos(hd+p[4]),
64+28.2843*Math.sin(hd+p[5]), 64-28.2843*Math.cos(hd+p[5]),
64+44.7214*Math.sin(hd+p[6]), 64-44.7214*Math.cos(hd+p[6])
];
buf1.fillPoly(poly);
flip1(56, 56);
}
// stops violent compass swings and wobbles, takes 3ms
function newHeading(m,h){
//log_debug("newHeading()");
var s = Math.abs(m - h);
var delta = (m>h)?1:-1;
if (s>=180){s=360-s; delta = -delta;}
if (s<2) return h;
if (s<3) return h;
var hd = h + delta*(1 + Math.round(s/5));
if (hd<0) hd+=360;
if (hd>360)hd-= 360;
return hd;
}
// takes approx 7ms
function tiltfixread(O,S){
//log_debug("tiltfixread()");
var m = Bangle.getCompass();
var g = Bangle.getAccel();
m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z;
var d = Math.atan2(-m.dx,m.dy)*180/Math.PI;
if (d<0) d+=360;
var phi = Math.atan(-g.x/-g.z);
var cosphi = Math.cos(phi), sinphi = Math.sin(phi);
var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi));
var costheta = Math.cos(theta), sintheta = Math.sin(theta);
var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta;
var yh = m.dz*sinphi - m.dx*cosphi;
var psi = Math.atan2(yh,xh)*180/Math.PI;
if (psi<0) psi+=360;
return psi;
}
function draw() {
//log_debug("draw()");
var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale);
heading = newHeading(d,heading);
if (gpsObject.getState() === gpsObject.GPS_RUNNING) {
wp_dist = gpsObject.getWPdistance();
wp_bearing = gpsObject.getWPbearing();
bearing = wp_bearing;
} else {
bearing = 0;
wp_distance = 0;
wp_bearing = 0;
}
var dir = bearing - heading;
if (dir < 0) dir += 360;
if (dir > 360) dir -= 360;
var t = drawCompass(dir); // we want compass to show us where to go
oldHeading = dir;
if (gpsObject.getState() === gpsObject.GPS_RUNNING) {
drawGPSData();
} else {
drawCompassHeading();
}
}
function drawCompassHeading() {
//log_debug("drawCompassHeading()");
// draw the heading
buf2.setColor(1);
buf2.setFontAlign(-1,-1);
buf2.setFont("Vector",38);
var hding = Math.round(heading);
var hd = hding.toString();
hd = hding < 10 ? "00"+hd : hding < 100 ? "0"+hd : hd;
buf2.drawString(hd,0,0);
flip2_bw(90, 200);
}
function drawGPSData() {
log_debug("drawGPSData()");
buf2.setFont("Vector",24);
var bs = wp_bearing.toString();
bs = wp_bearing<10?"00"+bs : wp_bearing<100 ?"0"+bs : bs;
var dst = loc.distance(wp_distance);
log_debug(bs);
log_debug(dst);
// -1=left (default), 0=center, 1=right
// show distance on the left
if (previous.dst !== dst) {
previous.dst = dst
buf2.setColor(1);
buf2.setFontAlign(-1,-1);
buf2.setFont("Vector", 20);
if (gpsObject.waypointHasLocation()) {
buf2.drawString(dst,0,0);
flip2_bb(0, 200);
} else {
buf2.drawString(" ",0,0);
flip2_bw(0, 200);
}
}
// bearing, place in middle at bottom of compass
if (previous.bs !== bs) {
previous.bs = bs;
buf2.setColor(1);
buf2.setFontAlign(0, -1);
buf2.setFont("Vector",38);
buf2.drawString(bs,40,0);
flip2_bw(80, 200);
}
// waypoint name on right
if (previous.wp_name !== wp.name) {
buf2.setColor(1);
buf2.setFontAlign(1,-1); // right, bottom
buf2.setFont("Vector", 20);
buf2.drawString(wp.name, 80, 0);
if (gpsObject.waypointHasLocation())
flip2_bb(160, 200);
else
flip2_bw(160, 200);
}
}
// clear the attributes that control the display refresh
function resetPrevious() {
log_debug("resetPrevious()");
previous = {bs:"-", dst:"-", wp_name:"-", course:999};
}
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
}
return getFace;
})();

146
apps/kitchen/digi.kit.js Normal file
View File

@ -0,0 +1,146 @@
(() => {
function getFace(){
var intervalRefSec;
var buf;
var days;
var prevInfo;
var prevDate;
var prevTime;
var infoMode;
const INFO_NONE = 0;
const INFO_BATT = 1;
const INFO_MEM = 2;
const Y_TIME = 30;
const Y_ACTIVITY = 116;
const Y_MODELINE = 200;
function init(gps) {
showMem("digi init 1");
days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday","Friday", "Saturday"];
prevInfo = "";
prevTimeStr = "";
prevDateStr = "";
infoMode = INFO_NONE;
g.clear();
showMem("digi init 2");
}
function freeResources() {
showMem("digi free 1");
days = undefined;
prevInfo = undefined;
prevTime = undefined;
prevDate = undefined;
showMem("digi free 2");
}
function showMem(msg) {
var val = process.memory();
var str = msg + " " + Math.round(val.usage*100/val.total) + "%";
//console.log(str);
}
function startTimer() {
draw();
intervalRefSec = setInterval(draw, 5000);
}
function stopTimer() {
if(intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);}
}
function onButtonShort(btn) {
if (btn === 1) cycleInfoMode();
}
function onButtonLong(btn) {}
function getGPSfix() { return undefined; }
function setGPSfix(f) {}
function draw() {
var d = new Date();
var da = d.toString().split(" ");
var time = da[4].substr(0,5);
if (time !== prevTime) {
prevTime = time;
g.setColor(0);
g.fillRect(0, Y_TIME, 239, Y_ACTIVITY -1);
g.setColor(1,1,1);
g.setFont("Vector",80);
g.setFontAlign(0,-1);
g.drawString(time, 120, Y_TIME);
}
var day = days[d.getDay()];
var dateStr = da[2] + " " + da[1] + " " + da[3];
if (dateStr !== prevDate) {
prevDate = dateStr;
g.setColor(0);
g.fillRect(0, Y_ACTIVITY, 239, Y_MODELINE - 3);
g.setColor(1,1,1);
g.setFont("Vector",26);
g.drawString(day, 120, Y_ACTIVITY);
g.drawString(dateStr, 120, Y_ACTIVITY + 40);
}
drawInfo();
}
function cycleInfoMode() {
switch(infoMode) {
case INFO_NONE:
infoMode = INFO_BATT;
break;
case INFO_BATT:
infoMode = INFO_MEM
break;
case INFO_MEM:
default:
infoMode = INFO_NONE;
break;
}
drawInfo();
}
function drawInfo() {
let val;
let str = "";
let col = 0x07FF; // cyan
switch(infoMode) {
case INFO_NONE:
col = 0x0000;
str = "";
break;
case INFO_MEM:
val = process.memory();
str = "Memory: " + Math.round(val.usage*100/val.total) + "%";
break;
case INFO_BATT:
default:
str = "Battery: " + E.getBattery() + "%";
}
// check if we need to draw, avoid flicker
if (str == prevInfo)
return;
prevInfo = str;
//g.setFont("6x8", 3);
g.setFont("Vector",26);
g.setColor(col);
g.fillRect(0, Y_MODELINE - 3, 239, Y_MODELINE + 25);
g.setColor(0,0,0);
g.setFontAlign(0, -1);
g.drawString(str, 120, Y_MODELINE);
}
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
}
return getFace;
})();

182
apps/kitchen/gps.kit.js Normal file
View File

@ -0,0 +1,182 @@
(() => {
function getFace(){
var intervalRefSec;
const GDISP_OS = 4;
const GDISP_LATLN = 5;
const GDISP_SPEED = 6;
const GDISP_ALT = 7;
const GDISP_COURSE = 8;
const Y_TIME = 30;
const Y_ACTIVITY = 120;
const Y_MODELINE = 200;
let gpsDisplay = GDISP_OS;
let clearActivityArea = true;
let gpsObject = undefined;
function log_debug(o) {
//console.log(o);
}
function init(gps) {
log_debug("gps init");
//log_debug(gps);
gpsObject = gps;
gpsDisplay = GDISP_OS;
clearActivityArea = true;
gpsObject.determineGPSState();
}
function freeResources() {}
function startTimer() {
draw();
intervalRefSec = setInterval(draw, 5000);
}
function stopTimer() {
if(intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);}
}
function onButtonShort(btn) {
if (btn === 1) cycleGPSDisplay();
}
function onButtonLong(btn) {
if (btn === 1) toggleGPSPower();
}
function draw(){
drawGPSTime();
drawGPSData();
}
function drawGPSTime() {
var time = gpsObject.getGPSTime();
g.reset();
g.clearRect(0,Y_TIME, 239, Y_ACTIVITY - 1);
g.setColor(1,1,1);
g.setFontAlign(0, -1);
if (time.length > 5)
g.setFont("Vector", 56);
else
g.setFont("Vector", 80);
g.drawString(time, 120, Y_TIME);
}
function drawGPSData() {
if (clearActivityArea) {
g.clearRect(0, Y_ACTIVITY, 239, Y_MODELINE - 1);
clearActivityArea = false;
}
g.setFontVector(26);
g.setColor(0xFFC0);
g.setFontAlign(0, -1);
if (gpsObject.getState() === gpsObject.GPS_OFF) {
g.drawString("GPS off", 120, Y_ACTIVITY);
return;
}
if (gpsObject.getState() === gpsObject.GPS_TIME) {
g.drawString("Waiting for", 120, Y_ACTIVITY);
g.drawString("GPS", 120, Y_ACTIVITY + 36);
return;
}
let fx = gpsObject.getLastFix();
log_debug("gpsObject.getState()= " + gpsObject.getState());
if (gpsObject.getState() === gpsObject.GPS_SATS) {
g.drawString("Satellites", 120, Y_ACTIVITY);
g.drawString(fx.satellites, 120, Y_ACTIVITY + 36);
return;
}
if (gpsObject.getState() === gpsObject.GPS_RUNNING) {
let time = gpsObject.formatTime(fx.time);
let age = gpsObject.timeSince(time);
let os = gpsObject.getOsRef();
//let ref = to_map_ref(6, os.easting, os.northing);
let speed;
let activityStr = "";
if (age < 0) age = 0;
g.setFontVector(40);
g.setColor(0xFFC0);
switch(gpsDisplay) {
case GDISP_OS:
activityStr = os;
break;
case GDISP_LATLN:
g.setFontVector(26);
activityStr = fx.lat.toFixed(4) + ", " + fx.lon.toFixed(4);
break;
case GDISP_SPEED:
speed = fx.speed;
speed = speed.toFixed(1);
activityStr = speed + "kph";
break;
case GDISP_ALT:
activityStr = fx.alt + "m";
break;
case GDISP_COURSE:
activityStr = fx.course;
break;
}
g.clearRect(0, Y_ACTIVITY, 239, Y_MODELINE - 1);
g.drawString(activityStr, 120, Y_ACTIVITY);
g.setFont("6x8",2);
g.setColor(1,1,1);
g.drawString(age, 120, Y_ACTIVITY + 46);
}
}
function toggleGPSPower() {
gpsObject.toggleGPSPower();
clearActivityArea = true;
draw();
}
function cycleGPSDisplay() {
if (gpsObject.getState() !== gpsObject.GPS_RUNNING) return;
switch (gpsDisplay) {
case GDISP_OS:
gpsDisplay = GDISP_SPEED;
break;
case GDISP_SPEED:
gpsDisplay = GDISP_ALT;
break;
case GDISP_ALT:
gpsDisplay = GDISP_LATLN;
break;
case GDISP_LATLN:
gpsDisplay = GDISP_COURSE;
break;
case GDISP_COURSE:
default:
gpsDisplay = GDISP_OS;
break;
}
clearActivityArea = true;
drawGPSData();
}
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
}
return getFace;
})();

482
apps/kitchen/kitchen.app.js Normal file
View File

@ -0,0 +1,482 @@
// read in the faces
var FACES = [];
var STOR = require("Storage");
STOR.list(/\.kit\.js$/).forEach(face=>FACES.push(eval(require("Storage").read(face))));
var iface = STOR.list(/\.kit\.js$/).indexOf("stepo.kit.js");
var face = FACES[iface]();
var firstPress
var pressTimer;
function stopdraw() {
face.stopTimer();
}
function startdraw() {
Bangle.drawWidgets();
face.startTimer();
}
function nextFace(){
stopdraw();
face.freeResources();
iface += 1
iface = iface % FACES.length;
face = FACES[iface]();
g.clear();
g.reset();
face.init(gpsObj);
startdraw();
}
// when you feel the buzzer you know you have done a long press
function longPressCheck() {
Bangle.buzz();
if (pressTimer) {
clearInterval(pressTimer);
pressTimer = undefined;
}
}
// start a timer and buzz when held long enough
function buttonPressed(btn) {
if (btn === 3) {
nextFace();
} else {
firstPress = getTime();
pressTimer = setInterval(longPressCheck, 1500);
}
}
// if you release too soon there is no buzz as timer is cleared
function buttonReleased(btn) {
var dur = getTime() - firstPress;
if (pressTimer) {
clearInterval(pressTimer);
pressTimer = undefined;
}
if ( dur >= 1.5 ) {
switch(btn) {
case 1:
face.onButtonLong(btn);
break;
case 2:
Bangle.showLauncher();
break;
case 3:
// do nothing
break;
}
return;
}
if (btn !== 3) face.onButtonShort(btn);
}
function setButtons(){
setWatch(buttonPressed.bind(null,1), BTN1, {repeat:true,edge:"rising"});
setWatch(buttonPressed.bind(null,2), BTN2, {repeat:true,edge:"rising"});
setWatch(nextFace, BTN3, {repeat:true,edge:"rising"});
setWatch(buttonReleased.bind(null,1), BTN1, {repeat:true,edge:"falling"});
setWatch(buttonReleased.bind(null,2), BTN2, {repeat:true,edge:"falling"});
// BTN 3 long press should always reset the bangle
}
Bangle.on('kill',()=>{
Bangle.setCompassPower(0);
Bangle.setGPSPower(0);
});
Bangle.on('lcdPower',function(on) {
if (on) {
startdraw();
} else {
stopdraw();
}
});
/*****************************************************************************
Start of GPS object code so we can share it between faces
******************************************************************************/
function log_debug(o) {
//console.log(o);
}
function radians(a) {
return a*Math.PI/180;
}
function degrees(a) {
var d = a*180/Math.PI;
return (d+360)%360;
}
function GPS() {
this.wp;
this.wp_index = 0;
this.wp_current = undefined;
this.GPS_OFF = 0;
this.GPS_TIME = 1;
this.GPS_SATS = 2;
this.GPS_RUNNING = 3;
this.gpsState = this.GPS_OFF;
this.gpsPowerState = false;
this.last_fix = {
fix: 0,
alt: 0,
lat: 0,
lon: 0,
speed: 0,
time: 0,
satellites: 0
};
this.listenerCount = 0;
this.loadFirstWaypoint();
}
GPS.prototype.log_debug = function(o) {
//console.log(o);
};
GPS.prototype.getState = function() {
return this.gpsState;
}
GPS.prototype.getLastFix = function() {
return this.last_fix;
}
GPS.prototype.determineGPSState = function() {
this.log_debug("determineGPSState");
gpsPowerState = Bangle.isGPSOn();
//this.log_debug("last_fix.fix " + this.last_fix.fix);
//this.log_debug("gpsPowerState " + this.gpsPowerState);
//this.log_debug("last_fix.satellites " + this.last_fix.satellites);
if (!gpsPowerState) {
this.gpsState = this.GPS_OFF;
this.resetLastFix();
} else if (this.last_fix.fix && this.gpsPowerState && this.last_fix.satellites > 0) {
this.gpsState = this.GPS_RUNNING;
} else {
this.gpsState = this.GPS_SATS;
}
this.log_debug("gpsState=" + this.gpsState);
if (this.gpsState !== this.GPS_OFF) {
if (this.listenerCount === 0) {
Bangle.on('GPS', processFix);
this.listenerCount++;
this.log_debug("listener added " + this.listenerCount);
}
} else {
if (this.listenerCount > 0) {
Bangle.removeListener("GPS", this.processFix);
this.listenerCount--;
this.log_debug("listener removed " + this.listenerCount);
}
}
};
GPS.prototype.getGPSTime = function() {
var time;
if (this.last_fix !== undefined && this.last_fix.time !== undefined && this.last_fix.time.toUTCString !== undefined &&
(this.gpsState == this.GPS_SATS || this.gpsState == this.GPS_RUNNING)) {
time = this.last_fix.time.toUTCString().split(" ");
return time[4];
} else {
var d = new Date();
var da = d.toString().split(" ");
time = da[4].substr(0,5);
return time;
}
};
GPS.prototype.toggleGPSPower = function() {
this.log_debug("toggleGPSPower()");
this.gpsPowerState = Bangle.isGPSOn();
this.gpsPowerState = !this.gpsPowerState;
Bangle.setGPSPower(this.gpsPowerState ? 1 : 0);
this.resetLastFix();
this.determineGPSState();
// poke the gps widget indicator to change
if (WIDGETS.gps !== undefined) {
WIDGETS.gps.draw();
}
};
GPS.prototype.resetLastFix = function() {
this.last_fix = {
fix: 0,
alt: 0,
lat: 0,
lon: 0,
speed: 0,
time: 0,
satellites: 0
};
};
function processFix(fix) {
//log_debug("processFix()");
gpsObj.processFix(fix);
}
GPS.prototype.processFix = function(fix) {
//this.log_debug("GPS:processFix()");
//this.log_debug(fix);
this.last_fix.time = fix.time;
if (this.gpsState == this.GPS_TIME) {
this.gpsState = this.GPS_SATS;
}
if (fix.fix) {
//this.log_debug("Got fix - setting state to GPS_RUNNING");
this.gpsState = this.GPS_RUNNING;
if (!this.last_fix.fix) Bangle.buzz(); // buzz on first position
this.last_fix = fix;
}
};
GPS.prototype.formatTime = function(now) {
var fd = now.toUTCString().split(" ");
return fd[4];
};
GPS.prototype.timeSince = function(t) {
var hms = t.split(":");
var now = new Date();
var sn = 3600*(now.getHours()) + 60*(now.getMinutes()) + 1*(now.getSeconds());
var st = 3600*(hms[0]) + 60*(hms[1]) + 1*(hms[2]);
return (sn - st);
};
GPS.prototype.getOsRef = function() {
let os = OsGridRef.latLongToOsGrid(this.last_fix);
let ref = to_map_ref(6, os.easting, os.northing);
return ref;
};
GPS.prototype.calcBearing = function(a,b) {
var delta = radians(b.lon-a.lon);
var alat = radians(a.lat);
var blat = radians(b.lat);
var y = Math.sin(delta) * Math.cos(blat);
var x = Math.cos(alat)*Math.sin(blat) -
Math.sin(alat)*Math.cos(blat)*Math.cos(delta);
return Math.round(degrees(Math.atan2(y, x)));
}
GPS.prototype.calcDistance = function(a,b) {
var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
var y = radians(b.lat-a.lat);
return Math.round(Math.sqrt(x*x + y*y) * 6371000);
}
GPS.prototype.getWPdistance = function() {
//log_debug(this.last_fix);
//log_debug(this.wp_current);
if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0)
return 0;
else
return this.calcDistance(this.last_fix, this.wp_current);
}
GPS.prototype.getWPbearing = function() {
//log_debug(this.last_fix);
//log_debug(this.wp_current);
if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0)
return 0;
else
return this.calcBearing(this.last_fix, this.wp_current);
}
GPS.prototype.loadFirstWaypoint = function() {
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}];
this.wp_index = 0;
this.wp_current = waypoints[this.wp_index];
log_debug(this.wp_current);
return this.wp_current;
}
GPS.prototype.getCurrentWaypoint = function() {
return this.wp_current;
}
GPS.prototype.waypointHasLocation = function() {
if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0)
return false;
else
return true;
}
GPS.prototype.markWaypoint = function() {
if(this.wp_current.name === "NONE")
return;
log_debug("GPS::markWaypoint()");
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}];
this.wp_current = waypoints[this.wp_index];
if (this.waypointHasLocation()) {
waypoints[this.wp_index] = {name:this.wp_current.name, lat:0, lon:0};
} else {
waypoints[this.wp_index] = {name:this.wp_current.name, lat:this.last_fix.lat, lon:this.last_fix.lon};
}
this.wp_current = waypoints[this.wp_index];
require("Storage").writeJSON("waypoints.json", waypoints);
log_debug("GPS::markWaypoint() written");
}
GPS.prototype.nextWaypoint = function(inc) {
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}];
this.wp_index+=inc;
if (this.wp_index>=waypoints.length) this.wp_index=0;
if (this.wp_index<0) this.wp_index = waypoints.length-1;
this.wp_current = waypoints[this.wp_index];
log_debug(this.wp_current);
return this.wp_current;
}
var gpsObj = new GPS();
/*****************************************************************************
Start of OS lat lon to grid ref code
******************************************************************************/
Number.prototype.toRad = function() { return this*Math.PI/180; };
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Ordnance Survey Grid Reference functions (c) Chris Veness 2005-2014 */
/* - www.movable-type.co.uk/scripts/gridref.js */
/* - www.movable-type.co.uk/scripts/latlon-gridref.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
function OsGridRef(easting, northing) {
this.easting = 0|easting;
this.northing = 0|northing;
}
OsGridRef.latLongToOsGrid = function(point) {
var lat = point.lat.toRad();
var lon = point.lon.toRad();
var a = 6377563.396, b = 6356256.909; // Airy 1830 major & minor semi-axes
var F0 = 0.9996012717; // NatGrid scale factor on central meridian
var lat0 = (49).toRad(), lon0 = (-2).toRad(); // NatGrid true origin is 49�N,2�W
var N0 = -100000, E0 = 400000; // northing & easting of true origin, metres
var e2 = 1 - (b*b)/(a*a); // eccentricity squared
var n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n;
var cosLat = Math.cos(lat), sinLat = Math.sin(lat);
var nu = a*F0/Math.sqrt(1-e2*sinLat*sinLat); // transverse radius of curvature
var rho = a*F0*(1-e2)/Math.pow(1-e2*sinLat*sinLat, 1.5); // meridional radius of curvature
var eta2 = nu/rho-1;
var Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
var Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0);
var Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0));
var Md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0));
var M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc
var cos3lat = cosLat*cosLat*cosLat;
var cos5lat = cos3lat*cosLat*cosLat;
var tan2lat = Math.tan(lat)*Math.tan(lat);
var tan4lat = tan2lat*tan2lat;
var I = M + N0;
var II = (nu/2)*sinLat*cosLat;
var III = (nu/24)*sinLat*cos3lat*(5-tan2lat+9*eta2);
var IIIA = (nu/720)*sinLat*cos5lat*(61-58*tan2lat+tan4lat);
var IV = nu*cosLat;
var V = (nu/6)*cos3lat*(nu/rho-tan2lat);
var VI = (nu/120) * cos5lat * (5 - 18*tan2lat + tan4lat + 14*eta2 - 58*tan2lat*eta2);
var dLon = lon-lon0;
var dLon2 = dLon*dLon, dLon3 = dLon2*dLon, dLon4 = dLon3*dLon, dLon5 = dLon4*dLon, dLon6 = dLon5*dLon;
var N = I + II*dLon2 + III*dLon4 + IIIA*dLon6;
var E = E0 + IV*dLon + V*dLon3 + VI*dLon5;
return new OsGridRef(E, N);
};
/*
* converts northing, easting to standard OS grid reference.
*
* [digits=10] - precision (10 digits = metres)
* to_map_ref(8, 651409, 313177); => 'TG 5140 1317'
* to_map_ref(0, 651409, 313177); => '651409,313177'
*
*/
function to_map_ref(digits, easting, northing) {
if (![ 0,2,4,6,8,10,12,14,16 ].includes(Number(digits))) throw new RangeError(`invalid precision '${digits}'`); // eslint-disable-line comma-spacing
let e = easting;
let n = northing;
// use digits = 0 to return numeric format (in metres) - note northing may be >= 1e7
if (digits == 0) {
const format = { useGrouping: false, minimumIntegerDigits: 6, maximumFractionDigits: 3 };
const ePad = e.toLocaleString('en', format);
const nPad = n.toLocaleString('en', format);
return `${ePad},${nPad}`;
}
// get the 100km-grid indices
const e100km = Math.floor(e / 100000), n100km = Math.floor(n / 100000);
// translate those into numeric equivalents of the grid letters
let l1 = (19 - n100km) - (19 - n100km) % 5 + Math.floor((e100km + 10) / 5);
let l2 = (19 - n100km) * 5 % 25 + e100km % 5;
// compensate for skipped 'I' and build grid letter-pairs
if (l1 > 7) l1++;
if (l2 > 7) l2++;
const letterPair = String.fromCharCode(l1 + 'A'.charCodeAt(0), l2 + 'A'.charCodeAt(0));
// strip 100km-grid indices from easting & northing, and reduce precision
e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));
n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));
// pad eastings & northings with leading zeros
e = e.toString().padStart(digits/2, '0');
n = n.toString().padStart(digits/2, '0');
return `${letterPair} ${e} ${n}`;
}
/*****************************************************************************
End of GPS object
******************************************************************************/
g.clear();
Bangle.loadWidgets();
face.init(gpsObj);
startdraw();
setButtons();

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH4A/AH4AVgAACF1crnNkF9QuBLoMHF9cyGIYuprovBX1cAsgABrovYJSBeBF4SPBFy8HmQbOLwdkFzAtBmYcNCIIuCYAIvXLgJ/BF5pecAAy9OdqgmCg8rmUznMyAAJkCEI5eEdqQgBU4YAJrsHEYheErwuSFpoxEEoa9WIwgwTgFeAwQvQLqQwFaYa7TLyYuBmQYBdKQuCIoUrlcyABcrKwJcWXgZJBEIQiBAAQlEEwI+BmU5CgINDF6ZgFGQI3BAAkzLw8OLygvBg8VhwaBLY5eEg8OisVjgABhwvVhwaCACgv/F78VF/4v/F8sHd9owBF68HFyhgYRyowDYQMVFqMHFy4xEAAMHg41BAAIrFiq6BAAIuZGhIAIFj4A/AH4A/AH4AWA=="))

View File

@ -0,0 +1,8 @@
require("Storage").write("kitchen.info",{
"id":"kitchen",
"name":"Kitchen",
"src":"kitchen.app.js",
"icon":"kitchen.img",
"type":"clock",
"files":"kitchen.info, kitchen.app.js, kitchen.img, stepo.kit.js, digi.kit.js, compass.kit.js, gps.kit.js"
});

BIN
apps/kitchen/kitchen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

136
apps/kitchen/stepo.kit.js Normal file
View File

@ -0,0 +1,136 @@
(() => {
function getFace(){
var pal4color;
var pal4red;
var buf;
var intervalRefSec;
function init(g) {
showMem("stepo init 1");
pal4color = new Uint16Array([0x0000,0xFFFF,0x7BEF,0xAFE5],0,2); // b,w,grey,greenyellow
pal4red = new Uint16Array([0x0000,0xFFFF,0xF800,0xAFE5],0,2); // b,w,red,greenyellow
buf = Graphics.createArrayBuffer(120,120,2,{msb:true});
showMem("stepo init 2");
}
function freeResources() {
showMem("stepo free 1");
pal4color = undefined;
pal4red = undefined;
buf = undefined;
showMem("stepo free 2");
}
function showMem(msg) {
var val = process.memory();
var str = msg + " " + Math.round(val.usage*100/val.total) + "%";
//console.log(str);
}
function flip(x,y) {
g.drawImage({width:120,height:120,bpp:2,buffer:buf.buffer, palette:pal4color}, x, y);
buf.clear();
}
function flip_red(x,y) {
g.drawImage({width:120,height:120,bpp:2,buffer:buf.buffer, palette:pal4red}, x, y);
buf.clear();
}
function onButtonShort(btn) {}
function onButtonLong(btn) {}
function radians(a) {
return a*Math.PI/180;
}
function startTimer() {
draw();
intervalRefSec = setInterval(draw, 5000);
}
function stopTimer() {
if(intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);}
}
function drawSteps() {
var i = 0;
var cx = 60;
var cy = 60;
var r = 56;
var steps = getSteps();
var percent = steps / 10000;
if (percent > 1) percent = 1;
var startrot = 0 - 180;
var midrot = -180 - (360 * percent);
var endrot = -360 - 180;
buf.setColor(3); // green-yellow
// draw guauge
for (i = startrot; i > midrot; i -= 4) {
x = cx + r * Math.sin(radians(i));
y = cy + r * Math.cos(radians(i));
buf.fillCircle(x,y,4);
}
buf.setColor(2); // grey
// draw remainder of guage in grey
for (i = midrot; i > endrot; i -= 4) {
x = cx + r * Math.sin(radians(i));
y = cy + r * Math.cos(radians(i));
buf.fillCircle(x,y,4);
}
// draw steps
buf.setColor(1); // white
buf.setFont("Vector", 24);
buf.setFontAlign(0,0);
buf.drawString(steps, cx, cy);
// change the remaining color to RED if battery is below 25%
if (E.getBattery() > 25)
flip(60,115);
else
flip_red(60,115);
}
function draw() {
var d = new Date();
var da = d.toString().split(" ");
var time = da[4].substr(0,5);
g.clearRect(0, 30, 239, 99);
g.setColor(1,1,1);
g.setFontAlign(0, -1);
g.setFont("Vector", 80);
g.drawString(time, 120, 30, true);
drawSteps();
}
function getSteps() {
if (stepsWidget() !== undefined)
return stepsWidget().getSteps();
return "-";
}
function stepsWidget() {
if (WIDGETS.activepedom !== undefined) {
return WIDGETS.activepedom;
} else if (WIDGETS.wpedom !== undefined) {
return WIDGETS.wpedom;
}
return undefined;
}
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
}
return getFace;
})();

170
apps/kitchen/waypoints.html Normal file
View File

@ -0,0 +1,170 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
<link rel="stylesheet" href="../../css/spectre-icons.min.css">
</head>
<body>
<h4>List of waypoints</h4>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Lat.</th>
<th>Long.</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="waypoints">
</tbody>
</table>
<br>
<h4>Add a new waypoint</h4>
<form id="add_waypoint_form">
<div class="columns">
<div class="column col-3 col-xs-8">
<input class="form-input input-sm" type="text" id="add_waypoint_name" placeholder="Name">
</div>
<div class="column col-3 col-xs-8">
<input class="form-input input-sm" value="0.0000" type="number" step="any" id="add_latitude" placeholder="Lat">
</div>
<div class="column col-3 col-xs-8">
<input class="form-input input-sm" value="0.0000" type="number" step="any" id="add_longtitude" placeholder="Long">
</div>
</div>
<div class="columns">
<div class="column col-3 col-xs-8">
<button id="add_name_button" class="btn btn-primary btn-sm">Add Name Only</button>
</div>
<div class="column col-3 col-xs-8">
<button id="add_waypoint_button" class="btn btn-primary btn-sm">Add Waypoint</button>
</div>
</div>
</form>
<br>
<button id="Download" class="btn btn-error">Reload</button> <button id="Upload" class="btn btn-primary">Upload</button>
<script src="../../core/lib/interface.js"></script>
<script>
var waypoints = []
var $name = document.getElementById('add_waypoint_name')
var $form = document.getElementById('add_waypoint_form')
var $button = document.getElementById('add_waypoint_button')
var $name_button = document.getElementById('add_name_button')
var $latitude = document.getElementById('add_latitude')
var $longtitude = document.getElementById('add_longtitude')
var $list = document.getElementById('waypoints')
function compare(a, b){
var x = a.name.toLowerCase();
var y = b.name.toLowerCase();
if (x=="none") {return -1};
if (y=="none") {return 1};
if (x < y) {return -1;}
if (x > y) {return 1;}
return 0;
}
$button.addEventListener('click', event => {
event.preventDefault()
var name = $name.value.trim()
if(!name) return;
var lat = parseFloat($latitude.value).toPrecision(5);
var lon = parseFloat($longtitude.value).toPrecision(5);
waypoints.push({
name, lat,lon,
});
waypoints.sort(compare);
renderWaypoints()
$name.value = ''
$latitude.value = (0).toPrecision(5);
$longtitude.value = (0).toPrecision(5);
});
$name_button.addEventListener('click', event => {
event.preventDefault()
var name = $name.value.trim()
if(!name) return;
waypoints.push({
name
});
waypoints.sort(compare);
renderWaypoints()
$name.value = ''
$latitude.value = 0.0000
$longtitude.value = 0.0000
});
function removeWaypoint(index){
$name.value = waypoints[index].name
$latitude.value = waypoints[index].lat
$longtitude.value = waypoints[index].lon
waypoints = waypoints.filter((p,i) => i!==index)
renderWaypoints()
}
function renderWaypoints(){
$list.innerHTML = ''
waypoints.forEach((waypoint,index) => {
var $waypoint = document.createElement('tr')
if (index==0){
$waypoint.innerHTML = `<td>${waypoint.name}</td>`
} else if(waypoint.lat==undefined){
$waypoint.innerHTML = `<td>${waypoint.name}</td><td>------</td><td>-----</td><td><button class="btn btn-action btn-primary" onclick="removeWaypoint(${index})"><i class="icon icon-edit"></i></button></td>`
} else {
$waypoint.innerHTML = `<td>${waypoint.name}</td><td>${waypoint.lat}</td><td>${waypoint.lon}</td><td><button class="btn btn-action btn-primary" onclick="removeWaypoint(${index})"><i class="icon icon-edit"></i></button></td>`
}
$list.appendChild($waypoint)
})
$name.focus()
}
function downloadJSONfile(fileid, callback) {
Puck.write(`\x10(function() {
var pts = require("Storage").readJSON("${fileid}")||[{name:"NONE"}];
Bluetooth.print(JSON.stringify(pts));
})()\n`,contents=>{
var storedpts = JSON.parse(contents);
callback(storedpts);
});
}
function uploadFile(fileid, contents) {
Puck.write(`\x10(function() {
require("Storage").write("${fileid}",'${contents}');
Bluetooth.print("OK");
})()\n`,ret=>{
console.log("uploadFile",ret);
});
}
function gotStored(pts){
waypoints = pts;
renderWaypoints();
}
function onInit() {
downloadJSONfile("waypoints.json", gotStored);
}
document.getElementById("Download").addEventListener("click", function() {
downloadJSONfile("waypoints.json", gotStored);
});
document.getElementById("Upload").addEventListener("click", function() {
var data = JSON.stringify(waypoints);
uploadFile("waypoints.json",data);
});
</script>
</body>
</html>

View File

@ -0,0 +1,20 @@
[
{
"name":"NONE"
},
{
"name":"No10",
"lat":51.5032,
"lon":-0.1269
},
{
"name":"Stone",
"lat":51.1788,
"lon":-1.8260
},
{ "name":"WP0" },
{ "name":"WP1" },
{ "name":"WP2" },
{ "name":"WP3" },
{ "name":"WP4" }
]