Merge branch 'master' of https://github.com/espruino/BangleApps into compass

# Conflicts:
#	apps/compass/compass.js
master
Ben Whittaker 2020-05-27 21:01:26 -04:00
commit 3cdd0f7820
113 changed files with 4451 additions and 3705 deletions

View File

@ -137,7 +137,7 @@
"name": "Default Alarm", "name": "Default Alarm",
"shortName":"Alarms", "shortName":"Alarms",
"icon": "app.png", "icon": "app.png",
"version":"0.07", "version":"0.08",
"description": "Set and respond to alarms", "description": "Set and respond to alarms",
"tags": "tool,alarm,widget", "tags": "tool,alarm,widget",
"storage": [ "storage": [
@ -280,7 +280,7 @@
{ "id": "gpstime", { "id": "gpstime",
"name": "GPS Time", "name": "GPS Time",
"icon": "gpstime.png", "icon": "gpstime.png",
"version":"0.03", "version":"0.04",
"description": "Update the Bangle.js's clock based on the time from the GPS receiver", "description": "Update the Bangle.js's clock based on the time from the GPS receiver",
"tags": "tool,gps", "tags": "tool,gps",
"storage": [ "storage": [
@ -303,7 +303,7 @@
{ "id": "speedo", { "id": "speedo",
"name": "Speedo", "name": "Speedo",
"icon": "speedo.png", "icon": "speedo.png",
"version":"0.03", "version":"0.04",
"description": "Show the current speed according to the GPS", "description": "Show the current speed according to the GPS",
"tags": "tool,outdoors,gps", "tags": "tool,outdoors,gps",
"storage": [ "storage": [
@ -888,7 +888,7 @@
{ "id": "berlinc", { "id": "berlinc",
"name": "Berlin Clock", "name": "Berlin Clock",
"icon": "berlin-clock.png", "icon": "berlin-clock.png",
"version":"0.02", "version":"0.03",
"description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)", "description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)",
"tags": "clock", "tags": "clock",
"type":"clock", "type":"clock",
@ -1727,7 +1727,7 @@
{ "id": "rndmclk", { "id": "rndmclk",
"name": "Random Clock Loader", "name": "Random Clock Loader",
"icon": "rndmclk.png", "icon": "rndmclk.png",
"version":"0.02", "version":"0.03",
"description": "Load a different clock whenever the LCD is switched on.", "description": "Load a different clock whenever the LCD is switched on.",
"readme": "README.md", "readme": "README.md",
"tags": "widget,clock", "tags": "widget,clock",
@ -1774,5 +1774,32 @@
"storage": [ "storage": [
{"name":"widviz.wid.js","url":"widget.js"} {"name":"widviz.wid.js","url":"widget.js"}
] ]
},
{ "id": "binclock",
"name": "Binary Clock",
"shortName":"Binary Clock",
"icon": "app.png",
"version":"0.02",
"description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.",
"tags": "clock,binary",
"type": "clock",
"storage": [
{"name":"binclock.app.js","url":"app.js"},
{"name":"binclock.img","url":"app-icon.js","evaluate":true}
]
} ,
{
"id": "pizzatimer",
"name": "Pizza Timer",
"shortName":"Pizza Timer",
"icon": "pizza.png",
"version":"0.01",
"description": "A timer app for when you cook Pizza. Some say it can also time other things",
"tags": "timer,tool,pizza",
"readme": "README.md",
"storage": [
{"name":"pizzatimer.app.js","url":"app.js"},
{"name":"pizzatimer.img","url":"app-icon.js","evaluate":true}
]
} }
] ]

159
apps/.eslintrc.json Normal file
View File

@ -0,0 +1,159 @@
{
"env": {
// TODO: "espruino": false
// TODO: "banglejs": false
},
"extends": "eslint:recommended",
"globals": {
// Methods and Fields at https://banglejs.com/reference
"Array": "readonly",
"ArrayBuffer": "readonly",
"ArrayBufferView": "readonly",
"Bangle": "readonly",
"BluetoothDevice": "readonly",
"BluetoothRemoteGATTCharacteristic": "readonly",
"BluetoothRemoteGATTServer": "readonly",
"BluetoothRemoteGATTService": "readonly",
"Boolean": "readonly",
"console": "readonly",
"DataView": "readonly",
"Date": "readonly",
"E": "readonly",
"Error": "readonly",
"Flash": "readonly",
"Float32Array": "readonly",
"Float64Array": "readonly",
"fs": "readonly",
"Function": "readonly",
"Graphics": "readonly",
"heatshrink": "readonly",
"I2C": "readonly",
"Int16Array": "readonly",
"Int32Array": "readonly",
"Int8Array": "readonly",
"InternalError": "readonly",
"JSON": "readonly",
"Math": "readonly",
"Modules": "readonly",
"NRF": "readonly",
"Number": "readonly",
"Object": "readonly",
"OneWire": "readonly",
"Pin": "readonly",
"process": "readonly",
"Promise": "readonly",
"ReferenceError": "readonly",
"RegExp": "readonly",
"Serial": "readonly",
"SPI": "readonly",
"Storage": "readonly",
"StorageFile": "readonly",
"String": "readonly",
"SyntaxError": "readonly",
"tensorflow": "readonly",
"TFMicroInterpreter": "readonly",
"TypeError": "readonly",
"Uint16Array": "readonly",
"Uint24Array": "readonly",
"Uint32Array": "readonly",
"Uint8Array": "readonly",
"Uint8ClampedArray": "readonly",
"Waveform": "readonly",
// Methods and Fields at https://banglejs.com/reference
"analogRead": "readonly",
"analogWrite": "readonly",
"arguments": "readonly",
"atob": "readonly",
"Bluetooth": "readonly",
"BTN": "readonly",
"BTN1": "readonly",
"BTN2": "readonly",
"BTN3": "readonly",
"BTN4": "readonly",
"BTN5": "readonly",
"btoa": "readonly",
"changeInterval": "readonly",
"clearInterval": "readonly",
"clearTimeout": "readonly",
"clearWatch": "readonly",
"decodeURIComponent": "readonly",
"digitalPulse": "readonly",
"digitalRead": "readonly",
"digitalWrite": "readonly",
"dump": "readonly",
"echo": "readonly",
"edit": "readonly",
"encodeURIComponent": "readonly",
"eval": "readonly",
"getPinMode": "readonly",
"getSerial": "readonly",
"getTime": "readonly",
"global": "readonly",
"HIGH": "readonly",
"I2C1": "readonly",
"Infinity": "readonly",
"isFinite": "readonly",
"isNaN": "readonly",
"LED": "readonly",
"LED1": "readonly",
"LED2": "readonly",
"load": "readonly",
"LoopbackA": "readonly",
"LoopbackB": "readonly",
"LOW": "readonly",
"NaN": "readonly",
"parseFloat": "readonly",
"parseInt": "readonly",
"peek16": "readonly",
"peek32": "readonly",
"peek8": "readonly",
"pinMode": "readonly",
"poke16": "readonly",
"poke32": "readonly",
"poke8": "readonly",
"print": "readonly",
"require": "readonly",
"reset": "readonly",
"save": "readonly",
"Serial1": "readonly",
"setBusyIndicator": "readonly",
"setInterval": "readonly",
"setSleepIndicator": "readonly",
"setTime": "readonly",
"setTimeout": "readonly",
"setWatch": "readonly",
"shiftOut": "readonly",
"SPI1": "readonly",
"Terminal": "readonly",
"trace": "readonly",
"VIBRATE": "readonly",
// Aliases and not defined at https://banglejs.com/reference
"g": "readonly",
"WIDGETS": "readonly"
},
"parserOptions": {
"ecmaVersion": 11
},
"rules": {
"indent": [
"warn",
2,
{
"SwitchCase": 1
}
],
"no-case-declarations": "off",
"no-constant-condition": "off",
"no-delete-var": "off",
"no-empty": "off",
"no-global-assign": "off",
"no-inner-declarations": "off",
"no-octal": "off",
"no-prototype-builtins": "off",
"no-redeclare": "off",
// TODO: "no-undef": "warn",
"no-undef": "off",
"no-unused-vars": "off",
"no-useless-escape": "off"
}
}

View File

@ -3,7 +3,7 @@ currently-running apps */
(() => { (() => {
function draw() { function draw() {
g.reset(); // reset the graphics context to defaults (color/font/etc) g.reset(); // reset the graphics context to defaults (color/font/etc)
// add your code // add your code
g.drawString("X", this.x, this.y); g.drawString("X", this.x, this.y);
} }

View File

@ -1,33 +1,33 @@
(() => { (() => {
//Graph module, as long as modules are not added by the app loader //Graph module, as long as modules are not added by the app loader
Modules.addCached("graph",function(){exports.drawAxes=function(b,c,a){function h(a){return e+m*(a-t)/x}function l(a){return f+g-g*(a-n)/u}var k=a.padx||0,d=a.pady||0,t=-k,w=c.length+k-1,n=(void 0!==a.miny?a.miny:a.miny=c.reduce(function(a,b){return Math.min(a,b)},c[0]))-d;c=(void 0!==a.maxy?a.maxy:a.maxy=c.reduce(function(a,b){return Math.max(a,b)},c[0]))+d;a.gridy&&(d=a.gridy,n=d*Math.floor(n/d),c=d*Math.ceil(c/d));var e=a.x||0,f=a.y||0,m=a.width||b.getWidth()-(e+1),g=a.height||b.getHeight()-(f+1);a.axes&&(null!==a.ylabel&& Modules.addCached("graph",function(){exports.drawAxes=function(b,c,a){function h(a){return e+m*(a-t)/x}function l(a){return f+g-g*(a-n)/u}var k=a.padx||0,d=a.pady||0,t=-k,w=c.length+k-1,n=(void 0!==a.miny?a.miny:a.miny=c.reduce(function(a,b){return Math.min(a,b)},c[0]))-d;c=(void 0!==a.maxy?a.maxy:a.maxy=c.reduce(function(a,b){return Math.max(a,b)},c[0]))+d;a.gridy&&(d=a.gridy,n=d*Math.floor(n/d),c=d*Math.ceil(c/d));var e=a.x||0,f=a.y||0,m=a.width||b.getWidth()-(e+1),g=a.height||b.getHeight()-(f+1);a.axes&&(null!==a.ylabel&&
(e+=6,m-=6),null!==a.xlabel&&(g-=6));a.title&&(f+=6,g-=6);a.axes&&(b.drawLine(e,f,e,f+g),b.drawLine(e,f+g,e+m,f+g));a.title&&(b.setFontAlign(0,-1),b.drawString(a.title,e+m/2,f-6));var x=w-t,u=c-n;u||(u=1);if(a.gridx){b.setFontAlign(0,-1,0);var v=a.gridx;for(d=Math.ceil((t+k)/v)*v;d<=w-k;d+=v){var r=h(d),p=a.xlabel?a.xlabel(d):d;b.setPixel(r,f+g-1);var q=b.stringWidth(p)/2;null!==a.xlabel&&r>q&&b.getWidth()>r+q&&b.drawString(p,r,f+g+2)}}if(a.gridy)for(b.setFontAlign(0,0,1),d=n;d<=c;d+=a.gridy)k=l(d), (e+=6,m-=6),null!==a.xlabel&&(g-=6));a.title&&(f+=6,g-=6);a.axes&&(b.drawLine(e,f,e,f+g),b.drawLine(e,f+g,e+m,f+g));a.title&&(b.setFontAlign(0,-1),b.drawString(a.title,e+m/2,f-6));var x=w-t,u=c-n;u||(u=1);if(a.gridx){b.setFontAlign(0,-1,0);var v=a.gridx;for(d=Math.ceil((t+k)/v)*v;d<=w-k;d+=v){var r=h(d),p=a.xlabel?a.xlabel(d):d;b.setPixel(r,f+g-1);var q=b.stringWidth(p)/2;null!==a.xlabel&&r>q&&b.getWidth()>r+q&&b.drawString(p,r,f+g+2)}}if(a.gridy)for(b.setFontAlign(0,0,1),d=n;d<=c;d+=a.gridy)k=l(d),
p=a.ylabel?a.ylabel(d):d,b.setPixel(e+1,k),q=b.stringWidth(p)/2,null!==a.ylabel&&k>q&&b.getHeight()>k+q&&b.drawString(p,e-5,k+1);b.setFontAlign(-1,-1,0);return{x:e,y:f,w:m,h:g,getx:h,gety:l}};exports.drawLine=function(b,c,a){a=a||{};a=exports.drawAxes(b,c,a);var h=!0,l;for(l in c)h?b.moveTo(a.getx(l),a.gety(c[l])):b.lineTo(a.getx(l),a.gety(c[l])),h=!1;return a};exports.drawBar=function(b,c,a){a=a||{};a.padx=1;a=exports.drawAxes(b,c,a);for(var h in c)b.fillRect(a.getx(h-.5)+1,a.gety(c[h]),a.getx(h+ p=a.ylabel?a.ylabel(d):d,b.setPixel(e+1,k),q=b.stringWidth(p)/2,null!==a.ylabel&&k>q&&b.getHeight()>k+q&&b.drawString(p,e-5,k+1);b.setFontAlign(-1,-1,0);return{x:e,y:f,w:m,h:g,getx:h,gety:l}};exports.drawLine=function(b,c,a){a=a||{};a=exports.drawAxes(b,c,a);var h=!0,l;for(l in c)h?b.moveTo(a.getx(l),a.gety(c[l])):b.lineTo(a.getx(l),a.gety(c[l])),h=!1;return a};exports.drawBar=function(b,c,a){a=a||{};a.padx=1;a=exports.drawAxes(b,c,a);for(var h in c)b.fillRect(a.getx(h-.5)+1,a.gety(c[h]),a.getx(h+
.5)-1,a.gety(0));return a}}); .5)-1,a.gety(0));return a}});
const storage = require("Storage"); const storage = require("Storage");
const SETTINGS_FILE = 'activepedom.settings.json'; const SETTINGS_FILE = 'activepedom.settings.json';
var history = 86400000; // 28800000=8h 43200000=12h //86400000=24h var history = 86400000; // 28800000=8h 43200000=12h //86400000=24h
//return setting //return setting
function setting(key) { function setting(key) {
//define default settings //define default settings
const DEFAULTS = { const DEFAULTS = {
'cMaxTime' : 1100, 'cMaxTime' : 1100,
'cMinTime' : 240, 'cMinTime' : 240,
'stepThreshold' : 30, 'stepThreshold' : 30,
'intervalResetActive' : 30000, 'intervalResetActive' : 30000,
'stepSensitivity' : 80, 'stepSensitivity' : 80,
'stepGoal' : 10000, 'stepGoal' : 10000,
'stepLength' : 75, 'stepLength' : 75,
}; };
if (!settings) { loadSettings(); } if (!settings) { loadSettings(); }
return (key in settings) ? settings[key] : DEFAULTS[key]; return (key in settings) ? settings[key] : DEFAULTS[key];
} }
//Convert ms to time //Convert ms to time
function getTime(t) { function getTime(t) {
date = new Date(t); date = new Date(t);
offset = date.getTimezoneOffset() / 60; offset = date.getTimezoneOffset() / 60;
//var milliseconds = parseInt((t % 1000) / 100), //var milliseconds = parseInt((t % 1000) / 100),
@ -39,9 +39,9 @@ function getTime(t) {
minutes = (minutes < 10) ? "0" + minutes : minutes; minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds; seconds = (seconds < 10) ? "0" + seconds : seconds;
return hours + ":" + minutes + ":" + seconds; return hours + ":" + minutes + ":" + seconds;
} }
function getDate(t) { function getDate(t) {
date = new Date(t*1); date = new Date(t*1);
year = date.getFullYear(); year = date.getFullYear();
month = date.getMonth()+1; //month is zero-based month = date.getMonth()+1; //month is zero-based
@ -49,27 +49,27 @@ function getDate(t) {
month = (month < 10) ? "0" + month : month; month = (month < 10) ? "0" + month : month;
day = (day < 10) ? "0" + day : day; day = (day < 10) ? "0" + day : day;
return year + "-" + month + "-" + day; return year + "-" + month + "-" + day;
} }
//columns: 0=time, 1=stepsCounted, 2=active, 3=stepsTooShort, 4=stepsTooLong, 5=stepsOutsideTime //columns: 0=time, 1=stepsCounted, 2=active, 3=stepsTooShort, 4=stepsTooLong, 5=stepsOutsideTime
function getArrayFromCSV(file, column) { function getArrayFromCSV(file, column) {
i = 0; i = 0;
array = []; array = [];
now = new Date(); now = new Date();
while ((nextLine = file.readLine())) { //as long as there is a next line while ((nextLine = file.readLine())) { //as long as there is a next line
if(nextLine) { if(nextLine) {
dataSplitted = nextLine.split(','); //split line, dataSplitted = nextLine.split(','); //split line,
diff = now - dataSplitted[0]; //calculate difference between now and stored time diff = now - dataSplitted[0]; //calculate difference between now and stored time
if (diff <= history) { //only entries from the last x ms if (diff <= history) { //only entries from the last x ms
array.push(dataSplitted[column]); array.push(dataSplitted[column]);
}
} }
i++; }
i++;
} }
return array; return array;
} }
function drawGraph() { function drawGraph() {
//times //times
// actives = getArrayFromCSV(csvFile, 2); // actives = getArrayFromCSV(csvFile, 2);
// shorts = getArrayFromCSV(csvFile, 3); // shorts = getArrayFromCSV(csvFile, 3);
@ -104,62 +104,62 @@ function drawGraph() {
g.drawString("First: " + first, 10, 30); g.drawString("First: " + first, 10, 30);
g.drawString(" Last: " + last, 10, 40); g.drawString(" Last: " + last, 10, 40);
require("graph").drawLine(g, steps, { require("graph").drawLine(g, steps, {
//title: "Steps Counted", //title: "Steps Counted",
axes : true, axes : true,
gridy : gridyValue, gridy : gridyValue,
y : 60, //offset on screen y : 60, //offset on screen
x : 5, //offset on screen x : 5, //offset on screen
}); });
//free memory from big variables //free memory from big variables
allData = undefined; allData = undefined;
allDataFile = undefined; allDataFile = undefined;
csvFile = undefined; csvFile = undefined;
times = undefined; times = undefined;
} }
function drawMenu () { function drawMenu () {
g.clear(); g.clear();
g.setFont("6x8", 1); g.setFont("6x8", 1);
g.drawString("BTN1:Timespan | BTN2:Draw", 20, 10); g.drawString("BTN1:Timespan | BTN2:Draw", 20, 10);
g.drawString("Timespan: " + history/1000/60/60 + " hours", 20, 20); g.drawString("Timespan: " + history/1000/60/60 + " hours", 20, 20);
} }
setWatch(function() { //BTN1 setWatch(function() { //BTN1
switch(history) { switch(history) {
case 3600000 : //1h case 3600000 : //1h
history = 14400000; //4h history = 14400000; //4h
break; break;
case 86400000 : //24 case 86400000 : //24
history = 3600000; //1h history = 3600000; //1h
break; break;
default : default :
history = history + 14400000; //4h history = history + 14400000; //4h
break; break;
} }
drawMenu(); drawMenu();
}, BTN1, {edge:"rising", debounce:50, repeat:true}); }, BTN1, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN2 setWatch(function() { //BTN2
g.setFont("6x8", 2); g.setFont("6x8", 2);
g.drawString ("Drawing...",30,60); g.drawString ("Drawing...",30,60);
drawGraph(); drawGraph();
}, BTN2, {edge:"rising", debounce:50, repeat:true}); }, BTN2, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN3 setWatch(function() { //BTN3
}, BTN3, {edge:"rising", debounce:50, repeat:true}); }, BTN3, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN4 setWatch(function() { //BTN4
}, BTN4, {edge:"rising", debounce:50, repeat:true}); }, BTN4, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN5 setWatch(function() { //BTN5
}, BTN5, {edge:"rising", debounce:50, repeat:true}); }, BTN5, {edge:"rising", debounce:50, repeat:true});
//load settings //load settings
let settings; let settings;
function loadSettings() { function loadSettings() {
settings = storage.readJSON(SETTINGS_FILE, 1) || {}; settings = storage.readJSON(SETTINGS_FILE, 1) || {};
} }
drawMenu(); drawMenu();
})(); })();

View File

@ -26,7 +26,7 @@
var storeDataInterval = 5*60*1000; //ms var storeDataInterval = 5*60*1000; //ms
let settings; let settings;
//load settings //load settings
function loadSettings() { function loadSettings() {
settings = s.readJSON(SETTINGS_FILE, 1) || {}; settings = s.readJSON(SETTINGS_FILE, 1) || {};
} }
@ -69,8 +69,8 @@
'stepGoal' : 10000, 'stepGoal' : 10000,
'stepLength' : 75, 'stepLength' : 75,
}; };
if (!settings) { loadSettings(); } if (!settings) { loadSettings(); }
return (key in settings) ? settings[key] : DEFAULTS[key]; return (key in settings) ? settings[key] : DEFAULTS[key];
} }
function setStepSensitivity(s) { function setStepSensitivity(s) {

View File

@ -5,3 +5,4 @@
0.05: Add alarm.boot.js and move code from the bootloader 0.05: Add alarm.boot.js and move code from the bootloader
0.06: Change 'New Alarm' to 'Save', allow Deletion of Alarms 0.06: Change 'New Alarm' to 'Save', allow Deletion of Alarms
0.07: Don't overwrite existing settings on app update 0.07: Don't overwrite existing settings on app update
0.08: Make alarm scheduling more reliable

View File

@ -2,15 +2,16 @@
(function() { (function() {
var alarms = require('Storage').readJSON('alarm.json',1)||[]; var alarms = require('Storage').readJSON('alarm.json',1)||[];
var time = new Date(); var time = new Date();
var active = alarms.filter(a=>a.on&&(a.last!=time.getDate())); var active = alarms.filter(a=>a.on);
if (active.length) { if (active.length) {
active = active.sort((a,b)=>a.hr-b.hr); active = active.sort((a,b)=>(a.hr-b.hr)+(a.last-b.last)*24);
var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);
if (!require('Storage').read("alarm.js")) { if (!require('Storage').read("alarm.js")) {
console.log("No alarm app!"); console.log("No alarm app!");
require('Storage').write('alarm.json',"[]") require('Storage').write('alarm.json',"[]");
} else { } else {
var t = 3600000*(active[0].hr-hr); var t = 3600000*(active[0].hr-hr);
if (active[0].last == time.getDate() || t < 0) t += 86400000;
if (t<1000) t=1000; if (t<1000) t=1000;
/* execute alarm at the correct time. We avoid execing immediately /* execute alarm at the correct time. We avoid execing immediately
since this code will get called AGAIN when alarm.js is loaded. alarm.js since this code will get called AGAIN when alarm.js is loaded. alarm.js
@ -21,4 +22,4 @@
},t); },t);
} }
} }
})() })();

View File

@ -155,7 +155,7 @@ function drawMoonPositionPage(gps, title) {
drawPoint(azimuthDegrees, 8, {r: 1, g: 1, b: 1}); drawPoint(azimuthDegrees, 8, {r: 1, g: 1, b: 1});
let m = setWatch(() => { let m = setWatch(() => {
let m = moonIndexPageMenu(gps); let m = moonIndexPageMenu(gps);
}, BTN3, {repeat: false, edge: "falling"}); }, BTN3, {repeat: false, edge: "falling"});
} }
@ -232,61 +232,61 @@ function drawSunShowPage(gps, key, date) {
drawPoint(azimuthDegrees, 8, {r: 1, g: 1, b: 0}); drawPoint(azimuthDegrees, 8, {r: 1, g: 1, b: 0});
m = setWatch(() => { m = setWatch(() => {
m = sunIndexPageMenu(gps); m = sunIndexPageMenu(gps);
}, BTN3, {repeat: false, edge: "falling"}); }, BTN3, {repeat: false, edge: "falling"});
return null; return null;
} }
function sunIndexPageMenu(gps) { function sunIndexPageMenu(gps) {
const sunTimes = SunCalc.getTimes(new Date(), gps.lat, gps.lon); const sunTimes = SunCalc.getTimes(new Date(), gps.lat, gps.lon);
const sunMenu = { const sunMenu = {
"": { "": {
"title": "-- Sun --", "title": "-- Sun --",
}, },
"Current Pos": () => { "Current Pos": () => {
m = E.showMenu(); m = E.showMenu();
drawSunShowPage(gps, "Current Pos", new Date()); drawSunShowPage(gps, "Current Pos", new Date());
}, },
};
Object.keys(sunTimes).sort().reduce((menu, key) => {
const title = titlizeKey(key);
menu[title] = () => {
m = E.showMenu();
drawSunShowPage(gps, key, sunTimes[key]);
}; };
return menu;
}, sunMenu);
Object.keys(sunTimes).sort().reduce((menu, key) => { sunMenu["< Back"] = () => m = indexPageMenu(gps);
const title = titlizeKey(key);
menu[title] = () => {
m = E.showMenu();
drawSunShowPage(gps, key, sunTimes[key]);
};
return menu;
}, sunMenu);
sunMenu["< Back"] = () => m = indexPageMenu(gps); return E.showMenu(sunMenu);
return E.showMenu(sunMenu);
} }
function moonIndexPageMenu(gps) { function moonIndexPageMenu(gps) {
const moonMenu = { const moonMenu = {
"": { "": {
"title": "-- Moon --", "title": "-- Moon --",
}, },
"Times": () => { "Times": () => {
m = E.showMenu(); m = E.showMenu();
drawMoonTimesPage(gps, "Times"); drawMoonTimesPage(gps, "Times");
}, },
"Position": () => { "Position": () => {
m = E.showMenu(); m = E.showMenu();
drawMoonPositionPage(gps, "Position"); drawMoonPositionPage(gps, "Position");
}, },
"Illumination": () => { "Illumination": () => {
m = E.showMenu(); m = E.showMenu();
drawMoonIlluminationPage(gps, "Illumination"); drawMoonIlluminationPage(gps, "Illumination");
}, },
"< Back": () => m = indexPageMenu(gps), "< Back": () => m = indexPageMenu(gps),
}; };
return E.showMenu(moonMenu); return E.showMenu(moonMenu);
} }
function indexPageMenu(gps) { function indexPageMenu(gps) {
@ -314,74 +314,74 @@ function getCenterStringX(str) {
* GPS wait page, shows GPS locating animation until it gets a lock, then moves to the Sun page * GPS wait page, shows GPS locating animation until it gets a lock, then moves to the Sun page
*/ */
function drawGPSWaitPage() { function drawGPSWaitPage() {
const img = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA==")); const img = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA=="));
const str1 = "Astrocalc v0.02"; const str1 = "Astrocalc v0.02";
const str2 = "Locating GPS"; const str2 = "Locating GPS";
const str3 = "Please wait..."; const str3 = "Please wait...";
g.clear(); g.clear();
g.drawImage(img, 100, 50); g.drawImage(img, 100, 50);
g.setFont("6x8", 1); g.setFont("6x8", 1);
g.drawString(str1, getCenterStringX(str1), 105); g.drawString(str1, getCenterStringX(str1), 105);
g.drawString(str2, getCenterStringX(str2), 140); g.drawString(str2, getCenterStringX(str2), 140);
g.drawString(str3, getCenterStringX(str3), 155); g.drawString(str3, getCenterStringX(str3), 155);
if (lastGPS) { if (lastGPS) {
lastGPS = JSON.parse(lastGPS); lastGPS = JSON.parse(lastGPS);
lastGPS.time = new Date(); lastGPS.time = new Date();
const str4 = "Press Button 3 to use last GPS"; const str4 = "Press Button 3 to use last GPS";
g.setColor("#d32e29"); g.setColor("#d32e29");
g.fillRect(0, 190, g.getWidth(), 215); g.fillRect(0, 190, g.getWidth(), 215);
g.setColor("#ffffff"); g.setColor("#ffffff");
g.drawString(str4, getCenterStringX(str4), 200); g.drawString(str4, getCenterStringX(str4), 200);
setWatch(() => { setWatch(() => {
clearWatch();
Bangle.setGPSPower(0);
m = indexPageMenu(lastGPS);
}, BTN3, {repeat: false});
}
g.flip();
const DEBUG = false;
if (DEBUG) {
clearWatch(); clearWatch();
Bangle.setGPSPower(0);
m = indexPageMenu(lastGPS);
}, BTN3, {repeat: false});
}
const gps = { g.flip();
"lat": 56.45783133333,
"lon": -3.02188583333,
"alt": 75.3,
"speed": 0.070376,
"course": NaN,
"time":new Date(),
"satellites": 4,
"fix": 1
};
m = indexPageMenu(gps); const DEBUG = false;
if (DEBUG) {
clearWatch();
return; const gps = {
} "lat": 56.45783133333,
"lon": -3.02188583333,
"alt": 75.3,
"speed": 0.070376,
"course": NaN,
"time":new Date(),
"satellites": 4,
"fix": 1
};
Bangle.on('GPS', (gps) => { m = indexPageMenu(gps);
if (gps.fix === 0) return;
clearWatch();
if (isNaN(gps.course)) gps.course = 0; return;
require("Storage").writeJSON(LAST_GPS_FILE, JSON.stringify(gps)); }
Bangle.setGPSPower(0);
Bangle.buzz();
Bangle.setLCDPower(true);
m = indexPageMenu(gps); Bangle.on('GPS', (gps) => {
}); if (gps.fix === 0) return;
clearWatch();
if (isNaN(gps.course)) gps.course = 0;
require("Storage").writeJSON(LAST_GPS_FILE, JSON.stringify(gps));
Bangle.setGPSPower(0);
Bangle.buzz();
Bangle.setLCDPower(true);
m = indexPageMenu(gps);
});
} }
function init() { function init() {
Bangle.setGPSPower(1); Bangle.setGPSPower(1);
drawGPSWaitPage(); drawGPSWaitPage();
} }
let m; let m;

View File

@ -6,9 +6,9 @@
(function () { 'use strict'; (function () { 'use strict';
// shortcuts for easier to read formulas // shortcuts for easier to read formulas
var PI = Math.PI, var PI = Math.PI,
sin = Math.sin, sin = Math.sin,
cos = Math.cos, cos = Math.cos,
tan = Math.tan, tan = Math.tan,
@ -17,219 +17,219 @@ var PI = Math.PI,
acos = Math.acos, acos = Math.acos,
rad = PI / 180; rad = PI / 180;
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
// date/time constants and conversions // date/time constants and conversions
var dayMs = 1000 * 60 * 60 * 24, var dayMs = 1000 * 60 * 60 * 24,
J1970 = 2440588, J1970 = 2440588,
J2000 = 2451545; J2000 = 2451545;
function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
function fromJulian(j) { return (j + 0.5 - J1970) * dayMs; } function fromJulian(j) { return (j + 0.5 - J1970) * dayMs; }
function toDays(date) { return toJulian(date) - J2000; } function toDays(date) { return toJulian(date) - J2000; }
// general calculations for position // general calculations for position
var e = rad * 23.4397; // obliquity of the Earth var e = rad * 23.4397; // obliquity of the Earth
function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); } function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); }
function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); } function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
function astroRefraction(h) { function astroRefraction(h) {
if (h < 0) // the following formula works for positive altitudes only. if (h < 0) // the following formula works for positive altitudes only.
h = 0; // if h = -0.08901179 a div/0 would occur. h = 0; // if h = -0.08901179 a div/0 would occur.
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
} }
// general sun calculations // general sun calculations
function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
function eclipticLongitude(M) { function eclipticLongitude(M) {
var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
P = rad * 102.9372; // perihelion of the Earth P = rad * 102.9372; // perihelion of the Earth
return M + C + P + PI; return M + C + P + PI;
} }
function sunCoords(d) { function sunCoords(d) {
var M = solarMeanAnomaly(d), var M = solarMeanAnomaly(d),
L = eclipticLongitude(M); L = eclipticLongitude(M);
return { return {
dec: declination(L, 0), dec: declination(L, 0),
ra: rightAscension(L, 0) ra: rightAscension(L, 0)
}; };
} }
var SunCalc = {}; var SunCalc = {};
// calculates sun position for a given date and latitude/longitude // calculates sun position for a given date and latitude/longitude
SunCalc.getPosition = function (date, lat, lng) { SunCalc.getPosition = function (date, lat, lng) {
var lw = rad * -lng, var lw = rad * -lng,
phi = rad * lat, phi = rad * lat,
d = toDays(date), d = toDays(date),
c = sunCoords(d), c = sunCoords(d),
H = siderealTime(d, lw) - c.ra; H = siderealTime(d, lw) - c.ra;
return { return {
azimuth: azimuth(H, phi, c.dec), azimuth: azimuth(H, phi, c.dec),
altitude: altitude(H, phi, c.dec) altitude: altitude(H, phi, c.dec)
}; };
}; };
// sun times configuration (angle, morning name, evening name) // sun times configuration (angle, morning name, evening name)
var times = SunCalc.times = [ var times = SunCalc.times = [
[-0.833, 'sunrise', 'sunset' ], [-0.833, 'sunrise', 'sunset' ],
[ -0.3, 'sunriseEnd', 'sunsetStart' ], [ -0.3, 'sunriseEnd', 'sunsetStart' ],
[ -6, 'dawn', 'dusk' ], [ -6, 'dawn', 'dusk' ],
[ -12, 'nauticalDawn', 'nauticalDusk'], [ -12, 'nauticalDawn', 'nauticalDusk'],
[ -18, 'nightEnd', 'night' ], [ -18, 'nightEnd', 'night' ],
[ 6, 'goldenHourEnd', 'goldenHour' ] [ 6, 'goldenHourEnd', 'goldenHour' ]
]; ];
// adds a custom time to the times config // adds a custom time to the times config
SunCalc.addTime = function (angle, riseName, setName) { SunCalc.addTime = function (angle, riseName, setName) {
times.push([angle, riseName, setName]); times.push([angle, riseName, setName]);
}; };
// calculations for sun times // calculations for sun times
var J0 = 0.0009; var J0 = 0.0009;
function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); }
function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; }
function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); }
function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); }
function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; }
// returns set time for the given sun altitude // returns set time for the given sun altitude
function getSetJ(h, lw, phi, dec, n, M, L) { function getSetJ(h, lw, phi, dec, n, M, L) {
var w = hourAngle(h, phi, dec), var w = hourAngle(h, phi, dec),
a = approxTransit(w, lw, n); a = approxTransit(w, lw, n);
return solarTransitJ(a, M, L); return solarTransitJ(a, M, L);
} }
// calculates sun times for a given date, latitude/longitude, and, optionally, // calculates sun times for a given date, latitude/longitude, and, optionally,
// the observer height (in meters) relative to the horizon // the observer height (in meters) relative to the horizon
SunCalc.getTimes = function (date, lat, lng, height) { SunCalc.getTimes = function (date, lat, lng, height) {
height = height || 0; height = height || 0;
var lw = rad * -lng, var lw = rad * -lng,
phi = rad * lat, phi = rad * lat,
dh = observerAngle(height), dh = observerAngle(height),
d = toDays(date), d = toDays(date),
n = julianCycle(d, lw), n = julianCycle(d, lw),
ds = approxTransit(0, lw, n), ds = approxTransit(0, lw, n),
M = solarMeanAnomaly(ds), M = solarMeanAnomaly(ds),
L = eclipticLongitude(M), L = eclipticLongitude(M),
dec = declination(L, 0), dec = declination(L, 0),
Jnoon = solarTransitJ(ds, M, L), Jnoon = solarTransitJ(ds, M, L),
i, len, time, h0, Jset, Jrise; i, len, time, h0, Jset, Jrise;
var result = { var result = {
solarNoon: new Date(fromJulian(Jnoon)), solarNoon: new Date(fromJulian(Jnoon)),
nadir: new Date(fromJulian(Jnoon - 0.5)) nadir: new Date(fromJulian(Jnoon - 0.5))
}; };
for (i = 0, len = times.length; i < len; i += 1) { for (i = 0, len = times.length; i < len; i += 1) {
time = times[i]; time = times[i];
h0 = (time[0] + dh) * rad; h0 = (time[0] + dh) * rad;
Jset = getSetJ(h0, lw, phi, dec, n, M, L); Jset = getSetJ(h0, lw, phi, dec, n, M, L);
Jrise = Jnoon - (Jset - Jnoon); Jrise = Jnoon - (Jset - Jnoon);
result[time[1]] = new Date(fromJulian(Jrise) - (dayMs / 2)); result[time[1]] = new Date(fromJulian(Jrise) - (dayMs / 2));
result[time[2]] = new Date(fromJulian(Jset) + (dayMs / 2)); result[time[2]] = new Date(fromJulian(Jset) + (dayMs / 2));
} }
return result; return result;
}; };
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas // moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
function moonCoords(d) { // geocentric ecliptic coordinates of the moon function moonCoords(d) { // geocentric ecliptic coordinates of the moon
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
M = rad * (134.963 + 13.064993 * d), // mean anomaly M = rad * (134.963 + 13.064993 * d), // mean anomaly
F = rad * (93.272 + 13.229350 * d), // mean distance F = rad * (93.272 + 13.229350 * d), // mean distance
l = L + rad * 6.289 * sin(M), // longitude l = L + rad * 6.289 * sin(M), // longitude
b = rad * 5.128 * sin(F), // latitude b = rad * 5.128 * sin(F), // latitude
dt = 385001 - 20905 * cos(M); // distance to the moon in km dt = 385001 - 20905 * cos(M); // distance to the moon in km
return { return {
ra: rightAscension(l, b), ra: rightAscension(l, b),
dec: declination(l, b), dec: declination(l, b),
dist: dt dist: dt
}; };
} }
SunCalc.getMoonPosition = function (date, lat, lng) { SunCalc.getMoonPosition = function (date, lat, lng) {
var lw = rad * -lng, var lw = rad * -lng,
phi = rad * lat, phi = rad * lat,
d = toDays(date), d = toDays(date),
c = moonCoords(d), c = moonCoords(d),
H = siderealTime(d, lw) - c.ra, H = siderealTime(d, lw) - c.ra,
h = altitude(H, phi, c.dec), h = altitude(H, phi, c.dec),
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
h = h + astroRefraction(h); // altitude correction for refraction h = h + astroRefraction(h); // altitude correction for refraction
return { return {
azimuth: azimuth(H, phi, c.dec), azimuth: azimuth(H, phi, c.dec),
altitude: h, altitude: h,
distance: c.dist, distance: c.dist,
parallacticAngle: pa parallacticAngle: pa
}; };
}; };
// calculations for illumination parameters of the moon, // calculations for illumination parameters of the moon,
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
// Function updated from gist: https://gist.github.com/endel/dfe6bb2fbe679781948c // Function updated from gist: https://gist.github.com/endel/dfe6bb2fbe679781948c
SunCalc.getMoonIllumination = function (date) { SunCalc.getMoonIllumination = function (date) {
let month = date.getMonth(); let month = date.getMonth();
let year = date.getFullYear(); let year = date.getFullYear();
let day = date.getDate(); let day = date.getDate();
@ -256,57 +256,57 @@ SunCalc.getMoonIllumination = function (date) {
if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0 if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0
return {phase: b}; return {phase: b};
}; };
function hoursLater(date, h) { function hoursLater(date, h) {
return new Date(date.valueOf() + h * dayMs / 24); return new Date(date.valueOf() + h * dayMs / 24);
} }
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article // calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
var t = date; var t = date;
if (inUTC) t.setUTCHours(0, 0, 0, 0); if (inUTC) t.setUTCHours(0, 0, 0, 0);
else t.setHours(0, 0, 0, 0); else t.setHours(0, 0, 0, 0);
var hc = 0.133 * rad, var hc = 0.133 * rad,
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
for (var i = 1; i <= 24; i += 2) { for (var i = 1; i <= 24; i += 2) {
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
a = (h0 + h2) / 2 - h1; a = (h0 + h2) / 2 - h1;
b = (h2 - h0) / 2; b = (h2 - h0) / 2;
xe = -b / (2 * a); xe = -b / (2 * a);
ye = (a * xe + b) * xe + h1; ye = (a * xe + b) * xe + h1;
d = b * b - 4 * a * h1; d = b * b - 4 * a * h1;
roots = 0; roots = 0;
if (d >= 0) { if (d >= 0) {
dx = Math.sqrt(d) / (Math.abs(a) * 2); dx = Math.sqrt(d) / (Math.abs(a) * 2);
x1 = xe - dx; x1 = xe - dx;
x2 = xe + dx; x2 = xe + dx;
if (Math.abs(x1) <= 1) roots++; if (Math.abs(x1) <= 1) roots++;
if (Math.abs(x2) <= 1) roots++; if (Math.abs(x2) <= 1) roots++;
if (x1 < -1) x1 = x2; if (x1 < -1) x1 = x2;
} }
if (roots === 1) { if (roots === 1) {
if (h0 < 0) rise = i + x1; if (h0 < 0) rise = i + x1;
else set = i + x1; else set = i + x1;
} else if (roots === 2) { } else if (roots === 2) {
rise = i + (ye < 0 ? x2 : x1); rise = i + (ye < 0 ? x2 : x1);
set = i + (ye < 0 ? x1 : x2); set = i + (ye < 0 ? x1 : x2);
} }
if (rise && set) break; if (rise && set) break;
h0 = h2; h0 = h2;
} }
var result = {}; var result = {};
@ -317,12 +317,12 @@ SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
return result; return result;
}; };
// export as Node module / AMD module / browser variable // export as Node module / AMD module / browser variable
if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc;
else if (typeof define === 'function' && define.amd) define(SunCalc); else if (typeof define === 'function' && define.amd) define(SunCalc);
else global.SunCalc = SunCalc; else global.SunCalc = SunCalc;
}()); }());

View File

@ -66,7 +66,7 @@
// Very coarse first approach to check if the BLE device is on. // Very coarse first approach to check if the BLE device is on.
if (NRF.getSecurityStatus().connected) if (NRF.getSecurityStatus().connected)
enabledConsumers = enabledConsumers | switchableConsumers.bluetooth; enabledConsumers = enabledConsumers | switchableConsumers.bluetooth;
// Reset the event registration vars // Reset the event registration vars
compassEventReceived = false; compassEventReceived = false;

View File

@ -6,98 +6,98 @@ const colpos = canvasWidth / numberOfColumns - 10;
const binSize = (canvasWidth / numberOfColumns) / 3; const binSize = (canvasWidth / numberOfColumns) / 3;
const findBinary = target => { const findBinary = target => {
return [ return [
[0, 0, 0, 0], // 0 [0, 0, 0, 0], // 0
[1, 0, 0, 0], // 1 [1, 0, 0, 0], // 1
[0, 1, 0, 0], // 2 [0, 1, 0, 0], // 2
[1, 1, 0, 0], // 3 [1, 1, 0, 0], // 3
[0, 0, 1, 0], // 4 [0, 0, 1, 0], // 4
[1, 0, 1, 0], // 5 [1, 0, 1, 0], // 5
[0, 1, 1, 0], // 6 [0, 1, 1, 0], // 6
[1, 1, 1, 0], // 7 [1, 1, 1, 0], // 7
[0, 0, 0, 1], // 8 [0, 0, 0, 1], // 8
[1, 0, 0, 1], // 9 [1, 0, 0, 1], // 9
][target]; ][target];
}; };
const getCurrentTime = () => { const getCurrentTime = () => {
const flattenArray = (array = []) => [].concat.apply([], array); const flattenArray = (array = []) => [].concat.apply([], array);
const format = number => { const format = number => {
const numberStr = number.toString(); const numberStr = number.toString();
return numberStr.length === 1 ? ["0", numberStr] : numberStr.split(""); return numberStr.length === 1 ? ["0", numberStr] : numberStr.split("");
}; };
const now = new Date(); const now = new Date();
return flattenArray([now.getHours(), now.getMinutes(), now.getSeconds()].map(format)); return flattenArray([now.getHours(), now.getMinutes(), now.getSeconds()].map(format));
}; };
let prevFrame = []; let prevFrame = [];
const drawColumn = (position = 0, column = [0, 0, 0, 0]) => { const drawColumn = (position = 0, column = [0, 0, 0, 0]) => {
const maxDotsPerColumn = [2, 4, 3, 4, 3, 4]; const maxDotsPerColumn = [2, 4, 3, 4, 3, 4];
const columnPos = position * colpos; const columnPos = position * colpos;
let pos = colpos / 2 + 45; let pos = colpos / 2 + 45;
const frame = column.reverse(); const frame = column.reverse();
const drawDot = fn => g[fn]((columnPos + colpos / 2), pos, binSize); const drawDot = fn => g[fn]((columnPos + colpos / 2), pos, binSize);
for (let i = 0; i < frame.length; i += 1) { for (let i = 0; i < frame.length; i += 1) {
if (i + maxDotsPerColumn[position] >= 4 || drawFullGrid) { if (i + maxDotsPerColumn[position] >= 4 || drawFullGrid) {
if (prevFrame && prevFrame[position] && prevFrame[position][i]) { if (prevFrame && prevFrame[position] && prevFrame[position][i]) {
if (frame[i] !== prevFrame[position][i]) { if (frame[i] !== prevFrame[position][i]) {
// subsequent draw // subsequent draw
g.clearRect((columnPos + colpos / 2) - 15, pos - 15, (columnPos + colpos / 2) + 20, pos + 20); g.clearRect((columnPos + colpos / 2) - 15, pos - 15, (columnPos + colpos / 2) + 20, pos + 20);
if (frame[i]) { if (frame[i]) {
drawDot('fillCircle'); drawDot('fillCircle');
} else { } else {
drawDot('drawCircle'); drawDot('drawCircle');
} }
}
} else {
// First draw
if (frame[i]) {
drawDot('fillCircle');
} else {
drawDot('drawCircle');
}
}
} }
pos += colpos; } else {
// First draw
if (frame[i]) {
drawDot('fillCircle');
} else {
drawDot('drawCircle');
}
}
} }
pos += colpos;
}
}; };
const drawClock = () => { const drawClock = () => {
const data = getCurrentTime().map(findBinary); const data = getCurrentTime().map(findBinary);
for (let i = 0; i < data.length; i += 1) { for (let i = 0; i < data.length; i += 1) {
drawColumn(i, data[i]); drawColumn(i, data[i]);
} }
prevFrame = data; prevFrame = data;
}; };
// Themes // Themes
const drawTheme = (idx) => () => { const drawTheme = (idx) => () => {
idx += 1; idx += 1;
const themes = [ const themes = [
[[0, 0, 0], [1, 1, 1]], [[0, 0, 0], [1, 1, 1]],
[[1, 1, 1], [0, 0, 0]], [[1, 1, 1], [0, 0, 0]],
[[0, 0, 0], [1, 0, 0]], [[0, 0, 0], [1, 0, 0]],
[[0, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 1, 0]],
[[0, 0, 0], [0, 0, 1]], [[0, 0, 0], [0, 0, 1]],
]; ];
if (idx >= themes.length) idx = 0; if (idx >= themes.length) idx = 0;
const color = themes[idx]; const color = themes[idx];
g.setBgColor.apply(g, color[0]); g.setBgColor.apply(g, color[0]);
g.setColor.apply(g, color[1]); g.setColor.apply(g, color[1]);
g.clear(); g.clear();
}; };
const nextTheme = drawTheme(0); const nextTheme = drawTheme(0);
setWatch(() => { setWatch(() => {
prevFrame = []; prevFrame = [];
Bangle.beep(); Bangle.beep();
nextTheme(); nextTheme();
}, BTN1, { repeat: true }); }, BTN1, { repeat: true });
Bangle.on('lcdPower', on => { Bangle.on('lcdPower', on => {
if (on) drawClock(); if (on) drawClock();
}); });
g.clear(); g.clear();

View File

@ -10,388 +10,388 @@ require('FontTeletext10x18Ascii').add(Graphics);
// Double height text // Double height text
Graphics.prototype.drawStringDH = function (txt, px, py, align, gw) { Graphics.prototype.drawStringDH = function (txt, px, py, align, gw) {
let g2 = Graphics.createArrayBuffer(gw,18,1,{msb:true}); let g2 = Graphics.createArrayBuffer(gw,18,1,{msb:true});
g2.setFontTeletext10x18Ascii(); g2.setFontTeletext10x18Ascii();
let w = g2.stringWidth(txt); let w = g2.stringWidth(txt);
let c = (w+3)>>2; let c = (w+3)>>2;
g2.drawString(txt); g2.drawString(txt);
let img = {width:w,height:1,transparent:0,buffer:new ArrayBuffer(c)}; let img = {width:w,height:1,transparent:0,buffer:new ArrayBuffer(c)};
let a = new Uint8Array(img.buffer); let a = new Uint8Array(img.buffer);
let x; let x;
switch (align) { switch (align) {
case 'C': x = px + (gw - w)/2; break; case 'C': x = px + (gw - w)/2; break;
case 'R': x = gw - w + px; break; case 'R': x = gw - w + px; break;
default: x = px; default: x = px;
} }
for (var y=0;y<18;y++) { for (var y=0;y<18;y++) {
a.set(new Uint8Array(g2.buffer,gw*y/8,c)); a.set(new Uint8Array(g2.buffer,gw*y/8,c));
this.drawImage(img,x,py+y*2); this.drawImage(img,x,py+y*2);
this.drawImage(img,x,py+1+y*2); this.drawImage(img,x,py+1+y*2);
} }
}; };
// Fill rectangle rotated around the centre // Fill rectangle rotated around the centre
Graphics.prototype.fillRotRect = function (sina, cosa, cx, cy, x0, x1, y0, y1) { Graphics.prototype.fillRotRect = function (sina, cosa, cx, cy, x0, x1, y0, y1) {
let fn = Math.ceil; let fn = Math.ceil;
return this.fillPoly([ return this.fillPoly([
fn(cx - x0*cosa + y0*sina), fn(cy - x0*sina - y0*cosa), fn(cx - x0*cosa + y0*sina), fn(cy - x0*sina - y0*cosa),
fn(cx - x1*cosa + y0*sina), fn(cy - x1*sina - y0*cosa), fn(cx - x1*cosa + y0*sina), fn(cy - x1*sina - y0*cosa),
fn(cx - x1*cosa + y1*sina), fn(cy - x1*sina - y1*cosa), fn(cx - x1*cosa + y1*sina), fn(cy - x1*sina - y1*cosa),
fn(cx - x0*cosa + y1*sina), fn(cy - x0*sina - y1*cosa) fn(cx - x0*cosa + y1*sina), fn(cy - x0*sina - y1*cosa)
]); ]);
}; };
// Draw a line from r1,a to r2,a relative to cx+cy // Draw a line from r1,a to r2,a relative to cx+cy
Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) { Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) {
return this.drawLine( return this.drawLine(
cx + r1*sina, cy - r1*cosa, cx + r1*sina, cy - r1*cosa,
cx + r2*sina, cy - r2*cosa cx + r2*sina, cy - r2*cosa
); );
}; };
(function(g) { (function(g) {
// Display modes // Display modes
// //
// 0: full-screen // 0: full-screen
// 1: with widgets // 1: with widgets
// 2: centred on Bangle (v.1), no widgets or time/date // 2: centred on Bangle (v.1), no widgets or time/date
// 3: centred with time above // 3: centred with time above
// 4: centred with date above // 4: centred with date above
// 5: centred with time and date above // 5: centred with time and date above
let mode; let mode;
// R1, R2: Outer and inner radii of hour marks // R1, R2: Outer and inner radii of hour marks
// RC1, RC2: Outer and inner radii of hub // RC1, RC2: Outer and inner radii of hub
// CX, CY: Centre location, relative to buffer (not screen, necessarily) // CX, CY: Centre location, relative to buffer (not screen, necessarily)
// HW2, MW2: Half-width of hour and minute hand // HW2, MW2: Half-width of hour and minute hand
// HR, MR: Length of hour and minute hand, relative to CX,CY // HR, MR: Length of hour and minute hand, relative to CX,CY
// M: Half-width of gap in hour marks // M: Half-width of gap in hour marks
// HSCALE: Half-width of hour mark as function(0<h<13) // HSCALE: Half-width of hour mark as function(0<h<13)
let R1, R2, RC1, RC2, CX, CY, HW2, MW2, HR, MR, M, HSCALE; let R1, R2, RC1, RC2, CX, CY, HW2, MW2, HR, MR, M, HSCALE;
// Screen size // Screen size
const GW = g.getWidth(); const GW = g.getWidth();
const GH = g.getHeight(); const GH = g.getHeight();
// Top margin: the gap taken from the top of the buffer, except when // Top margin: the gap taken from the top of the buffer, except when
// in mode 0 (full screen) // in mode 0 (full screen)
let TM; let TM;
// Buffer image. undefined means it needs regenerating // Buffer image. undefined means it needs regenerating
let faceImg; let faceImg;
// with_seconds flag determines whether the face is updated every // with_seconds flag determines whether the face is updated every
// second or every minute, and to draw the hand or not. // second or every minute, and to draw the hand or not.
let with_seconds = true; let with_seconds = true;
// Display flags, determined from `mode` by setMode() // Display flags, determined from `mode` by setMode()
let with_widgets = false; let with_widgets = false;
let with_digital_time = true; let with_digital_time = true;
let with_digital_date = true; let with_digital_date = true;
// Create offscreen buffer for the once-per-minute face draw // Create offscreen buffer for the once-per-minute face draw
const G1 = Graphics.createArrayBuffer(g.getWidth(), g.getHeight(), 1, {msb:true}); const G1 = Graphics.createArrayBuffer(g.getWidth(), g.getHeight(), 1, {msb:true});
// Precalculate sin/cos for the hour marks. Might be premature // Precalculate sin/cos for the hour marks. Might be premature
// optimisation, but might as well. // optimisation, but might as well.
let ss = [], cs = []; let ss = [], cs = [];
for (let h=1; h<=12; h++) {
const a = Math.PI * h / 6;
ss[h] = Math.sin(a);
cs[h] = Math.cos(a);
}
// Draw the face with hour and minute hand. Ideally, we'd separate
// the face from the hands and double-buffer, but memory is limited,
// so we buffer once and minute, and draw the second hand dynamically
// (with a bit of flicker)
const drawFace = (G) => {
const fw = R1 * 2;
const fh = R1 * 2;
const fw2 = R1;
const fh2 = R1;
let hs = [];
// Wipe the image and start with white
G.clear();
G.setColor(1,1,1);
// Draw the hour marks.
for (let h=1; h<=12; h++) { for (let h=1; h<=12; h++) {
const a = Math.PI * h / 6; hs[h] = HSCALE(h);
ss[h] = Math.sin(a); G.fillRotRect(ss[h], cs[h], CX, CY, -hs[h], hs[h], R2, R1);
cs[h] = Math.cos(a);
} }
// Draw the face with hour and minute hand. Ideally, we'd separate // Draw the hub
// the face from the hands and double-buffer, but memory is limited, G.fillCircle(CX, CY, RC1);
// so we buffer once and minute, and draw the second hand dynamically
// (with a bit of flicker)
const drawFace = (G) => {
const fw = R1 * 2;
const fh = R1 * 2;
const fw2 = R1;
const fh2 = R1;
let hs = [];
// Wipe the image and start with white // Black
G.clear(); G.setColor(0,0,0);
G.setColor(1,1,1);
// Draw the hour marks. // Clear the centre of the hub
for (let h=1; h<=12; h++) { G.fillCircle(CX, CY, RC2);
hs[h] = HSCALE(h);
G.fillRotRect(ss[h], cs[h], CX, CY, -hs[h], hs[h], R2, R1);
} // Draw the gap in the hour marks
for (let h=1; h<=12; h++) {
G.fillRotRect(ss[h], cs[h], CX, CY, -M, M, R2-1, R1+1);
}
// Draw the hub // Back to white for future draw operations
G.fillCircle(CX, CY, RC1); G.setColor(1,1,1);
// Black // While the buffer remains full-screen, we may trim out the
G.setColor(0,0,0); // bottom of the image so we can shift the whole thing down for
// widgets.
const img = {width:GW,height:GH-TM,buffer:G.buffer};
return img;
};
// Clear the centre of the hub let hours, minutes, seconds, date;
G.fillCircle(CX, CY, RC2);
// Draw the gap in the hour marks // Schedule event for calling at the start of the next second
for (let h=1; h<=12; h++) { const inOneSecond = (cb) => {
G.fillRotRect(ss[h], cs[h], CX, CY, -M, M, R2-1, R1+1); let now = new Date();
} clearTimeout();
setTimeout(cb, 1000 - now.getMilliseconds());
};
// Back to white for future draw operations // Schedule event for calling at the start of the next minute
G.setColor(1,1,1); const inOneMinute = (cb) => {
let now = new Date();
clearTimeout();
setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds()));
};
// While the buffer remains full-screen, we may trim out the // Draw a fat hour/minute hand
// bottom of the image so we can shift the whole thing down for const drawHand = (G, a, w2, r1, r2) =>
// widgets. G.fillRotRect(Math.sin(a), Math.cos(a), CX, CY, -w2, w2, r1, r2);
const img = {width:GW,height:GH-TM,buffer:G.buffer};
return img;
};
let hours, minutes, seconds, date; // Redraw function
const drawAll = (force) => {
let now = new Date();
// Schedule event for calling at the start of the next second if (!faceImg) force = true;
const inOneSecond = (cb) => {
let now = new Date();
clearTimeout();
setTimeout(cb, 1000 - now.getMilliseconds());
};
// Schedule event for calling at the start of the next minute let face_changed = force;
const inOneMinute = (cb) => { let date_changed = false;
let now = new Date();
clearTimeout();
setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds()));
};
// Draw a fat hour/minute hand tmp = hours;
const drawHand = (G, a, w2, r1, r2) => hours = now.getHours();
G.fillRotRect(Math.sin(a), Math.cos(a), CX, CY, -w2, w2, r1, r2); if (tmp !== hours)
face_changed = true;
// Redraw function tmp = minutes;
const drawAll = (force) => { minutes = now.getMinutes();
let now = new Date(); if (tmp !== minutes)
face_changed = true;
if (!faceImg) force = true; // If the face has been updated and/or needs a redraw,
// face_changed is true.
let face_changed = force; let time_changed = face_changed;
let date_changed = false;
tmp = hours; // If the screen needs an update, regardless of whether the face
hours = now.getHours(); // needs a redraw, time_changed is true.
if (tmp !== hours)
face_changed = true;
tmp = minutes; if (with_seconds) {
minutes = now.getMinutes(); // If we're going by second, we always need an update.
if (tmp !== minutes) seconds = now.getSeconds();
face_changed = true; time_changed = true;
}
// If the face has been updated and/or needs a redraw, if (with_digital_date) {
// face_changed is true. // See if the date has changed. If it has, then we need a
// full-blown redraw of the screen and the face, plus text.
tmp = date;
date = now.getDate();
if (tmp !== date) {
date_changed = true;
face_changed = true; // Should have changed anyway with hour/minute rollover
}
}
let time_changed = face_changed; if (face_changed) {
// Redraw the face and hands onto the buffer G1.
faceImg = drawFace(G1);
drawHand(G1, Math.PI*hours/6, HW2, RC1, HR);
drawHand(G1, Math.PI*minutes/30, MW2, RC1, MR);
}
// If the screen needs an update, regardless of whether the face // Has the time updated? If so, we'll need to draw something.
// needs a redraw, time_changed is true. if (time_changed) {
if (with_seconds) { // Are we adding text?
// If we're going by second, we always need an update. if (with_digital_date || with_digital_time) {
seconds = now.getSeconds();
time_changed = true; // Construct the date/time text to add above the face
let d = now.toString();
let da = d.toString().split(" ");
let txt;
if (with_digital_time) {
txt = da[4].substr(0, 5);
if (with_digital_date)
G1.drawStringDH(txt+',', 24, 0, 'L', GW);
else
G1.drawStringDH(txt, 0, 0, 'C', GW);
} }
if (with_digital_date) { if (with_digital_date) {
// See if the date has changed. If it has, then we need a let txt = [da[0], da[1], da[2]].join(" ");
// full-blown redraw of the screen and the face, plus text. if (with_digital_time)
tmp = date; G1.drawStringDH(txt, -24, 0, 'R', GW);
date = now.getDate(); else
if (tmp !== date) { G1.drawStringDH(txt, 0, 0, 'C', GW);
date_changed = true;
face_changed = true; // Should have changed anyway with hour/minute rollover
}
} }
}
if (face_changed) { // If the time has updated, we need to _at least_ draw the
// Redraw the face and hands onto the buffer G1. // image to the screen.
faceImg = drawFace(G1); g.setColor(1,1,1);
drawHand(G1, Math.PI*hours/6, HW2, RC1, HR); g.drawImage({width:GW,
drawHand(G1, Math.PI*minutes/30, MW2, RC1, MR); height:GH-TM,
} buffer:G1.buffer}, 0, TM);
// Has the time updated? If so, we'll need to draw something. // and possibly add the second hand
if (time_changed) { if (with_seconds) {
let a = 2.0 * Math.PI * seconds / 60.0;
g.drawRotLine(Math.sin(a), Math.cos(a), CX, CY+TM, RC1, R1);
}
// Are we adding text? // Clock chime on the hour.
if (with_digital_date || with_digital_time) { if (hours >= 0 && minutes === 0)
// Construct the date/time text to add above the face
let d = now.toString();
let da = d.toString().split(" ");
let txt;
if (with_digital_time) {
txt = da[4].substr(0, 5);
if (with_digital_date)
G1.drawStringDH(txt+',', 24, 0, 'L', GW);
else
G1.drawStringDH(txt, 0, 0, 'C', GW);
}
if (with_digital_date) {
let txt = [da[0], da[1], da[2]].join(" ");
if (with_digital_time)
G1.drawStringDH(txt, -24, 0, 'R', GW);
else
G1.drawStringDH(txt, 0, 0, 'C', GW);
}
}
// If the time has updated, we need to _at least_ draw the
// image to the screen.
g.setColor(1,1,1);
g.drawImage({width:GW,
height:GH-TM,
buffer:G1.buffer}, 0, TM);
// and possibly add the second hand
if (with_seconds) {
let a = 2.0 * Math.PI * seconds / 60.0;
g.drawRotLine(Math.sin(a), Math.cos(a), CX, CY+TM, RC1, R1);
}
// Clock chime on the hour.
if (hours >= 0 && minutes === 0)
try {
Bangle.buzz();
} catch (e) { }
// And draw widgets if we're in that mode
if (with_widgets)
Bangle.drawWidgets();
}
// Schedule to repeat this. A `setTimeout(1000)` isn't good
// enough, as all the above might've taken some milliseconds and
// we don't want to drift.
if (with_seconds)
inOneSecond(drawAll);
else
inOneMinute(drawAll);
};
const setButtons = () => {
const opts = { repeat: true, edge:'rising', debounce:30};
// BTN1: enable/disable second hand
setWatch(changeSeconds, BTN1, opts);
// BTN2: return to launcher
setWatch(Bangle.showLauncher, BTN2, { repeat:false, edge:'falling' });
// BTN3: change display mode
setWatch(function () { ++mode; setMode(); drawAll(true); }, BTN3, opts);
};
// Load display parameters based on `mode`
const setMode = () => {
// Normalize mode to 0 <= mode <= 5
mode = (6+mode) % 6;
// [R1, R2, RC1, RC2, HW2, MW3, HR, MR, M, HSCALE] =
const scales = [
[120, 84, 17, 12.4, 4.6, 2.2, 8, 2, 1, h => (3.0 + Math.ceil(h/1.5)) ],
[102, 70, 14.6, 10.7, 3.88, 1.8, 8, 2, 1, h => (2.4 + Math.ceil(h/1.6)) ],
];
if (mode < 3) {
// Face without time/date text. Might have widgets though.
with_digital_time = with_digital_date = false;
with_widgets = (mode == 1);
}
else {
// Face with time/date text, but no widgets
with_digital_time = (mode-2)&1;
with_digital_date = (mode-2)&2;
with_widgets = false;
}
// Destructure the array to the global display parameters
let arr = scales[mode > 0 ? 1 : 0];
R1 = arr[0];
R2 = arr[1];
RC1 = arr[2];
RC2 = arr[3];
HW2 = arr[4];
MW2 = arr[5];
HR = R2 - arr[6];
MR = R1 - arr[7];
M = arr[8];
HSCALE = arr[9];
TM = with_widgets ? 36 : 0;
CX = GW/2;
CY = R1;
// If we're in the small-face + text regime, we're going to buffer
// the full screen but draw the clock face further down to give
// space for the text.
//
// Compare with modes 0 (full-screen) and 1 (with_widgets==true)
// where the face is drawn at the top of the buffer, but drawn
// lower down the screen (so CY doesn't move)
if (mode > 1) {
CY += 36;
}
// We only don't bother redrawing the face from modes 2 to 5, as
// they're the same.
if (!faceImg || mode<3) {
faceImg = undefined;
}
// Store the settings for next time
try { try {
storage.writeJSON(filename, [mode,with_seconds]); Bangle.buzz();
} catch (e) { } catch (e) { }
console.log(e);
}
// Clear the screen: we need to make sure all parts are cleaned off. // And draw widgets if we're in that mode
g.clear(); if (with_widgets)
}; Bangle.drawWidgets();
const changeSeconds = () => {
with_seconds = !with_seconds;
drawAll(true);
};
Bangle.loadWidgets();
// Restore mode
try {
conf = storage.readJSON(filename);
mode = conf[0];
with_seconds = conf[1];
} catch (e) {
console.log(e);
mode = 1;
} }
setButtons(); // Schedule to repeat this. A `setTimeout(1000)` isn't good
setMode(); // enough, as all the above might've taken some milliseconds and
drawAll(); // we don't want to drift.
if (with_seconds)
inOneSecond(drawAll);
else
inOneMinute(drawAll);
};
Bangle.on('lcdPower', (on) => { const setButtons = () => {
if (on) { const opts = { repeat: true, edge:'rising', debounce:30};
Bangle.loadWidgets();
Bangle.drawWidgets(); // BTN1: enable/disable second hand
drawAll(); setWatch(changeSeconds, BTN1, opts);
} else {
clearTimeout(); // BTN2: return to launcher
} setWatch(Bangle.showLauncher, BTN2, { repeat:false, edge:'falling' });
});
// BTN3: change display mode
setWatch(function () { ++mode; setMode(); drawAll(true); }, BTN3, opts);
};
// Load display parameters based on `mode`
const setMode = () => {
// Normalize mode to 0 <= mode <= 5
mode = (6+mode) % 6;
// [R1, R2, RC1, RC2, HW2, MW3, HR, MR, M, HSCALE] =
const scales = [
[120, 84, 17, 12.4, 4.6, 2.2, 8, 2, 1, h => (3.0 + Math.ceil(h/1.5)) ],
[102, 70, 14.6, 10.7, 3.88, 1.8, 8, 2, 1, h => (2.4 + Math.ceil(h/1.6)) ],
];
if (mode < 3) {
// Face without time/date text. Might have widgets though.
with_digital_time = with_digital_date = false;
with_widgets = (mode == 1);
}
else {
// Face with time/date text, but no widgets
with_digital_time = (mode-2)&1;
with_digital_date = (mode-2)&2;
with_widgets = false;
}
// Destructure the array to the global display parameters
let arr = scales[mode > 0 ? 1 : 0];
R1 = arr[0];
R2 = arr[1];
RC1 = arr[2];
RC2 = arr[3];
HW2 = arr[4];
MW2 = arr[5];
HR = R2 - arr[6];
MR = R1 - arr[7];
M = arr[8];
HSCALE = arr[9];
TM = with_widgets ? 36 : 0;
CX = GW/2;
CY = R1;
// If we're in the small-face + text regime, we're going to buffer
// the full screen but draw the clock face further down to give
// space for the text.
//
// Compare with modes 0 (full-screen) and 1 (with_widgets==true)
// where the face is drawn at the top of the buffer, but drawn
// lower down the screen (so CY doesn't move)
if (mode > 1) {
CY += 36;
}
// We only don't bother redrawing the face from modes 2 to 5, as
// they're the same.
if (!faceImg || mode<3) {
faceImg = undefined;
}
// Store the settings for next time
try {
storage.writeJSON(filename, [mode,with_seconds]);
} catch (e) {
console.log(e);
}
// Clear the screen: we need to make sure all parts are cleaned off.
g.clear();
};
const changeSeconds = () => {
with_seconds = !with_seconds;
drawAll(true);
};
Bangle.loadWidgets();
// Restore mode
try {
conf = storage.readJSON(filename);
mode = conf[0];
with_seconds = conf[1];
} catch (e) {
console.log(e);
mode = 1;
}
setButtons();
setMode();
drawAll();
Bangle.on('lcdPower', (on) => {
if (on) {
Bangle.loadWidgets();
Bangle.drawWidgets();
drawAll();
} else {
clearTimeout();
}
});
})(g); })(g);

View File

@ -1 +1,2 @@
0.02: Modified for use with new bootloader and firmware 0.02: Modified for use with new bootloader and firmware
0.03: Shrinked size to avoid cut-off edges on the physical device. BTN3: show date. BTN1: show time in decimal.

10
apps/berlinc/README.md Normal file
View File

@ -0,0 +1,10 @@
# Berlin Clock Watch Face
This is a clock-face analogous to the [Berlin Clock](https://en.wikipedia.org/wiki/Mengenlehreuhr).
## Usage
* BTN1: toggle displaying the time in decimal figures (24 hour format) in the minutes fields. The first two fields are used for the hour and the last two fields for the minute. This might be a help when you're still familarizig yourself with this new way to express the time.
* BTN2: start the launcher
* BTN3: toggle displaying the current date (in ISO 8601 format) below the actual clock-face.

View File

@ -1,58 +1,97 @@
// place your const, vars, functions or classes here // Berlin Clock see https://en.wikipedia.org/wiki/Mengenlehreuhr
fields = [ 4 , 4 , 11 , 4 ]; // https://github.com/eska-muc/BangleApps
width = g.getWidth(); const fields = [4, 4, 11, 4];
height = g.getHeight(); const offset = 20;
rowHeight = height/4; const width = g.getWidth() - 2 * offset;
const height = g.getHeight() - 2 * offset;
const rowHeight = height / 4;
var show_date = false;
var show_time = false;
var yy = 0;
rowlights = []; rowlights = [];
time_digit = [];
function drawBerlinClock() { function drawBerlinClock() {
var now = new Date(); g.clear();
rowlights[0] = Math.floor(now.getHours() / 5); var now = new Date();
rowlights[1] = now.getHours() % 5;
rowlights[2] = Math.floor(now.getMinutes() / 5);
rowlights[3] = now.getMinutes() % 5;
g.clear(); // show date below the clock
if (show_date) {
var yr = now.getFullYear();
var month = now.getMonth() + 1;
var day = now.getDate();
var dateString = `${yr}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`;
var strWidth = g.stringWidth(dateString);
g.setColor(1, 1, 1);
g.setFontAlign(-1,-1);
g.drawString(dateString, ( g.getWidth() - strWidth ) / 2, height + offset + 4);
}
g.drawRect(0,0,width,height); rowlights[0] = Math.floor(now.getHours() / 5);
for (row = 0 ; row < 4 ; row++) { rowlights[1] = now.getHours() % 5;
nfields = fields[row]; rowlights[2] = Math.floor(now.getMinutes() / 5);
boxWidth = width/nfields; rowlights[3] = now.getMinutes() % 5;
for (col = 0 ; col < nfields ; col++) { time_digit[0] = Math.floor(now.getHours() / 10);
x1 = col*boxWidth; time_digit[1] = now.getHours() % 10;
y1 = row*rowHeight; time_digit[2] = Math.floor(now.getMinutes() / 10);
x2 = (col+1)*boxWidth; time_digit[3] = now.getMinutes() % 10;
y2 = (row+1)*rowHeight;
g.setColor(1,1,1); g.drawRect(offset, offset, width + offset, height + offset);
g.drawRect(x1,y1,x2,y2); for (row = 0; row < 4; row++) {
if (col<rowlights[row]) { nfields = fields[row];
boxWidth = width / nfields;
if (row === 2 ) { for (col = 0; col < nfields; col++) {
if (((col+1) % 3) === 0) { x1 = col * boxWidth + offset;
g.setColor(1,0,0); y1 = row * rowHeight + offset;
} else { x2 = (col + 1) * boxWidth + offset;
g.setColor(1,1,0); y2 = (row + 1) * rowHeight + offset;
}
g.setColor(1, 1, 1);
g.drawRect(x1, y1, x2, y2);
if (col < rowlights[row]) {
if (row === 2) {
if (((col + 1) % 3) === 0) {
g.setColor(1, 0, 0);
} else { } else {
g.setColor(1,0,0); g.setColor(1, 1, 0);
} }
} else {
g.fillRect(x1+2,y1+2,x2-2,y2-2); g.setColor(1, 0, 0);
} }
g.fillRect(x1 + 2, y1 + 2, x2 - 2, y2 - 2);
}
if (row == 3 && show_time) {
g.setColor(1,1,1);
g.setFontAlign(0,0);
g.drawString(time_digit[col],(x1+x2)/2,(y1+y2)/2);
} }
} }
}
}
function toggleDate() {
show_date = ! show_date;
drawBerlinClock();
}
function toggleTime() {
show_time = ! show_time;
drawBerlinClock();
} }
// special function to handle display switch on // special function to handle display switch on
Bangle.on('lcdPower', (on) => { Bangle.on('lcdPower', (on) => {
g.clear(); g.clear();
if (on) { if (on) {
Bangle.drawWidgets(); Bangle.drawWidgets();
// call your app function here // call your app function here
drawBerlinClock(); drawBerlinClock();
}}); }
});
// refesh every 15 sec // refesh every 15 sec
setInterval(drawBerlinClock, 15E3); setInterval(drawBerlinClock, 15E3);
@ -61,5 +100,9 @@ g.clear();
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
drawBerlinClock(); drawBerlinClock();
// Toggle date display, when BTN3 is pressed
setWatch(toggleTime,BTN1, { repeat : true, edge: "falling"});
// Toggle date display, when BTN3 is pressed
setWatch(toggleDate,BTN3, { repeat : true, edge: "falling"});
// Show launcher when middle button pressed // Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });

2
apps/binclock/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: New App!
0.02: Fixed bug where screen didn't clear so incorrect time displayed.

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwkEIf4A/AH8AgP/iAECiIJCj/xAgURBoUAn8gAYMP//wAgIMBBwX//4gCAIUAgf/EIUfC5QEBC5MCI4gNCEIPyAgRGDLQMwBIwEJEAYEFAH7v3dQTpDAZ6cDdIYDPdQbpDAZ8QYgTpDAZ5IEAaYAeM4cRTYSuQiABBiQCBbckjmQzFmcggUzGJkBBoMDQgcSkMAAIIXOgL8CC6gvRL4b2CL4MwTIotJAAJfJiIiCC5RfHF4LdHC4wvGAwIvHL5UDYQIuBF44A/AH4A/AH4AbA"))

178
apps/binclock/app.js Normal file
View File

@ -0,0 +1,178 @@
// Load fonts
require("Font7x11Numeric7Seg").add(Graphics);
// position on screen
const X = 160, Y = 180;
var displayTime = 0;
var minuteLED = [0,0,0,0,0,0];
var hourLED = [0,0,0,0,0];
var prevMinute = [0,0,0,0,0,0];
var prevHour = [0,0,0,0,0];
function drawTime(d) {
// work out how to display the current time
var h = d.getHours(), m = d.getMinutes();
var time = (" "+h).substr(-2) + ":" + ("0"+m).substr(-2);
// draw the current time (4x size 7 segment)
g.setFont("7x11Numeric7Seg",4);
g.setFontAlign(1,1); // align right bottom
g.drawString(time, X, Y, true /*clear background*/);
// draw the seconds (2x size 7 segment)
g.setFont("7x11Numeric7Seg",2);
g.drawString(("0"+d.getSeconds()).substr(-2), X+30, Y, true /*clear background*/);
}
function updateHourArray(hours){
var j;
for(j=0;j<hourLED.length;j++){
prevHour[j] = hourLED[j];
}
var i;
for(i = 0;i < hourLED.length;i++){
hourLED[i]=0;
}
if(hours > 15){
hourLED[0] = 1;
hours = hours - 16;
}
if(hours > 7){
hourLED[1] = 1;
hours = hours - 8;
}
if(hours > 3){
hourLED[2] = 1;
hours = hours - 4;
}
if(hours > 1){
hourLED[3] = 1;
hours = hours - 2;
}
if(hours > 0){
hourLED[4] = 1;
}
return hourLED;
}
function updateMinuteArray(minutes){
var j;
for(j=0;j<minuteLED.length;j++){
prevMinute[j] = minuteLED[j];
}
var i;
for(i = 0;i < minuteLED.length;i++){
minuteLED[i]=0;
}
if(minutes > 31){
minuteLED[0] = 1;
minutes = minutes - 32;
}
if(minutes > 15){
minuteLED[1] = 1;
minutes = minutes - 16;
}
if(minutes > 7){
minuteLED[2] = 1;
minutes = minutes - 8;
}
if(minutes > 3){
minuteLED[3] = 1;
minutes = minutes - 4;
}
if(minutes > 1){
minuteLED[4] = 1;
minutes = minutes - 2;
}
if(minutes > 0){
minuteLED[5] = 1;
}
return minuteLED;
}
function draw(){
// work out how to display the current time
var d = new Date();
var h = d.getHours(), m = d.getMinutes();
updateHourArray(h);
updateMinuteArray(m);
var i;
//Draw hour circles
for(i=0; i<hourLED.length; i++){
if(prevHour[i] == hourLED[i]){
if(hourLED[i] == 1){
g.fillCircle(24+i*48,50,10);
} else {
var colour = g.getColor();
g.setColor(0,0,0);
g.fillCircle(24+i*48,50,10);
g.setColor(colour);
g.drawCircle(24+i*48,50,10);
}
}
}
for(i=0; i<minuteLED.length; i++){
if(prevMinute[i] == minuteLED[i]){
if(minuteLED[i] == 1){
g.fillCircle(20+i*40,100,10);
} else {
var colour = g.getColor();
g.setColor(0,0,0);
g.fillCircle(20+i*40,100,10);
g.setColor(colour);
g.drawCircle(20+i*40,100,10);
}
}
}
// draw the date, in a normal font
g.setFont("6x8");
g.setFontAlign(0,1); // align center bottom
// pad the date - this clears the background if the date were to change length
var dateStr = " "+require("locale").date(d)+" ";
g.drawString(dateStr, g.getWidth()/2, 130, true /*clear background*/);
if(displayTime){
drawTime(d);
}else{
g.clearRect(0,240,240,130);
}
}
// Clear the screen once, at startup
g.clear();
// draw immediately at first
draw();
var secondInterval = setInterval(draw, 1000);
// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower',on=>{
if (secondInterval) clearInterval(secondInterval);
secondInterval = undefined;
if (on) {
setInterval(draw, 1000);
draw(); // draw immediately
}
});
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
// Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });
setWatch(function() {
if(displayTime == 0){
displayTime = 1;
} else{
displayTime = 0;
}
}, BTN, {edge:"rising", debounce:50, repeat:true});

BIN
apps/binclock/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

View File

@ -1,18 +1,18 @@
const Clubs = { width : 48, height : 48, bpp : 1, const Clubs = { width : 48, height : 48, bpp : 1,
buffer : require("heatshrink").decompress(atob("ACcP+AFDn/8Aod//wFD///AgUBAoOAApsDAoPAAr4vLI4pTEgP8L4M/wEH/5rB//gh//x/x//wj//9/3//4n4iBAAIZBAol/Aof+Apv5z4FP+OPAo41BAoX8I4Pj45HBAoPD4YFBLIOD4JZBRAMD4CKC/AFBj59Cg/gQYYFXAB4=")) buffer : require("heatshrink").decompress(atob("ACcP+AFDn/8Aod//wFD///AgUBAoOAApsDAoPAAr4vLI4pTEgP8L4M/wEH/5rB//gh//x/x//wj//9/3//4n4iBAAIZBAol/Aof+Apv5z4FP+OPAo41BAoX8I4Pj45HBAoPD4YFBLIOD4JZBRAMD4CKC/AFBj59Cg/gQYYFXAB4="))
}; };
const Spades = { width : 48, height : 48, bpp : 1, const Spades = { width : 48, height : 48, bpp : 1,
buffer : require("heatshrink").decompress(atob("ABsBwAFDgfAAocH8AFDh/wAocf/AFDn/8Aod//wFD///FwYFBGAUDAoIwCg4FBGAUPAoIwCj4FBGAU/AoIwCv4FBGAQEBGAQuCGAQuCGAQFLHQQ8CAupHLL4prB+fPTgU/8fHVwbLLApbXFbpYFLdIoADA==")) buffer : require("heatshrink").decompress(atob("ABsBwAFDgfAAocH8AFDh/wAocf/AFDn/8Aod//wFD///FwYFBGAUDAoIwCg4FBGAUPAoIwCj4FBGAU/AoIwCv4FBGAQEBGAQuCGAQuCGAQFLHQQ8CAupHLL4prB+fPTgU/8fHVwbLLApbXFbpYFLdIoADA=="))
}; };
const Hearts = { width : 48, height : 48, bpp : 4, const Hearts = { width : 48, height : 48, bpp : 4,
buffer : require("heatshrink").decompress(atob("ADlVqtQBQ8FBYIKIrnMAAINGqoKC4okGCwYAB4AKDhgKE4oWKAAILDBQwYEBYwwDFwojFgoLHEgQ6H5hhCBZAkCBRAjLEgI6IC4YLIC5Y7BBZXBjgjVABYX/C8CnKABbXLABTvMC8sMC6fAC4KQURwIABRypgULwRgULwRIUCwhIRIwiRSRoZITCwx5POoowRCxAwNFxIwNCxQwLFxYwLCxgwJFxowJCxwwHFx4wHCyAwFFyIwFCyQwDFycAgoXBqAXTgFc4oWUJAJGUJARGVAEo")) buffer : require("heatshrink").decompress(atob("ADlVqtQBQ8FBYIKIrnMAAINGqoKC4okGCwYAB4AKDhgKE4oWKAAILDBQwYEBYwwDFwojFgoLHEgQ6H5hhCBZAkCBRAjLEgI6IC4YLIC5Y7BBZXBjgjVABYX/C8CnKABbXLABTvMC8sMC6fAC4KQURwIABRypgULwRgULwRIUCwhIRIwiRSRoZITCwx5POoowRCxAwNFxIwNCxQwLFxYwLCxgwJFxowJCxwwHFx4wHCyAwFFyIwFCyQwDFycAgoXBqAXTgFc4oWUJAJGUJARGVAEo"))
}; };
const Diamonds = { width : 48, height : 48, bpp : 4, const Diamonds = { width : 48, height : 48, bpp : 4,
buffer : require("heatshrink").decompress(atob("AHUFC60M4AXV5nFIyvM5hGVC4JIUCwJIUIwRIUIwRIUCwZISIwgABqBGUJCQWFPKBGGJCFcC455OCw4wOOox5QIxB5NOpBIOFxZ5LCxYwKOpQwMIxh5KOxipLL6xgNR5QwMX5TvXPJZ1JJBpGLPJR1LJBZGNPJIWOJA5GOPJB1NJBIWQPIpGRJApGRPIoWSJAa8PJA5GTJAYWUJAJGVAAJGVAHo=")) buffer : require("heatshrink").decompress(atob("AHUFC60M4AXV5nFIyvM5hGVC4JIUCwJIUIwRIUIwRIUCwZISIwgABqBGUJCQWFPKBGGJCFcC455OCw4wOOox5QIxB5NOpBIOFxZ5LCxYwKOpQwMIxh5KOxipLL6xgNR5QwMX5TvXPJZ1JJBpGLPJR1LJBZGNPJIWOJA5GOPJB1NJBIWQPIpGRJApGRPIoWSJAa8PJA5GTJAYWUJAJGVAAJGVAHo="))
}; };
var deck = []; var deck = [];
@ -20,168 +20,168 @@ var player = {Hand:[]};
var computer = {Hand:[]}; var computer = {Hand:[]};
function createDeck() { function createDeck() {
var suits = ["Spades", "Hearts", "Diamonds", "Clubs"]; var suits = ["Spades", "Hearts", "Diamonds", "Clubs"];
var values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]; var values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];
var dck = []; var dck = [];
for (var i = 0 ; i < values.length; i++) { for (var i = 0 ; i < values.length; i++) {
for(var x = 0; x < suits.length; x++) { for(var x = 0; x < suits.length; x++) {
dck.push({ Value: values[i], Suit: suits[x] }); dck.push({ Value: values[i], Suit: suits[x] });
}
} }
return dck; }
return dck;
} }
function shuffle(a) { function shuffle(a) {
var j, x, i; var j, x, i;
for (i = a.length - 1; i > 0; i--) { for (i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1)); j = Math.floor(Math.random() * (i + 1));
x = a[i]; x = a[i];
a[i] = a[j]; a[i] = a[j];
a[j] = x; a[j] = x;
} }
return a; return a;
} }
function EndGameMessdage(msg){ function EndGameMessdage(msg){
g.drawString(msg, 155, 200); g.drawString(msg, 155, 200);
setTimeout(function(){ setTimeout(function(){
startGame(); startGame();
}, 2500); }, 2500);
} }
function hitMe() { function hitMe() {
player.Hand.push(deck.pop()); player.Hand.push(deck.pop());
renderOnScreen(1); renderOnScreen(1);
var playerWeight = calcWeight(player.Hand, 0); var playerWeight = calcWeight(player.Hand, 0);
if(playerWeight == 21) if(playerWeight == 21)
EndGameMessdage('WINNER'); EndGameMessdage('WINNER');
else if(playerWeight > 21) else if(playerWeight > 21)
EndGameMessdage('LOOSER'); EndGameMessdage('LOOSER');
} }
function calcWeight(hand, hideCard) { function calcWeight(hand, hideCard) {
if(hideCard === 1) { if(hideCard === 1) {
if (hand[0].Value == "J" || hand[0].Value == "Q" || hand[0].Value == "K") if (hand[0].Value == "J" || hand[0].Value == "Q" || hand[0].Value == "K")
return "10 +"; return "10 +";
else if (hand[0].Value == "A") else if (hand[0].Value == "A")
return "11 +"; return "11 +";
else else
return parseInt(hand[0].Value) +" +"; return parseInt(hand[0].Value) +" +";
}
else {
var weight = 0;
for(i=0; i<hand.length; i++){
if (hand[i].Value == "J" || hand[i].Value == "Q" || hand[i].Value == "K") {
weight += 10;
}
else if (hand[i].Value == "A") {
weight += 1;
}
else
weight += parseInt(hand[i].Value);
} }
else {
var weight = 0;
for(i=0; i<hand.length; i++){
if (hand[i].Value == "J" || hand[i].Value == "Q" || hand[i].Value == "K") {
weight += 10;
}
else if (hand[i].Value == "A") {
weight += 1;
}
else
weight += parseInt(hand[i].Value);
}
// Find count of aces because it may be 11 or 1 // Find count of aces because it may be 11 or 1
var numOfAces = hand.filter(function(x){ return x.Value === "A"; }).length; var numOfAces = hand.filter(function(x){ return x.Value === "A"; }).length;
for (var j = 0; j < numOfAces; j++) { for (var j = 0; j < numOfAces; j++) {
if (weight + 10 <= 21) { if (weight + 10 <= 21) {
weight +=10; weight +=10;
} }
}
return weight;
} }
return weight;
}
} }
function stand(){ function stand(){
function sleepFor( sleepDuration ){ function sleepFor( sleepDuration ){
console.log("Sleeping..."); console.log("Sleeping...");
var now = new Date().getTime(); var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ /* do nothing */ } while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
} }
renderOnScreen(0);
var playerWeight = calcWeight(player.Hand, 0);
var bangleWeight = calcWeight(computer.Hand, 0);
while(bangleWeight<17){
sleepFor(500);
computer.Hand.push(deck.pop());
renderOnScreen(0); renderOnScreen(0);
var playerWeight = calcWeight(player.Hand, 0); bangleWeight = calcWeight(computer.Hand, 0);
var bangleWeight = calcWeight(computer.Hand, 0); }
while(bangleWeight<17){ if (bangleWeight == playerWeight)
sleepFor(500); EndGameMessdage('TIES');
computer.Hand.push(deck.pop()); else if(playerWeight==21 || bangleWeight > 21 || bangleWeight < playerWeight)
renderOnScreen(0); EndGameMessdage('WINNER');
bangleWeight = calcWeight(computer.Hand, 0); else if(bangleWeight > playerWeight)
} EndGameMessdage('LOOSER');
if (bangleWeight == playerWeight)
EndGameMessdage('TIES');
else if(playerWeight==21 || bangleWeight > 21 || bangleWeight < playerWeight)
EndGameMessdage('WINNER');
else if(bangleWeight > playerWeight)
EndGameMessdage('LOOSER');
} }
function renderOnScreen(HideCard) { function renderOnScreen(HideCard) {
const fontName = "6x8"; const fontName = "6x8";
g.clear(); // clear screen g.clear(); // clear screen
g.reset(); // default draw styles g.reset(); // default draw styles
g.setFont(fontName, 1); g.setFont(fontName, 1);
g.drawString('RST', 220, 35); g.drawString('RST', 220, 35);
g.drawString('Hit', 60, 230); g.drawString('Hit', 60, 230);
g.drawString('Stand', 165, 230); g.drawString('Stand', 165, 230);
g.setFont(fontName, 3); g.setFont(fontName, 3);
for(i=0; i<computer.Hand.length; i++){ for(i=0; i<computer.Hand.length; i++){
g.drawImage(eval(computer.Hand[i].Suit), i*48, 10); g.drawImage(eval(computer.Hand[i].Suit), i*48, 10);
if(i == 1 && HideCard == 1) if(i == 1 && HideCard == 1)
g.drawString("?", i*48+18, 58); g.drawString("?", i*48+18, 58);
else else
g.drawString(computer.Hand[i].Value, i*48+18, 58); g.drawString(computer.Hand[i].Value, i*48+18, 58);
} }
g.setFont(fontName, 2); g.setFont(fontName, 2);
g.drawString('BangleJS has '+ calcWeight(computer.Hand, HideCard), 5, 85); g.drawString('BangleJS has '+ calcWeight(computer.Hand, HideCard), 5, 85);
g.setFont(fontName, 3); g.setFont(fontName, 3);
for(i=0; i<player.Hand.length; i++){ for(i=0; i<player.Hand.length; i++){
g.drawImage(eval(player.Hand[i].Suit), i*48, 125); g.drawImage(eval(player.Hand[i].Suit), i*48, 125);
g.drawString(player.Hand[i].Value, i*48+18, 175); g.drawString(player.Hand[i].Value, i*48+18, 175);
} }
g.setFont(fontName, 2); g.setFont(fontName, 2);
g.drawString('You have ' + calcWeight(player.Hand, 0), 5, 202); g.drawString('You have ' + calcWeight(player.Hand, 0), 5, 202);
} }
function dealHands() { function dealHands() {
player.Hand= []; player.Hand= [];
computer.Hand= []; computer.Hand= [];
setTimeout(function(){ setTimeout(function(){
player.Hand.push(deck.pop()); player.Hand.push(deck.pop());
renderOnScreen(0); renderOnScreen(0);
}, 500); }, 500);
setTimeout(function(){ setTimeout(function(){
computer.Hand.push(deck.pop()); computer.Hand.push(deck.pop());
renderOnScreen(1); renderOnScreen(1);
}, 1000); }, 1000);
setTimeout(function(){ setTimeout(function(){
player.Hand.push(deck.pop()); player.Hand.push(deck.pop());
renderOnScreen(1); renderOnScreen(1);
}, 1500); }, 1500);
setTimeout(function(){ setTimeout(function(){
computer.Hand.push(deck.pop()); computer.Hand.push(deck.pop());
renderOnScreen(1); renderOnScreen(1);
}, 2000); }, 2000);
} }
function startGame(){ function startGame(){
deck = createDeck(); deck = createDeck();
deck = shuffle(deck); deck = shuffle(deck);
dealHands(); dealHands();
} }
setWatch(hitMe, BTN4, {repeat:true, edge:"falling"}); setWatch(hitMe, BTN4, {repeat:true, edge:"falling"});

View File

@ -37,16 +37,16 @@ function scan() {
waitMessage(); waitMessage();
NRF.findDevices(devices => { NRF.findDevices(devices => {
devices.forEach(device =>{ devices.forEach(device =>{
let deviceName = device.id.substring(0,17); let deviceName = device.id.substring(0,17);
if (device.name) { if (device.name) {
deviceName = device.name; deviceName = device.name;
} }
menu[deviceName] = () => showDeviceInfo(device); menu[deviceName] = () => showDeviceInfo(device);
}); });
showMainMenu(menu); showMainMenu(menu);
}, { active: true }); }, { active: true });
} }

View File

@ -22,22 +22,22 @@ function draw() {
function scan() { function scan() {
NRF.findDevices(devices => { NRF.findDevices(devices => {
for (let device of devices) { for (let device of devices) {
// Only display devices that advertise a name // Only display devices that advertise a name
if (device.name) { if (device.name) {
// Remove no devices found message if it is present // Remove no devices found message if it is present
if (menu[NODEVICE]) { if (menu[NODEVICE]) {
delete menu[NODEVICE]; delete menu[NODEVICE];
}
menu[device.name] = {
value : device.rssi,
onchange : () => {}
};
} }
menu[device.name] = {
value : device.rssi,
onchange : () => {}
};
} }
draw(); }
draw();
}, { active: true }); }, { active: true });
} }

View File

@ -1,103 +1,103 @@
const buf = Graphics.createArrayBuffer(144,200,1,{msb:true}); const buf = Graphics.createArrayBuffer(144,200,1,{msb:true});
const NUMBERS = [ const NUMBERS = [
[1,1,1,1,3,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],//0 [1,1,1,1,3,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],//0
[0,1,1,1,3,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1],//1 [0,1,1,1,3,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1],//1
[1,1,1,1,3,0,0,1,1,1,2,1,1,1,4,1,1,1,0,0,1,1,1,1,1],//2 [1,1,1,1,3,0,0,1,1,1,2,1,1,1,4,1,1,1,0,0,1,1,1,1,1],//2
[1,1,1,1,3,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],//3 [1,1,1,1,3,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],//3
[1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,5,1,1,1,1,0,0,1,1,1],//4 [1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,5,1,1,1,1,0,0,1,1,1],//4
[1,1,1,1,1,1,1,1,0,0,5,1,1,1,3,0,0,1,1,1,1,1,1,1,1],//5 [1,1,1,1,1,1,1,1,0,0,5,1,1,1,3,0,0,1,1,1,1,1,1,1,1],//5
[1,1,1,1,1,1,1,1,0,0,1,1,1,1,3,1,1,0,1,1,1,1,1,1,1],//6 [1,1,1,1,1,1,1,1,0,0,1,1,1,1,3,1,1,0,1,1,1,1,1,1,1],//6
[1,1,1,1,3,0,0,1,1,1,0,2,1,1,1,0,1,1,1,0,0,1,1,1,0],//7 [1,1,1,1,3,0,0,1,1,1,0,2,1,1,1,0,1,1,1,0,0,1,1,1,0],//7
[1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1],//8 [1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1],//8
[1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1] //9 [1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1] //9
]; ];
let intervalRef = null; let intervalRef = null;
let digits = [-1,-1,-1,-1,-1,-1]; let digits = [-1,-1,-1,-1,-1,-1];
function flip() { function flip() {
g.setColor(1,1,1); g.setColor(1,1,1);
g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26); g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26);
} }
function drawPixel(ox,oy,x,y,r,p) { function drawPixel(ox,oy,x,y,r,p) {
let x1 = ox+x*(r*2+1); let x1 = ox+x*(r*2+1);
let y1 = oy+y*(r*2+1); let y1 = oy+y*(r*2+1);
let xmid = x1+r; let xmid = x1+r;
let ymid = y1+r; let ymid = y1+r;
let x2 = xmid+r; let x2 = xmid+r;
let y2 = ymid+r; let y2 = ymid+r;
if (p > 0) { if (p > 0) {
if (p > 1) { if (p > 1) {
buf.setColor(0,0,0); buf.setColor(0,0,0);
buf.fillRect(x1,y1,x2,y2); buf.fillRect(x1,y1,x2,y2);
}
buf.setColor(1,1,1);
} else {
buf.setColor(0,0,0);
}
if (p < 2) {
buf.fillRect(x1,y1,x2,y2);
} else if (p === 2) {
buf.fillPoly([xmid,y1,x2,y1,x2,y2,x1,y2,x1,ymid]);
} else if (p === 3) {
buf.fillPoly([x1,y1,xmid,y1,x2,ymid,x2,y2,x1,y2]);
} else if (p === 4) {
buf.fillPoly([x1,y1,x2,y1,x2,ymid,xmid,y2,x1,y2]);
} else if (p === 5) {
buf.fillPoly([x1,y1,x2,y1,x2,y2,xmid,y2,x1,ymid]);
} }
buf.setColor(1,1,1);
} else {
buf.setColor(0,0,0);
}
if (p < 2) {
buf.fillRect(x1,y1,x2,y2);
} else if (p === 2) {
buf.fillPoly([xmid,y1,x2,y1,x2,y2,x1,y2,x1,ymid]);
} else if (p === 3) {
buf.fillPoly([x1,y1,xmid,y1,x2,ymid,x2,y2,x1,y2]);
} else if (p === 4) {
buf.fillPoly([x1,y1,x2,y1,x2,ymid,xmid,y2,x1,y2]);
} else if (p === 5) {
buf.fillPoly([x1,y1,x2,y1,x2,y2,xmid,y2,x1,ymid]);
}
} }
function redraw() { function redraw() {
let time = new Date(); let time = new Date();
let hours = time.getHours(); let hours = time.getHours();
let mins = time.getMinutes(); let mins = time.getMinutes();
let secs = time.getSeconds(); let secs = time.getSeconds();
let newDigits = [Math.floor(hours/10),hours%10,Math.floor(mins/10),mins%10,Math.floor(secs/10),secs%10]; let newDigits = [Math.floor(hours/10),hours%10,Math.floor(mins/10),mins%10,Math.floor(secs/10),secs%10];
for (var p = 0;p<25;p++) { for (var p = 0;p<25;p++) {
var px = p%5; var px = p%5;
var py = Math.floor(p/5); var py = Math.floor(p/5);
if (digits[0] === -1 || NUMBERS[newDigits[0]][p] !== NUMBERS[digits[0]][p] ) { if (digits[0] === -1 || NUMBERS[newDigits[0]][p] !== NUMBERS[digits[0]][p] ) {
drawPixel(0,20,px,py,6,NUMBERS[newDigits[0]][p]); drawPixel(0,20,px,py,6,NUMBERS[newDigits[0]][p]);
}
if (digits[1] === -1 || NUMBERS[newDigits[1]][p] !== NUMBERS[digits[1]][p] ) {
drawPixel(78,20,px,py,6,NUMBERS[newDigits[1]][p]);
}
if (digits[2] === -1 || NUMBERS[newDigits[2]][p] !== NUMBERS[digits[2]][p] ) {
drawPixel(0,92,px,py,6,NUMBERS[newDigits[2]][p]);
}
if (digits[3] === -1 || NUMBERS[newDigits[3]][p] !== NUMBERS[digits[3]][p] ) {
drawPixel(78,92,px,py,6,NUMBERS[newDigits[3]][p]);
}
if (digits[4] === -1 || NUMBERS[newDigits[4]][p] !== NUMBERS[digits[4]][p] ) {
drawPixel(69,164,px,py,3,NUMBERS[newDigits[4]][p]);
}
if (digits[5] === -1 || NUMBERS[newDigits[5]][p] !== NUMBERS[digits[5]][p] ) {
drawPixel(108,164,px,py,3,NUMBERS[newDigits[5]][p]);
}
} }
digits = newDigits; if (digits[1] === -1 || NUMBERS[newDigits[1]][p] !== NUMBERS[digits[1]][p] ) {
flip(); drawPixel(78,20,px,py,6,NUMBERS[newDigits[1]][p]);
}
if (digits[2] === -1 || NUMBERS[newDigits[2]][p] !== NUMBERS[digits[2]][p] ) {
drawPixel(0,92,px,py,6,NUMBERS[newDigits[2]][p]);
}
if (digits[3] === -1 || NUMBERS[newDigits[3]][p] !== NUMBERS[digits[3]][p] ) {
drawPixel(78,92,px,py,6,NUMBERS[newDigits[3]][p]);
}
if (digits[4] === -1 || NUMBERS[newDigits[4]][p] !== NUMBERS[digits[4]][p] ) {
drawPixel(69,164,px,py,3,NUMBERS[newDigits[4]][p]);
}
if (digits[5] === -1 || NUMBERS[newDigits[5]][p] !== NUMBERS[digits[5]][p] ) {
drawPixel(108,164,px,py,3,NUMBERS[newDigits[5]][p]);
}
}
digits = newDigits;
flip();
} }
function clearTimers() { function clearTimers() {
if(intervalRef) { if(intervalRef) {
clearInterval(intervalRef); clearInterval(intervalRef);
intervalRef = undefined; intervalRef = undefined;
} }
} }
function startTimers() { function startTimers() {
g.clear(); g.clear();
Bangle.drawWidgets(); Bangle.drawWidgets();
intervalRef = setInterval(redraw,1000); intervalRef = setInterval(redraw,1000);
redraw(); redraw();
} }
Bangle.loadWidgets(); Bangle.loadWidgets();
startTimers(); startTimers();
Bangle.on('lcdPower',function(on) { Bangle.on('lcdPower',function(on) {
if (on) { if (on) {
startTimers(); startTimers();
} else { } else {
clearTimers(); clearTimers();
} }
}); });
// Show launcher when middle button pressed // Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});

View File

@ -1,12 +1,12 @@
var hour_hand = { var hour_hand = {
width : 61, height : 8, bpp : 1, width : 61, height : 8, bpp : 1,
transparent : 0, transparent : 0,
buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////////////w==")) buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////////////w=="))
}; };
var minute_hand = { var minute_hand = {
width : 110, height : 4, bpp : 1, width : 110, height : 4, bpp : 1,
transparent : 0, transparent : 0,
buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////w==")) buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////w=="))
}; };
//g.fillRect(0,24,239,239); // Apps area //g.fillRect(0,24,239,239); // Apps area
@ -24,117 +24,117 @@ let tick1 = Graphics.createArrayBuffer(8,4,1);
tick1.fillRect(0,0,tick1.getWidth()-1, tick1.getHeight()-1); tick1.fillRect(0,0,tick1.getWidth()-1, tick1.getHeight()-1);
function big_wheel_x(angle){ function big_wheel_x(angle){
return clock_center.x + radius * Math.cos(angle*p180); return clock_center.x + radius * Math.cos(angle*p180);
} }
function big_wheel_y(angle){ function big_wheel_y(angle){
return clock_center.y + radius * Math.sin(angle*p180); return clock_center.y + radius * Math.sin(angle*p180);
} }
function rotate_around_x(center_x, angle, tick){ function rotate_around_x(center_x, angle, tick){
return center_x + Math.cos(angle*p180) * tick.getWidth()/2; return center_x + Math.cos(angle*p180) * tick.getWidth()/2;
} }
function rotate_around_y(center_y, angle, tick){ function rotate_around_y(center_y, angle, tick){
return center_y + Math.sin(angle*p180) * tick.getWidth()/2; return center_y + Math.sin(angle*p180) * tick.getWidth()/2;
} }
function hour_pos_x(angle){ function hour_pos_x(angle){
return clock_center.x + Math.cos(angle*p180) * hour_hand.width/2; return clock_center.x + Math.cos(angle*p180) * hour_hand.width/2;
} }
function hour_pos_y(angle){ function hour_pos_y(angle){
return clock_center.y + Math.sin(angle*p180) * hour_hand.width/2; return clock_center.y + Math.sin(angle*p180) * hour_hand.width/2;
} }
function minute_pos_x(angle){ function minute_pos_x(angle){
return clock_center.x + Math.cos(angle*p180) * minute_hand.width/2; return clock_center.x + Math.cos(angle*p180) * minute_hand.width/2;
} }
function minute_pos_y(angle){ function minute_pos_y(angle){
return clock_center.y + Math.sin(angle*p180) * minute_hand.width/2; return clock_center.y + Math.sin(angle*p180) * minute_hand.width/2;
} }
function minute_angle(date){ function minute_angle(date){
//let minutes = date.getMinutes() + date.getSeconds()/60; //let minutes = date.getMinutes() + date.getSeconds()/60;
let minutes = date.getMinutes(); let minutes = date.getMinutes();
return 6*minutes - 90; return 6*minutes - 90;
} }
function hour_angle(date){ function hour_angle(date){
let hours= date.getHours() + date.getMinutes()/60; let hours= date.getHours() + date.getMinutes()/60;
return 30*hours - 90; return 30*hours - 90;
} }
function draw_clock(){ function draw_clock(){
//console.log("draw_clock"); //console.log("draw_clock");
let date = new Date(); let date = new Date();
//g.clear(); //g.clear();
g.setBgColor(0,0,0); g.setBgColor(0,0,0);
g.setColor(0,0,0); g.setColor(0,0,0);
g.fillRect(0,24,239,239); // clear app area g.fillRect(0,24,239,239); // clear app area
g.setColor(1,1,1); g.setColor(1,1,1);
// draw cross lines for testing // draw cross lines for testing
// g.setColor(1,0,0); // g.setColor(1,0,0);
// g.drawLine(clock_center.x - radius, clock_center.y, clock_center.x + radius, clock_center.y); // g.drawLine(clock_center.x - radius, clock_center.y, clock_center.x + radius, clock_center.y);
// g.drawLine(clock_center.x, clock_center.y - radius, clock_center.x, clock_center.y + radius); // g.drawLine(clock_center.x, clock_center.y - radius, clock_center.x, clock_center.y + radius);
g.setColor(1,1,1); g.setColor(1,1,1);
let ticks = [0, 90, 180, 270]; let ticks = [0, 90, 180, 270];
ticks.forEach((item)=>{ ticks.forEach((item)=>{
let agl = item+180; let agl = item+180;
g.drawImage(tick0.asImage(), rotate_around_x(big_wheel_x(item), agl, tick0), rotate_around_y(big_wheel_y(item), agl, tick0), {rotate:agl*p180}); g.drawImage(tick0.asImage(), rotate_around_x(big_wheel_x(item), agl, tick0), rotate_around_y(big_wheel_y(item), agl, tick0), {rotate:agl*p180});
}); });
ticks = [30, 60, 120, 150, 210, 240, 300, 330]; ticks = [30, 60, 120, 150, 210, 240, 300, 330];
ticks.forEach((item)=>{ ticks.forEach((item)=>{
let agl = item+180; let agl = item+180;
g.drawImage(tick5.asImage(), rotate_around_x(big_wheel_x(item), agl, tick5), rotate_around_y(big_wheel_y(item), agl, tick5), {rotate:agl*p180}); g.drawImage(tick5.asImage(), rotate_around_x(big_wheel_x(item), agl, tick5), rotate_around_y(big_wheel_y(item), agl, tick5), {rotate:agl*p180});
}); });
let hour_agl = hour_angle(date); let hour_agl = hour_angle(date);
let minute_agl = minute_angle(date); let minute_agl = minute_angle(date);
g.drawImage(hour_hand, hour_pos_x(hour_agl), hour_pos_y(hour_agl), {rotate:hour_agl*p180}); // g.drawImage(hour_hand, hour_pos_x(hour_agl), hour_pos_y(hour_agl), {rotate:hour_agl*p180}); //
g.drawImage(minute_hand, minute_pos_x(minute_agl), minute_pos_y(minute_agl), {rotate:minute_agl*p180}); // g.drawImage(minute_hand, minute_pos_x(minute_agl), minute_pos_y(minute_agl), {rotate:minute_agl*p180}); //
g.setColor(1,1,1); g.setColor(1,1,1);
g.fillCircle(clock_center.x, clock_center.y, 6); g.fillCircle(clock_center.x, clock_center.y, 6);
g.setColor(0,0,0); g.setColor(0,0,0);
g.fillCircle(clock_center.x, clock_center.y, 3); g.fillCircle(clock_center.x, clock_center.y, 3);
// draw minute ticks. Takes long time to draw! // draw minute ticks. Takes long time to draw!
g.setColor(1,1,1); g.setColor(1,1,1);
for (var i=0; i<60; i++){ for (var i=0; i<60; i++){
let agl = i*6+180; let agl = i*6+180;
g.drawImage(tick1.asImage(), rotate_around_x(big_wheel_x(i*6), agl, tick1), rotate_around_y(big_wheel_y(i*6), agl, tick1), {rotate:agl*p180}); g.drawImage(tick1.asImage(), rotate_around_x(big_wheel_x(i*6), agl, tick1), rotate_around_y(big_wheel_y(i*6), agl, tick1), {rotate:agl*p180});
} }
g.flip(); g.flip();
//console.log(date); //console.log(date);
} }
function clearTimers(){ function clearTimers(){
//console.log("clearTimers"); //console.log("clearTimers");
if(intervalRef) { if(intervalRef) {
clearInterval(intervalRef); clearInterval(intervalRef);
intervalRef = null; intervalRef = null;
//console.log("interval is cleared"); //console.log("interval is cleared");
} }
} }
function startTimers(){ function startTimers(){
//console.log("startTimers"); //console.log("startTimers");
if(intervalRef) clearTimers(); if(intervalRef) clearTimers();
intervalRef = setInterval(draw_clock, 60*1000); intervalRef = setInterval(draw_clock, 60*1000);
//console.log("interval is set"); //console.log("interval is set");
draw_clock(); draw_clock();
} }
Bangle.on('lcdPower', (on) => { Bangle.on('lcdPower', (on) => {
if (on) { if (on) {
//console.log("lcdPower: on"); //console.log("lcdPower: on");
Bangle.drawWidgets(); Bangle.drawWidgets();
startTimers(); startTimers();
} else { } else {
//console.log("lcdPower: off"); //console.log("lcdPower: off");
clearTimers(); clearTimers();
} }
}); });
Bangle.on('faceUp',function(up){ Bangle.on('faceUp',function(up){
//console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn());
if (up && !Bangle.isLCDOn()) { if (up && !Bangle.isLCDOn()) {
//console.log("faceUp and LCD off"); //console.log("faceUp and LCD off");
clearTimers(); clearTimers();
Bangle.setLCDPower(true); Bangle.setLCDPower(true);
} }
}); });
g.clear(); g.clear();

View File

@ -15,7 +15,8 @@
"rules": { "rules": {
"indent": [ "indent": [
"error", "error",
2 2,
{ "SwitchCase": 1 }
], ],
"linebreak-style": [ "linebreak-style": [
"error", "error",
@ -24,10 +25,11 @@
"quotes": [ "quotes": [
"error", "error",
"double" "double"
], ]
/*,
"semi": [ "semi": [
"error", "error",
"always" "always"
] ]*/
} }
} }

View File

@ -150,4 +150,4 @@ exports = class Exercise {
workout.emit("redraw"); workout.emit("redraw");
} }
} };

View File

@ -25,4 +25,4 @@ exports = class Set {
if (this.reps <= this.minReps) return; if (this.reps <= this.minReps) return;
this.reps--; this.reps--;
} }
} };

View File

@ -3,7 +3,7 @@ exports = class Workout {
this.title = params.title; this.title = params.title;
this.exercises = []; this.exercises = [];
this.completed = false; this.completed = false;
this.on("redraw", redraw.bind(null, this)); this.on("redraw", params.redraw.bind(null, this));
} }
addExercises(exercises) { addExercises(exercises) {
@ -27,11 +27,12 @@ exports = class Workout {
return !!this.completed; return !!this.completed;
} }
static fromJSON(workoutJSON) { static fromJSON(workoutJSON, redraw) {
const Set = require("buffgym-set.js"); const Set = require("buffgym-set.js");
const Exercise = require("buffgym-exercise.js"); const Exercise = require("buffgym-exercise.js");
const workout = new this({ const workout = new this({
title: workoutJSON.title, title: workoutJSON.title,
redraw: redraw,
}); });
const exercises = workoutJSON.exercises.map(exerciseJSON => { const exercises = workoutJSON.exercises.map(exerciseJSON => {
const exercise = new Exercise({ const exercise = new Exercise({
@ -80,4 +81,4 @@ exports = class Workout {
// Call current exercise state machine // Call current exercise state machine
this.currentExercise().next(this); this.currentExercise().next(this);
} }
} };

View File

@ -248,7 +248,7 @@ function getWorkoutIndex() {
function buildWorkout(fName) { function buildWorkout(fName) {
const Workout = require("buffgym-workout.js"); const Workout = require("buffgym-workout.js");
const workoutJSON = require("Storage").readJSON(fName); const workoutJSON = require("Storage").readJSON(fName);
const workout = Workout.fromJSON(workoutJSON); const workout = Workout.fromJSON(workoutJSON, redraw);
return workout; return workout;
} }

View File

@ -372,7 +372,7 @@ function buttonPress(val) {
for (var k in keys) { for (var k in keys) {
if (keys.hasOwnProperty(k)) { if (keys.hasOwnProperty(k)) {
drawKey(k, keys[k], k == '5'); drawKey(k, keys[k], k == '5');
} }
} }
g.setFont('7x11Numeric7Seg', 2.8); g.setFont('7x11Numeric7Seg', 2.8);

View File

@ -45,12 +45,12 @@ function showMenu() {
} }
}, },
'Reset values': function() { 'Reset values': function() {
settingsChronowid.hours = 0; settingsChronowid.hours = 0;
settingsChronowid.minutes = 0; settingsChronowid.minutes = 0;
settingsChronowid.seconds = 0; settingsChronowid.seconds = 0;
settingsChronowid.started = false; settingsChronowid.started = false;
updateSettings(); updateSettings();
showMenu(); showMenu();
}, },
'Hours': { 'Hours': {
value: settingsChronowid.hours, value: settingsChronowid.hours,
@ -89,8 +89,8 @@ function showMenu() {
settingsChronowid.started = v; settingsChronowid.started = v;
updateSettings(); updateSettings();
} }
}, },
}; };
timerMenu['-Exit-'] = ()=>{load();}; timerMenu['-Exit-'] = ()=>{load();};
return E.showMenu(timerMenu); return E.showMenu(timerMenu);
} }

View File

@ -1,93 +1,93 @@
(() => { (() => {
const storage = require('Storage'); const storage = require('Storage');
settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file
var height = 23; var height = 23;
var width = 58; var width = 58;
var interval = 0; //used for the 1 second interval timer var interval = 0; //used for the 1 second interval timer
var now = new Date(); var now = new Date();
var time = 0; var time = 0;
var diff = settingsChronowid.goal - now; var diff = settingsChronowid.goal - now;
//Convert ms to time //Convert ms to time
function getTime(t) { function getTime(t) {
var milliseconds = parseInt((t % 1000) / 100), var milliseconds = parseInt((t % 1000) / 100),
seconds = Math.floor((t / 1000) % 60), seconds = Math.floor((t / 1000) % 60),
minutes = Math.floor((t / (1000 * 60)) % 60), minutes = Math.floor((t / (1000 * 60)) % 60),
hours = Math.floor((t / (1000 * 60 * 60)) % 24); hours = Math.floor((t / (1000 * 60 * 60)) % 24);
hours = (hours < 10) ? "0" + hours : hours; hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes; minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds; seconds = (seconds < 10) ? "0" + seconds : seconds;
return hours + ":" + minutes + ":" + seconds; return hours + ":" + minutes + ":" + seconds;
}
function printDebug() {
print ("Nowtime: " + getTime(now));
print ("Now: " + now);
print ("Goaltime: " + getTime(settingsChronowid.goal));
print ("Goal: " + settingsChronowid.goal);
print("Difftime: " + getTime(diff));
print("Diff: " + diff);
print ("Started: " + settingsChronowid.started);
print ("----");
}
//counts down, calculates and displays
function countDown() {
now = new Date();
diff = settingsChronowid.goal - now; //calculate difference
WIDGETS["chronowid"].draw();
//time is up
if (settingsChronowid.started && diff < 1000) {
Bangle.buzz(1500);
//write timer off to file
settingsChronowid.started = false;
storage.writeJSON('chronowid.json', settingsChronowid);
clearInterval(interval); //stop interval
} }
function printDebug() {
print ("Nowtime: " + getTime(now));
print ("Now: " + now);
print ("Goaltime: " + getTime(settingsChronowid.goal));
print ("Goal: " + settingsChronowid.goal);
print("Difftime: " + getTime(diff));
print("Diff: " + diff);
print ("Started: " + settingsChronowid.started);
print ("----");
}
//counts down, calculates and displays
function countDown() {
now = new Date();
diff = settingsChronowid.goal - now; //calculate difference
WIDGETS["chronowid"].draw();
//time is up
if (settingsChronowid.started && diff < 1000) {
Bangle.buzz(1500);
//write timer off to file
settingsChronowid.started = false;
storage.writeJSON('chronowid.json', settingsChronowid);
clearInterval(interval); //stop interval
}
//printDebug();
}
// draw your widget
function draw() {
if (!settingsChronowid.started) {
width = 0;
return; //do not draw anything if timer is not started
}
g.reset();
if (diff >= 0) {
if (diff < 3600000) { //less than 1 hour left
width = 58;
g.clearRect(this.x,this.y,this.x+width,this.y+height);
g.setFont("6x8", 2);
g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00
}
if (diff >= 3600000) { //one hour or more left
width = 48;
g.clearRect(this.x,this.y,this.x+width,this.y+height);
g.setFont("6x8", 1);
g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00
}
}
// not needed anymoe, because we check if diff < 1000 now, so 00:00 is displayed.
// else {
// width = 58;
// g.clearRect(this.x,this.y,this.x+width,this.y+height);
// g.setFont("6x8", 2);
// g.drawString("END", this.x+15, this.y+5);
// }
}
if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second
// add the widget
WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() {
reload();
Bangle.drawWidgets(); // relayout all widgets
}};
//printDebug(); //printDebug();
countDown(); }
// draw your widget
function draw() {
if (!settingsChronowid.started) {
width = 0;
return; //do not draw anything if timer is not started
}
g.reset();
if (diff >= 0) {
if (diff < 3600000) { //less than 1 hour left
width = 58;
g.clearRect(this.x,this.y,this.x+width,this.y+height);
g.setFont("6x8", 2);
g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00
}
if (diff >= 3600000) { //one hour or more left
width = 48;
g.clearRect(this.x,this.y,this.x+width,this.y+height);
g.setFont("6x8", 1);
g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00
}
}
// not needed anymoe, because we check if diff < 1000 now, so 00:00 is displayed.
// else {
// width = 58;
// g.clearRect(this.x,this.y,this.x+width,this.y+height);
// g.setFont("6x8", 2);
// g.drawString("END", this.x+15, this.y+5);
// }
}
if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second
// add the widget
WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() {
reload();
Bangle.drawWidgets(); // relayout all widgets
}};
//printDebug();
countDown();
})(); })();

View File

@ -7,12 +7,12 @@ setWatch(x=>{
},BTN1,{repeat:true}); },BTN1,{repeat:true});
function updateAdvertising() { function updateAdvertising() {
try { try {
NRF.setAdvertising({},{ NRF.setAdvertising({},{
manufacturer: 0x0590, manufacturer: 0x0590,
manufacturerData: new Uint8Array([mycounter>>8,mycounter&255]) manufacturerData: new Uint8Array([mycounter>>8,mycounter&255])
}); });
} catch(e){} } catch(e){}
} }
function drawPlayers() { function drawPlayers() {

View File

@ -14,9 +14,9 @@ const x21=x20+pw+ps;
const x30=x21+pw+ds; const x30=x21+pw+ds;
const x31=x30+pw+ps; const x31=x30+pw+ps;
const xSpace=[[x00,x01], // all pixel x spacing const xSpace=[[x00,x01], // all pixel x spacing
[x10,x11], [x10,x11],
[x20,x21], [x20,x21],
[x30,x31]]; [x30,x31]];
const y0=oy; // y spacing const y0=oy; // y spacing
const y1=y0+pw+ps; const y1=y0+pw+ps;
@ -24,35 +24,35 @@ const y2=y1+pw+ps;
const ySpace=[y0, y1, y2]; const ySpace=[y0, y1, y2];
const pixels = [[[0,0], // digit on/off pixels const pixels = [[[0,0], // digit on/off pixels
[1,1], [1,1],
[1,1]], [1,1]],
[[0,1], // digit 1 [[0,1], // digit 1
[0,1], [0,1],
[0,1]], [0,1]],
[[0,1], [[0,1],
[1,0], [1,0],
[1,1]], [1,1]],
[[1,1], [[1,1],
[0,1], [0,1],
[1,1]], [1,1]],
[[1,0], [[1,0],
[1,1], [1,1],
[0,1]], [0,1]],
[[1,1], [[1,1],
[1,0], [1,0],
[0,1]], [0,1]],
[[1,0], [[1,0],
[1,1], [1,1],
[1,1]], [1,1]],
[[1,1], [[1,1],
[0,1], [0,1],
[0,1]], [0,1]],
[[1,1], [[1,1],
[1,1], [1,1],
[1,1]], [1,1]],
[[1,1], [[1,1],
[1,1], [1,1],
[0,1]]]; [0,1]]];
let idTimeout = null; let idTimeout = null;

View File

@ -27,7 +27,7 @@ function arrow(r,c) {
80+60*Math.sin(r), 80-60*Math.cos(r), 80+60*Math.sin(r), 80-60*Math.cos(r),
80+10*Math.sin(r+p), 80-10*Math.cos(r+p), 80+10*Math.sin(r+p), 80-10*Math.cos(r+p),
80+10*Math.sin(r-p), 80-10*Math.cos(r-p), 80+10*Math.sin(r-p), 80-10*Math.cos(r-p),
]); ]);
} }
var oldHeading = 0; var oldHeading = 0;

View File

@ -1 +1 @@
require("heatshrink").decompress(atob("/4AYv4CB+YdZABPvEkYA/AGv3EkfPAQP+DrI")) require("heatshrink").decompress(atob("/4AYv4CB+YdZABPvEkYA/AGv3EkfPAQP+DrI"))

View File

@ -2,9 +2,9 @@ var rx = 0, ry = 0;
function draw() { function draw() {
var rcx=Math.cos(rx), var rcx=Math.cos(rx),
rsx=Math.sin(rx), rsx=Math.sin(rx),
rcy=Math.cos(ry), rcy=Math.cos(ry),
rsy=Math.sin(ry); rsy=Math.sin(ry);
function p(x,y,z) { function p(x,y,z) {
var t; var t;
t = x*rcy + z*rsy; t = x*rcy + z*rsy;

View File

@ -110,8 +110,8 @@ function drawTimeText() {
var time = da[4].split(":"); var time = da[4].split(":");
var hours = time[0], var hours = time[0],
minutes = time[1], minutes = time[1],
seconds = time[2]; seconds = time[2];
g.setColor(mainColor); g.setColor(mainColor);
g.setFont(font, timeFontSize); g.setFont(font, timeFontSize);
g.drawString(`${hours}:${minutes}:${seconds}`, xyCenter, yposTime, true); g.drawString(`${hours}:${minutes}:${seconds}`, xyCenter, yposTime, true);

View File

@ -7,7 +7,7 @@ var debug = 0; //1 = show debug info
//write settings to file //write settings to file
function updateSettings() { function updateSettings() {
storage.write('daysleft.json', settings); storage.write('daysleft.json', settings);
} }
//Define standard settings //Define standard settings
@ -24,8 +24,8 @@ settings = storage.readJSON('daysleft.json',1); //read storage
if (!settings) resetSettings(); //if settings file was not found, set to standard if (!settings) resetSettings(); //if settings file was not found, set to standard
var dd = settings.day, var dd = settings.day,
mm = settings.month-1, //-1 because month is zero-based mm = settings.month-1, //-1 because month is zero-based
yy = settings.year; yy = settings.year;
const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
const targetDate = new Date(yy, mm, dd); //is 00:00 const targetDate = new Date(yy, mm, dd); //is 00:00

View File

@ -27,22 +27,22 @@ var scenes = [
"| __|_ -| . | _| | | | | . |\n"+ "| __|_ -| . | _| | | | | . |\n"+
"|____|___| _|_| |___|_|_|_|___|\n"+ "|____|___| _|_| |___|_|_|_|___|\n"+
" |_| espruino.com\n\n", " |_| espruino.com\n\n",
"The JavaScript Interpreter for uCs\n", "The JavaScript Interpreter for uCs\n",
" * On-chip JS Interpreter", " * On-chip JS Interpreter",
" * GPS, Acclerometer, Compass", " * GPS, Acclerometer, Compass",
" * 64 MHz, 64kB RAM, 512kB + 4MB Flash", " * 64 MHz, 64kB RAM, 512kB + 4MB Flash",
" * 240x240 IPS LCD", " * 240x240 IPS LCD",
" * Speaker & Vibration motor", " * Speaker & Vibration motor",
" * Bluetooth LE", " * Bluetooth LE",
" * 1 week battery life", " * 1 week battery life",
"", "",
"Includes:", "Includes:",
" * Tensorflow AI", " * Tensorflow AI",
" * Bluetooth LE central & periph", " * Bluetooth LE central & periph",
" * Graphics Library", " * Graphics Library",
" * VT100 terminal", " * VT100 terminal",
"","","" "","",""
]; ];
var n=0; var n=0;
var i = setInterval(function() { var i = setInterval(function() {
Terminal.println(txt[n]); Terminal.println(txt[n]);
@ -62,19 +62,19 @@ var scenes = [
function() { function() {
var img = require("heatshrink").decompress(atob("oNBxH+5wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHGpAAoQKv4ADCBQAeqsrAAejBw9/B4oABqt/IGepHw5CEQspALH5hBC5pAvv4/MAALFkIBWpPI6IHqpAu0Z3GfYOpRYdPQEhALYIp2FBYNVI4JAvvL4LH0yBYAFJAQQQ5Ay1JAFftBAQBYxCDv+qIGiCHIQiGnIBfOv5BJIQRAyIJkrvKEkIBrFBB4qEGIGRCNYsZAQIQV/IZDEiICRCDQVJAUIQVPC4lVIF6yJQYpAZ5t/FYvNIBepqtVIJGjIDoqBDY2pdYo3DfAhBIQLmpvIcDvIrC5oJEIAhTCGQmj5qgEC4t5e7YrBqt5BI6UFBg15v4XHbQwAQb4oAKv7NKABdVRoYATUAwnICqjZFIMdVE4+jXI4XGYCxBFFZN/M5OpCxUrvJ/ZFYmjvNVAAY+KCwpDBC6YAV5vNC9oA/AH4A/AHYA==")); var img = require("heatshrink").decompress(atob("oNBxH+5wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHGpAAoQKv4ADCBQAeqsrAAejBw9/B4oABqt/IGepHw5CEQspALH5hBC5pAvv4/MAALFkIBWpPI6IHqpAu0Z3GfYOpRYdPQEhALYIp2FBYNVI4JAvvL4LH0yBYAFJAQQQ5Ay1JAFftBAQBYxCDv+qIGiCHIQiGnIBfOv5BJIQRAyIJkrvKEkIBrFBB4qEGIGRCNYsZAQIQV/IZDEiICRCDQVJAUIQVPC4lVIF6yJQYpAZ5t/FYvNIBepqtVIJGjIDoqBDY2pdYo3DfAhBIQLmpvIcDvIrC5oJEIAhTCGQmj5qgEC4t5e7YrBqt5BI6UFBg15v4XHbQwAQb4oAKv7NKABdVRoYATUAwnICqjZFIMdVE4+jXI4XGYCxBFFZN/M5OpCxUrvJ/ZFYmjvNVAAY+KCwpDBC6YAV5vNC9oA/AH4A/AHYA=="));
g.clear();
y = 0;
var step = 4;
var i = setInterval(function() {
y+=step;
g.clear(); g.clear();
g.drawImage(img,60,60,{rotate:Math.sin(y*0.03)*0.5}); y = 0;
g.flip(); var step = 4;
}, 20); var i = setInterval(function() {
Bangle.setLCDMode("120x120"); y+=step;
return function() { g.clear();
if (i) clearInterval(i); g.drawImage(img,60,60,{rotate:Math.sin(y*0.03)*0.5});
}; g.flip();
}, 20);
Bangle.setLCDMode("120x120");
return function() {
if (i) clearInterval(i);
};
}, },
function() { function() {
var rx = 0, ry = 0; var rx = 0, ry = 0;
@ -82,9 +82,9 @@ var scenes = [
// draw a cube // draw a cube
function draw() { function draw() {
var rcx=Math.cos(rx), var rcx=Math.cos(rx),
rsx=Math.sin(rx), rsx=Math.sin(rx),
rcy=Math.cos(ry), rcy=Math.cos(ry),
rsy=Math.sin(ry); rsy=Math.sin(ry);
// Project 3D coordinates into 2D // Project 3D coordinates into 2D
function p(x,y,z) { function p(x,y,z) {
var t; var t;
@ -149,7 +149,7 @@ var scenes = [
y+=step; y+=step;
g.scroll(0,1); g.scroll(0,1);
g.drawImage(img,Math.random()*240,Math.random()*240, g.drawImage(img,Math.random()*240,Math.random()*240,
{rotate:Math.random()*6.3, scale:0.5+Math.random()}); {rotate:Math.random()*6.3, scale:0.5+Math.random()});
}, 1); }, 1);
Bangle.setLCDMode(); Bangle.setLCDMode();
return function() { return function() {

View File

@ -88,10 +88,10 @@ function binToHex(bins) {
function hexToBin(hexStr) { function hexToBin(hexStr) {
const regEx = new RegExp("..", "g"); const regEx = new RegExp("..", "g");
const bin = hexStr const bin = hexStr
.replace(regEx, el => el + '_') .replace(regEx, el => el + '_')
.slice(0, -1) .slice(0, -1)
.split('_') .split('_')
.map(hex => ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8)); .map(hex => ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8));
return bin; return bin;
} }
@ -153,8 +153,8 @@ function drawFont(str, font, x, y) {
const gridWidthTotal = (rows * (pxlW + gap)) + gutter; const gridWidthTotal = (rows * (pxlW + gap)) + gutter;
for (let i = 0; i < charArr.length; i++) { for (let i = 0; i < charArr.length; i++) {
const charAsBin = fontMap.hasOwnProperty(charArr[i])? const charAsBin = fontMap.hasOwnProperty(charArr[i])?
hexToBin(fontMap[charArr[i]]): hexToBin(fontMap[charArr[i]]):
fontMap.empty; fontMap.empty;
drawGrid( drawGrid(
{x: x + (i * gridWidthTotal), y: y}, {x: x + (i * gridWidthTotal), y: y},
@ -188,8 +188,8 @@ function drawCompass(lastHeading) {
const cps = Bangle.getCompass(); const cps = Bangle.getCompass();
let angle = cps.heading; let angle = cps.heading;
let heading = angle? let heading = angle?
directions[Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8]: directions[Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8]:
"-- "; "-- ";
heading = (heading + " ").slice(0, 3); heading = (heading + " ").slice(0, 3);
if (lastHeading != heading) drawFont(heading, "5x5", 40, 67); if (lastHeading != heading) drawFont(heading, "5x5", 40, 67);

View File

@ -2,7 +2,7 @@ var storage = require('Storage');
//notify your phone //notify your phone
function find(){ function find(){
Bluetooth.println(JSON.stringify({t:"findPhone", n:true})); Bluetooth.println(JSON.stringify({t:"findPhone", n:true}));
} }
//init graphics //init graphics
@ -17,17 +17,17 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
//check if HID enabled and show message //check if HID enabled and show message
if (settings.HID=="kb" || settings.HID=="kbmedia") { if (settings.HID=="kb" || settings.HID=="kbmedia") {
g.setColor(0x03E0); g.setColor(0x03E0);
g.drawString("click to find", g.getWidth()/2, g.getHeight()/2); g.drawString("click to find", g.getWidth()/2, g.getHeight()/2);
//register all buttons and screen to find phone //register all buttons and screen to find phone
setWatch(find, BTN1); setWatch(find, BTN1);
setWatch(find, BTN2); setWatch(find, BTN2);
setWatch(find, BTN3); setWatch(find, BTN3);
setWatch(find, BTN4); setWatch(find, BTN4);
setWatch(find, BTN5); setWatch(find, BTN5);
}else{ }else{
g.setColor(0xf800); g.setColor(0xf800);
g.drawString("enable HID!", g.getWidth()/2, g.getHeight()/2); g.drawString("enable HID!", g.getWidth()/2, g.getHeight()/2);
} }

View File

@ -5,15 +5,15 @@ function redraw() {
g.drawImage(img, 120-96, 120-96, {scale:2}); g.drawImage(img, 120-96, 120-96, {scale:2});
} }
// Code for button (Puck.js) // Code for button (Puck.js)
var busy = false; var busy = false;
var lastTry = getTime(); var lastTry = getTime();
function flag() { function flag() {
E.showMessage("Working..."); E.showMessage("Working...");
if (busy && lastTry+5<getTime()) busy=false; if (busy && lastTry+5<getTime()) busy=false;
lastTry = getTime(); lastTry = getTime();
if (busy) { if (busy) {
digitalPulse(LED1,1,[10,200,10,200,10]); digitalPulse(LED1,1,[10,200,10,200,10]);
@ -22,33 +22,33 @@ function flag() {
busy = true; busy = true;
var gatt; var gatt;
NRF.requestDevice({ filters: [{ name: 'Flag' }] }) NRF.requestDevice({ filters: [{ name: 'Flag' }] })
.then(function(device) { .then(function(device) {
console.log("Found"); console.log("Found");
return device.gatt.connect(); return device.gatt.connect();
}).then(function(g) { }).then(function(g) {
console.log("Connected"); console.log("Connected");
gatt = g; gatt = g;
return gatt.getPrimaryService( return gatt.getPrimaryService(
"3e440001-f5bb-357d-719d-179272e4d4d9"); "3e440001-f5bb-357d-719d-179272e4d4d9");
}).then(function(service) { }).then(function(service) {
console.log("Found service"); console.log("Found service");
return service.getCharacteristic( return service.getCharacteristic(
"3e440002-f5bb-357d-719d-179272e4d4d9"); "3e440002-f5bb-357d-719d-179272e4d4d9");
}).then(function(characteristic) { }).then(function(characteristic) {
console.log("Found characteristic"); console.log("Found characteristic");
return characteristic.writeValue(1); return characteristic.writeValue(1);
}).then(function() { }).then(function() {
console.log("Found service"); console.log("Found service");
gatt.disconnect(); gatt.disconnect();
console.log("Done!"); console.log("Done!");
busy=false; busy=false;
redraw(); redraw();
}).catch(function(e) { }).catch(function(e) {
console.log("ERROR",e); console.log("ERROR",e);
busy=false; busy=false;
gatt.disconnect(); gatt.disconnect();
redraw(); redraw();
}); });
} }
setWatch(flag, BTN, {repeat:true}); setWatch(flag, BTN, {repeat:true});

View File

@ -101,7 +101,7 @@ Bangle.on('touch', function(button) {
if (!running) { if (!running) {
gameStart(); gameStart();
} else { } else {
birdvy -= 4; birdvy -= 4;
} }
}); });

View File

@ -34,14 +34,14 @@ const drawSegment = (params) => {
for (i = angle1; i < angle2; i=i+incr) { for (i = angle1; i < angle2; i=i+incr) {
brush = thickness * (angle2-angle1) /angle2; brush = thickness * (angle2-angle1) /angle2;
points = [ points = [
x + Math.sin(i) * (segRadius+brush), x + Math.sin(i) * (segRadius+brush),
y - Math.cos(i) * (segRadius+brush), y - Math.cos(i) * (segRadius+brush),
x + Math.sin(i+incr) * (segRadius+brush), x + Math.sin(i+incr) * (segRadius+brush),
y - Math.cos(i+incr) * (segRadius+brush), y - Math.cos(i+incr) * (segRadius+brush),
x + Math.sin(i+incr) * (segRadius-brush), x + Math.sin(i+incr) * (segRadius-brush),
y - Math.cos(i+incr) * (segRadius-brush), y - Math.cos(i+incr) * (segRadius-brush),
x + Math.sin(i) * (segRadius-brush), x + Math.sin(i) * (segRadius-brush),
y - Math.cos(i) * (segRadius-brush) y - Math.cos(i) * (segRadius-brush)
]; ];
g.fillPoly(points); g.fillPoly(points);
} }
@ -165,11 +165,11 @@ const drawMinuteHand = () => {
g.setColor(0,1,0); g.setColor(0,1,0);
break; break;
case "blue": case "blue":
g.setColor(0,0,1); g.setColor(0,0,1);
break; break;
case "80s": case "80s":
g.setColor(1,0,0); g.setColor(1,0,0);
break; break;
default: default:
g.setColor(0,1,0); g.setColor(0,1,0);
} }
@ -177,7 +177,7 @@ const drawMinuteHand = () => {
var points = [centerX,centerY]; var points = [centerX,centerY];
for (i = 0; i < angle; i=i+cirRad/60) { for (i = 0; i < angle; i=i+cirRad/60) {
points.push(Math.round(centerX + Math.sin(i) * radius), points.push(Math.round(centerX + Math.sin(i) * radius),
Math.round(centerY - Math.cos(i) * radius)); Math.round(centerY - Math.cos(i) * radius));
} }
g.fillPoly(points); g.fillPoly(points);
}; };
@ -194,24 +194,24 @@ const drawHourHand = () => {
}; };
const drawClockFace = () => { const drawClockFace = () => {
switch(colour) { switch(colour) {
case "red": case "red":
g.setColor(0.8,0.3,0); g.setColor(0.8,0.3,0);
break; break;
case "green": case "green":
g.setColor(0.1,0.7,0); g.setColor(0.1,0.7,0);
break; break;
case "blue": case "blue":
g.setColor(0,0.3,0.8); g.setColor(0,0.3,0.8);
break; break;
case "80s": case "80s":
g.setColor(1,1,1); g.setColor(1,1,1);
break; break;
default: default:
g.setColor(0.1,0.7,0); g.setColor(0.1,0.7,0);
} }
g.fillCircle(centerX,centerY,radius*0.98); g.fillCircle(centerX,centerY,radius*0.98);
}; };
const drawAll = () => { const drawAll = () => {
currentDate = new Date(); currentDate = new Date();

View File

@ -1,33 +1,33 @@
// make sure to enclose the function in parentheses // make sure to enclose the function in parentheses
(function (back) { (function (back) {
let settings = require('Storage').readJSON('gallifr.json',1)||{}; let settings = require('Storage').readJSON('gallifr.json',1)||{};
let colours = ["green","red","blue","80s"]; let colours = ["green","red","blue","80s"];
let onoff = ["on","off"]; let onoff = ["on","off"];
function save(key, value) { function save(key, value) {
settings[key] = value; settings[key] = value;
require('Storage').writeJSON('gallifr.json',settings); require('Storage').writeJSON('gallifr.json',settings);
}
const appMenu = {
'': {'title': 'Clock Settings'},
'< Back': back,
'Colour': {
value: 0|settings['colour'],
min:0,max:3,
format: m => colours[m],
onchange: m => {save('colour', m)}
},
'Widgets': {
value: 0|settings['widgets'],
min:0,max:1,
format: m => onoff[m],
onchange: m => {save('widgets', m)}
},
'Decoration': {
value: 0|settings['decoration'],
min:0,max:1,
format: m => onoff[m],
onchange: m => {save('decoration', m)}
} }
const appMenu = { };
'': {'title': 'Clock Settings'}, E.showMenu(appMenu)
'< Back': back, })
'Colour': {
value: 0|settings['colour'],
min:0,max:3,
format: m => colours[m],
onchange: m => {save('colour', m)}
},
'Widgets': {
value: 0|settings['widgets'],
min:0,max:1,
format: m => onoff[m],
onchange: m => {save('widgets', m)}
},
'Decoration': {
value: 0|settings['decoration'],
min:0,max:1,
format: m => onoff[m],
onchange: m => {save('decoration', m)}
}
};
E.showMenu(appMenu)
})

View File

@ -3,38 +3,38 @@ const storage = require("Storage");
const SETTINGS_FILE = 'getup.settings.json'; const SETTINGS_FILE = 'getup.settings.json';
function setting(key) { function setting(key) {
const DEFAULTS = { const DEFAULTS = {
'sitTime' : 20, 'sitTime' : 20,
'moveTime' : 1 'moveTime' : 1
} }
if (!settings) { if (!settings) {
loadSettings(); loadSettings();
} }
return (key in settings) ? settings[key] : DEFAULTS[key]; return (key in settings) ? settings[key] : DEFAULTS[key];
} }
let settings; let settings;
function loadSettings() { function loadSettings() {
settings = storage.readJSON(SETTINGS_FILE, 1) || {}; settings = storage.readJSON(SETTINGS_FILE, 1) || {};
} }
//vibrate, draw move message and start timer for sitting message //vibrate, draw move message and start timer for sitting message
function remind() { function remind() {
Bangle.buzz(1000,1); Bangle.buzz(1000,1);
g.clear(); g.clear();
g.setFont("8x12",4); g.setFont("8x12",4);
g.setColor(0x03E0); g.setColor(0x03E0);
g.drawString("MOVE!", g.getWidth()/2, g.getHeight()/2); g.drawString("MOVE!", g.getWidth()/2, g.getHeight()/2);
setTimeout(print_message,setting("moveTime") * 60000); setTimeout(print_message,setting("moveTime") * 60000);
} }
//draw sitting message and start timer for reminder //draw sitting message and start timer for reminder
function print_message(){ function print_message(){
g.clear(); g.clear();
g.setFont("8x12",2); g.setFont("8x12",2);
g.setColor(0xF800); g.setColor(0xF800);
g.drawString("sitting is dangerous!", g.getWidth()/2, g.getHeight()/2); g.drawString("sitting is dangerous!", g.getWidth()/2, g.getHeight()/2);
setTimeout(remind,setting("sitTime") * 60000); setTimeout(remind,setting("sitTime") * 60000);
} }
//init graphics //init graphics

View File

@ -4,8 +4,8 @@ var buf = Graphics.createArrayBuffer(240,50,2,{msb:true});
var candraw = true; var candraw = true;
function flip(b,y) { function flip(b,y) {
g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer, palette:pal2color},0,y); g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer, palette:pal2color},0,y);
b.clear(); b.clear();
} }
var brg=0; var brg=0;
@ -44,27 +44,27 @@ function drawCompass(course) {
if (bpos>210) bpos = 226; if (bpos>210) bpos = 226;
buf.setColor(2); buf.setColor(2);
buf.fillCircle(bpos,40,8); buf.fillCircle(bpos,40,8);
} }
flip(buf,Yoff); flip(buf,Yoff);
} }
//displayed heading //displayed heading
var heading = 0; var heading = 0;
function newHeading(m,h){ function newHeading(m,h){
var s = Math.abs(m - h); var s = Math.abs(m - h);
var delta = 1; var delta = 1;
if (s<2) return h; if (s<2) return h;
if (m > h){ if (m > h){
if (s >= 180) { delta = -1; s = 360 - s;} if (s >= 180) { delta = -1; s = 360 - s;}
} else if (m <= h){ } else if (m <= h){
if (s < 180) delta = -1; if (s < 180) delta = -1;
else s = 360 -s; else s = 360 -s;
} }
delta = delta * (1 + Math.round(s/15)); delta = delta * (1 + Math.round(s/15));
heading+=delta; heading+=delta;
if (heading<0) heading += 360; if (heading<0) heading += 360;
if (heading>360) heading -= 360; if (heading>360) heading -= 360;
return heading; return heading;
} }
var course =0; var course =0;
@ -190,20 +190,20 @@ function setButtons(){
setWatch(nextwp.bind(null,-1), BTN1, {repeat:true,edge:"falling"}); setWatch(nextwp.bind(null,-1), BTN1, {repeat:true,edge:"falling"});
setWatch(doselect, BTN2, {repeat:true,edge:"falling"}); setWatch(doselect, BTN2, {repeat:true,edge:"falling"});
setWatch(nextwp.bind(null,1), BTN3, {repeat:true,edge:"falling"}); setWatch(nextwp.bind(null,1), BTN3, {repeat:true,edge:"falling"});
}; }
var SCREENACCESS = { var SCREENACCESS = {
withApp:true, withApp:true,
request:function(){ request:function(){
this.withApp=false; this.withApp=false;
stopdraw(); stopdraw();
clearWatch(); clearWatch();
}, },
release:function(){ release:function(){
this.withApp=true; this.withApp=true;
startdraw(); startdraw();
setButtons(); setButtons();
} }
} }
Bangle.on('lcdPower',function(on) { Bangle.on('lcdPower',function(on) {
@ -229,9 +229,9 @@ function nextwp(inc){
function doselect(){ function doselect(){
if (selected && waypoints[wpindex].lat===undefined && savedfix.fix) { if (selected && waypoints[wpindex].lat===undefined && savedfix.fix) {
waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon}; waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon};
wp = waypoints[wpindex]; wp = waypoints[wpindex];
require("Storage").writeJSON("waypoints.json", waypoints); require("Storage").writeJSON("waypoints.json", waypoints);
} }
selected=!selected; selected=!selected;
drawN(); drawN();

View File

@ -1 +1,2 @@
0.03: Fix time output on new firmwares when no GPS time set (fix #104) 0.03: Fix time output on new firmwares when no GPS time set (fix #104)
0.04: Fix shown UTC time zone sign

View File

@ -47,7 +47,7 @@ Bangle.on('GPS',function(f) {
g.drawString(t[4],120,185); // time g.drawString(t[4],120,185); // time
if (fix.time) { if (fix.time) {
// timezone // timezone
var tz = (new Date()).getTimezoneOffset()/60; var tz = (new Date()).getTimezoneOffset()/-60;
if (tz==0) tz="UTC"; if (tz==0) tz="UTC";
else if (tz>0) tz="UTC+"+tz; else if (tz>0) tz="UTC+"+tz;
else tz="UTC"+tz; else tz="UTC"+tz;

View File

@ -95,7 +95,7 @@ function startKeyboardHID() {
getCharacter().then(ch => { getCharacter().then(ch => {
return sendHID(KEY[ch]); return sendHID(KEY[ch]);
}).then(startKeyboardHID); }).then(startKeyboardHID);
}; }
if (settings.HID=="kb" || settings.HID=="kbmedia") { if (settings.HID=="kb" || settings.HID=="kbmedia") {
if (settings.HID=="kbmedia") { if (settings.HID=="kbmedia") {

View File

@ -48,9 +48,9 @@ function drawApp() {
if (camShot) { if (camShot) {
setWatch(function(e) { setWatch(function(e) {
E.showMessage('camShot !'); E.showMessage('camShot !');
setTimeout(drawApp, 1000); setTimeout(drawApp, 1000);
camShot(() => {}); camShot(() => {});
}, BTN2, { edge:"falling",repeat:true,debounce:50}); }, BTN2, { edge:"falling",repeat:true,debounce:50});
drawApp(); drawApp();

View File

@ -4,71 +4,71 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
var sendInProgress = false; // Only send one message at a time, do not flood var sendInProgress = false; // Only send one message at a time, do not flood
const sendHid = function (x, y, btn1, btn2, btn3, btn4, btn5, cb) { const sendHid = function (x, y, btn1, btn2, btn3, btn4, btn5, cb) {
try { try {
const buttons = (btn5<<4) | (btn4<<3) | (btn3<<2) | (btn2<<1) | (btn1<<0); const buttons = (btn5<<4) | (btn4<<3) | (btn3<<2) | (btn2<<1) | (btn1<<0);
if (!sendInProgress) { if (!sendInProgress) {
sendInProgress = true; sendInProgress = true;
NRF.sendHIDReport([buttons, x, y], () => { NRF.sendHIDReport([buttons, x, y], () => {
sendInProgress = false; sendInProgress = false;
if (cb) cb(); if (cb) cb();
}); });
} }
} catch(e) { } catch(e) {
print(e); print(e);
} }
}; };
function drawApp() { function drawApp() {
g.clear(); g.clear();
g.setFont("6x8",2); g.setFont("6x8",2);
g.setFontAlign(0,0); g.setFontAlign(0,0);
g.drawString("Joystick", 120, 120); g.drawString("Joystick", 120, 120);
const d = g.getWidth() - 18; const d = g.getWidth() - 18;
function c(a) { function c(a) {
return { return {
width: 8, width: 8,
height: a.length, height: a.length,
bpp: 1, bpp: 1,
buffer: (new Uint8Array(a)).buffer buffer: (new Uint8Array(a)).buffer
}; };
} }
g.drawImage(c([16,56,124,254,16,16,16,16]),d,40); g.drawImage(c([16,56,124,254,16,16,16,16]),d,40);
g.drawImage(c([16,16,16,16,254,124,56,16]),d,194); g.drawImage(c([16,16,16,16,254,124,56,16]),d,194);
g.drawImage(c([0,8,12,14,255,14,12,8]),d,116); g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);
} }
function update() { function update() {
const btn1 = BTN1.read(); const btn1 = BTN1.read();
const btn2 = BTN2.read(); const btn2 = BTN2.read();
const btn3 = BTN3.read(); const btn3 = BTN3.read();
const btn4 = BTN4.read(); const btn4 = BTN4.read();
const btn5 = BTN5.read(); const btn5 = BTN5.read();
const acc = Bangle.getAccel(); const acc = Bangle.getAccel();
var x = acc.x*-127; var x = acc.x*-127;
var y = acc.y*-127; var y = acc.y*-127;
// check limits // check limits
if (x > 127) x = 127; if (x > 127) x = 127;
else if (x < -127) x = -127; else if (x < -127) x = -127;
if (y > 127) y = 127; if (y > 127) y = 127;
else if (y < -127) y = -127; else if (y < -127) y = -127;
sendHid(x & 0xff, y & 0xff, btn1, btn2, btn3, btn4, btn5); sendHid(x & 0xff, y & 0xff, btn1, btn2, btn3, btn4, btn5);
} }
if (settings.HID === "joy") { if (settings.HID === "joy") {
drawApp(); drawApp();
setInterval(update, 100); // 10 Hz setInterval(update, 100); // 10 Hz
} else { } else {
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) { E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
if (enable) { if (enable) {
settings.HID = "joy"; settings.HID = "joy";
storage.write('setting.json', settings); storage.write('setting.json', settings);
setTimeout(load, 1000, "hidjoystick.app.js"); setTimeout(load, 1000, "hidjoystick.app.js");
} else { } else {
setTimeout(load, 1000); setTimeout(load, 1000);
} }
}); });
} }

View File

@ -16,13 +16,13 @@ setWatch(x=>{
},BTN1,{repeat:true}); },BTN1,{repeat:true});
function updateAdvertising() { function updateAdvertising() {
try { try {
NRF.setAdvertising({},{ NRF.setAdvertising({},{
manufacturer: 0x0590, manufacturer: 0x0590,
manufacturerData: new Uint8Array([mycounter>>8,mycounter&255]), manufacturerData: new Uint8Array([mycounter>>8,mycounter&255]),
interval: 60 interval: 60
}); });
} catch(e){} } catch(e){}
} }
function drawPlayers() { function drawPlayers() {
@ -44,7 +44,7 @@ function drawPlayers() {
var d = 63 - (offset&63); var d = 63 - (offset&63);
g.fillRect(0,10,240,12); g.fillRect(0,10,240,12);
for (var x=d;x<240;x+=64) for (var x=d;x<240;x+=64)
g.fillRect(x,12,x+2,12+20); g.fillRect(x,12,x+2,12+20);
var y = 20; var y = 20;
var p = mycounter-offset; var p = mycounter-offset;
g.drawString("You",p-16,y+20); g.drawString("You",p-16,y+20);
@ -60,7 +60,7 @@ function drawPlayers() {
g.fillRect(0,150,240,152); g.fillRect(0,150,240,152);
for (var x=d;x<240;x+=64) for (var x=d;x<240;x+=64)
g.fillRect(x,152,x+2,160); g.fillRect(x,152,x+2,160);
g.flip(); g.flip();
} }

View File

@ -45,7 +45,8 @@ function draw() {
cg.setFontAlign(1,-1); cg.setFontAlign(1,-1);
cg.drawString(hours, x, 0); cg.drawString(hours, x, 0);
x+=2; x+=2;
cg.fillRect(x, 10, x+2, 10+2).fillRect(x, 20, x+2, 20+2); if (t.getSeconds() & 1)
cg.fillRect(x, 10, x+2, 10+2).fillRect(x, 20, x+2, 20+2);
x+=6; x+=6;
cg.setFontAlign(-1,-1); cg.setFontAlign(-1,-1);
cg.drawString(("0"+t.getMinutes()).substr(-2), x, 0); cg.drawString(("0"+t.getMinutes()).substr(-2), x, 0);

View File

@ -7,30 +7,30 @@ by Gordon Williams https://github.com/gfwilliams
/* jshint esversion: 6 */ /* jshint esversion: 6 */
const allWords = [ const allWords = [
"AEARLYDN", "AEARLYDN",
"LATEYRZO", "LATEYRZO",
"MORNINGO", "MORNINGO",
"KMIDDLEN", "KMIDDLEN",
"AFTERDAY", "AFTERDAY",
"OFDZTHEC", "OFDZTHEC",
"EVENINGR", "EVENINGR",
"ORMNIGHT" "ORMNIGHT"
]; ];
const timeOfDay = { const timeOfDay = {
0: ["", 0, 0], 0: ["", 0, 0],
1: ["EARLYMORNING", 10, 20, 30, 40, 50, 02, 12, 22, 32, 42, 52, 62], 1: ["EARLYMORNING", 10, 20, 30, 40, 50, 02, 12, 22, 32, 42, 52, 62],
2: ["MORNING", 02, 12, 22, 32, 42, 52, 62], 2: ["MORNING", 02, 12, 22, 32, 42, 52, 62],
3: ["LATEMORNING", 01, 11, 21, 31, 02, 12, 22, 32, 42, 52, 62], 3: ["LATEMORNING", 01, 11, 21, 31, 02, 12, 22, 32, 42, 52, 62],
4: ["MIDDAY", 13, 23, 33, 54, 64, 74], 4: ["MIDDAY", 13, 23, 33, 54, 64, 74],
5: ["EARLYAFTERNOON", 10, 20, 30, 40, 50, 04, 14, 24, 34, 44, 70, 71, 72, 73], 5: ["EARLYAFTERNOON", 10, 20, 30, 40, 50, 04, 14, 24, 34, 44, 70, 71, 72, 73],
6: ["AFTERNOON", 04, 14, 24, 34, 44, 70, 71, 72, 73], 6: ["AFTERNOON", 04, 14, 24, 34, 44, 70, 71, 72, 73],
7: ["LATEAFTERNOON", 01, 11, 21, 31, 04, 14, 24, 34, 44, 70, 71, 72, 73], 7: ["LATEAFTERNOON", 01, 11, 21, 31, 04, 14, 24, 34, 44, 70, 71, 72, 73],
8: ["EARLYEVENING", 10, 20, 30, 40, 50, 06, 16, 26, 36, 46, 56, 66], 8: ["EARLYEVENING", 10, 20, 30, 40, 50, 06, 16, 26, 36, 46, 56, 66],
9: ["EVENING", 06, 16, 26, 36, 46, 56, 66], 9: ["EVENING", 06, 16, 26, 36, 46, 56, 66],
10: ["NIGHT", 37, 47, 57, 67, 77], 10: ["NIGHT", 37, 47, 57, 67, 77],
11: ["MIDDLEOFTHENIGHT", 13, 23, 33, 43, 53, 63, 05, 15, 45, 55, 65, 37,47,57,67,77 ], 11: ["MIDDLEOFTHENIGHT", 13, 23, 33, 43, 53, 63, 05, 15, 45, 55, 65, 37,47,57,67,77 ],
}; };
@ -51,100 +51,100 @@ var hidxPrev;
function drawWordClock() { function drawWordClock() {
// get time // get time
var t = new Date(); var t = new Date();
var h = t.getHours(); var h = t.getHours();
var m = t.getMinutes(); var m = t.getMinutes();
var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2);
var day = t.getDay(); var day = t.getDay();
var hidx; var hidx;
var activeColor = activeColorDay; var activeColor = activeColorDay;
if(h < 7 || h > 19) {activeColor = activeColorNight;} if(h < 7 || h > 19) {activeColor = activeColorNight;}
g.setFont("6x8",fontSize); g.setFont("6x8",fontSize);
g.setColor(passivColor); g.setColor(passivColor);
g.setFontAlign(0, -1, 0); g.setFontAlign(0, -1, 0);
// Switch case isn't good for this in Js apparently so... // Switch case isn't good for this in Js apparently so...
if(h < 3){ if(h < 3){
// Middle of the Night // Middle of the Night
hidx = 11; hidx = 11;
} }
else if (h < 7){ else if (h < 7){
// Early Morning // Early Morning
hidx = 1; hidx = 1;
} }
else if (h < 10){ else if (h < 10){
// Morning // Morning
hidx = 2; hidx = 2;
} }
else if (h < 12){ else if (h < 12){
// Late Morning // Late Morning
hidx = 3; hidx = 3;
} }
else if (h < 13){ else if (h < 13){
// Midday // Midday
hidx = 4; hidx = 4;
} }
else if (h < 14){ else if (h < 14){
// Early afternoon // Early afternoon
hidx = 5; hidx = 5;
} }
else if (h < 16){ else if (h < 16){
// Afternoon // Afternoon
hidx = 6; hidx = 6;
} }
else if (h < 17){ else if (h < 17){
// Late Afternoon // Late Afternoon
hidx = 7; hidx = 7;
} }
else if (h < 19){ else if (h < 19){
// Early evening // Early evening
hidx = 8; hidx = 8;
} }
else if (h < 21){ else if (h < 21){
// evening // evening
hidx = 9; hidx = 9;
} }
else if (h < 24){ else if (h < 24){
// Night // Night
hidx = 10; hidx = 10;
} }
// check whether we need to redraw the watchface // check whether we need to redraw the watchface
if (hidx !== hidxPrev) { if (hidx !== hidxPrev) {
// draw allWords // draw allWords
var c; var c;
var y = ys; var y = ys;
var x = xs; var x = xs;
allWords.forEach((line) => { allWords.forEach((line) => {
x = xs; x = xs;
for (c in line) { for (c in line) {
g.drawString(line[c], x, y); g.drawString(line[c], x, y);
x += dx; x += dx;
} }
y += dy; y += dy;
}); });
// write hour in active color // write hour in active color
g.setColor(activeColor); g.setColor(activeColor);
timeOfDay[hidx][0].split('').forEach((c, pos) => { timeOfDay[hidx][0].split('').forEach((c, pos) => {
x = xs + (timeOfDay[hidx][pos + 1] / 10 | 0) * dx; x = xs + (timeOfDay[hidx][pos + 1] / 10 | 0) * dx;
y = ys + (timeOfDay[hidx][pos + 1] % 10) * dy; y = ys + (timeOfDay[hidx][pos + 1] % 10) * dy;
g.drawString(c, x, y); g.drawString(c, x, y);
}); });
hidxPrev = hidx; hidxPrev = hidx;
} }
// Display digital time while button 1 is pressed // Display digital time while button 1 is pressed
g.clearRect(0, 215, 240, 240); g.clearRect(0, 215, 240, 240);
if (BTN1.read()){ if (BTN1.read()){
g.setColor(activeColor); g.setColor(activeColor);
g.drawString(time, 120, 215); g.drawString(time, 120, 215);
} }
} }

View File

@ -3,19 +3,19 @@ E.showMessage("Jingle Bells");
var eventEmitter = new Object(); var eventEmitter = new Object();
function strofa(notes, times, current, next){ function strofa(notes, times, current, next){
eventEmitter.on(current, () => { eventEmitter.on(current, () => {
if (notes.length == 0) { if (notes.length == 0) {
eventEmitter.emit(next); eventEmitter.emit(next);
return; return;
} }
let note = notes.shift(); let note = notes.shift();
let time = times.shift(); let time = times.shift();
Bangle.beep(time, note).then(() => { Bangle.beep(time, note).then(() => {
setTimeout(() => { setTimeout(() => {
eventEmitter.emit(current); eventEmitter.emit(current);
}, time); }, time);
}); });
}); });
} }
var one = [2637, 2637, 2637, 2637, 2637, 2637, 2637, 3135, 2093, 2349, 2637]; var one = [2637, 2637, 2637, 2637, 2637, 2637, 2637, 3135, 2093, 2349, 2637];

View File

@ -1,16 +1,16 @@
/* jshint esversion: 6 */ /* jshint esversion: 6 */
const distanceUnits = { // how many meters per X? const distanceUnits = { // how many meters per X?
"m": 1, "m": 1,
"yd": 0.9144, "yd": 0.9144,
"mi": 1609.34, "mi": 1609.34,
"km": 1000, "km": 1000,
"kmi": 1000 "kmi": 1000
}; };
const speedUnits = { // how many kph per X? const speedUnits = { // how many kph per X?
"kmh": 1, "kmh": 1,
"kph": 1, "kph": 1,
"km/h": 1, "km/h": 1,
"mph": 1.60934 "mph": 1.60934
}; };
/* /*
@ -34,417 +34,435 @@ timePattern / datePattern:
*/ */
var locales = { var locales = {
"en_GB": { // this is default "en_GB": { // this is default
lang: "en_GB", lang: "en_GB",
decimal_point: ".", decimal_point: ".",
thousands_sep: ",", thousands_sep: ",",
currency_symbol: "£", currency_first: true, currency_symbol: "£", currency_first: true,
int_curr_symbol: "GBP", int_curr_symbol: "GBP",
speed: 'mph', speed: 'mph',
distance: { "0": "yd", "1": "mi" }, distance: { "0": "yd", "1": "mi" },
temperature: '°C', temperature: '°C',
ampm: { 0: "am", 1: "pm" }, ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%b %d %Y", 1: "%d/%m/%Y" }, // Feb 28 2020" // "01/03/2020"(short) datePattern: { 0: "%b %d %Y", 1: "%d/%m/%Y" }, // Feb 28 2020" // "01/03/2020"(short)
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December", month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english... // No translation for english...
}, },
"de_DE": { "de_DE": {
lang: "de_DE", lang: "de_DE",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 01.01.20 datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 01.01.20
abmonth: "Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", abmonth: "Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
abday: "So,Mo,Di,Mi,Do,Fr,Sa", abday: "So,Mo,Di,Mi,Do,Fr,Sa",
day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }
}, },
"en_US": { "en_US": {
lang: "en_US", lang: "en_US",
decimal_point: ".", decimal_point: ".",
thousands_sep: ",", thousands_sep: ",",
currency_symbol: "$", currency_first: true, currency_symbol: "$", currency_first: true,
int_curr_symbol: "USD", int_curr_symbol: "USD",
speed: "mph", speed: "mph",
distance: { 0: "yd", 1: "mi" }, distance: { 0: "yd", 1: "mi" },
temperature: "°F", temperature: "°F",
ampm: { 0: "am", 1: "pm" }, ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%b %d, %Y", 1: "%m/%d/%y" }, datePattern: { 0: "%b %d, %Y", 1: "%m/%d/%y" },
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December", month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english... // No translation for english...
}, },
"en_JP": { // we do not have the font, so it is not ja_JP "en_JP": { // we do not have the font, so it is not ja_JP
lang: "en_JP", lang: "en_JP",
decimal_point: ".", decimal_point: ".",
thousands_sep: ",", thousands_sep: ",",
currency_symbol: "¥", currency_symbol: "¥",
int_curr_symbol: "JPY", int_curr_symbol: "JPY",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°F", temperature: "°F",
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%y/%M/%d", 1: "%y/%m;/%d" }, datePattern: { 0: "%y/%M/%d", 1: "%y/%m;/%d" },
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December", month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english... // No translation for english...
}, },
"nl_NL": { "nl_NL": {
lang: "nl_NL", lang: "nl_NL",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
datePattern: { 0: "%A %B %d %Y", 1: "%d.%m.%y" }, // zondag 1 maart 2020 // 01.01.20 datePattern: { 0: "%A %B %d %Y", 1: "%d.%m.%y" }, // zondag 1 maart 2020 // 01.01.20
abday: "zo,ma,di,wo,do,vr,za", abday: "zo,ma,di,wo,do,vr,za",
day: "zondag,maandag,dinsdag,woensdag,donderdag,vrijdag,zaterdag", day: "zondag,maandag,dinsdag,woensdag,donderdag,vrijdag,zaterdag",
abmonth: "jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec", abmonth: "jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec",
month: "januari,februari,maart,april,mei,juni,juli,augustus,september,oktober,november,december", month: "januari,februari,maart,april,mei,juni,juli,augustus,september,oktober,november,december",
// No translation for english... // No translation for english...
}, },
"en_CA": { "en_CA": {
lang: "en_CA", lang: "en_CA",
decimal_point: ".", decimal_point: ".",
thousands_sep: ",", thousands_sep: ",",
currency_symbol: "$", currency_symbol: "$",
int_curr_symbol: "CAD", int_curr_symbol: "CAD",
speed: "km/h", speed: "km/h",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "am", 1: "pm" }, ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %B %d, %Y", "1": "%Y-%m-%d" }, // Sunday, March 1, 2020 // 2012-12-20 datePattern: { 0: "%A, %B %d, %Y", "1": "%Y-%m-%d" }, // Sunday, March 1, 2020 // 2012-12-20
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December", month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english... // No translation for english...
}, },
"fr_FR": { "fr_FR": {
lang: "fr_FR", lang: "fr_FR",
decimal_point: ",", decimal_point: ",",
thousands_sep: " ", thousands_sep: " ",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: "km/h", speed: "km/h",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%Y" }, // dimanche 1 mars 2020 // 01/03/2020 datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%Y" }, // dimanche 1 mars 2020 // 01/03/2020
abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc", abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc",
month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
abday: "dim,lun,mar,mer,jeu,ven,sam", abday: "dim,lun,mar,mer,jeu,ven,sam",
day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"sv_SE": { "sv_SE": {
lang: "sv_SE", lang: "sv_SE",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "kr", currency_symbol: "kr",
int_curr_symbol: "SKR", int_curr_symbol: "SKR",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "fm", 1: "em" }, ampm: { 0: "fm", 1: "em" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // söndag 1 mars 2020 // 2020-03-01 datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // söndag 1 mars 2020 // 2020-03-01
abmonth: "jan,feb,mars,apr,maj,juni,juli,aug,sep,okt,nov,dec", abmonth: "jan,feb,mars,apr,maj,juni,juli,aug,sep,okt,nov,dec",
month: "januari,februari,mars,april,maj,juni,juli,augusti,september,oktober,november,december", month: "januari,februari,mars,april,maj,juni,juli,augusti,september,oktober,november,december",
abday: "sön,mån,tis,ons,tors,fre,lör", abday: "sön,mån,tis,ons,tors,fre,lör",
day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag", day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag",
trans: { yes: "ja", Yes: "Ja", no: "nej", No: "Nej", ok: "ok", on: "on", off: "off" } trans: { yes: "ja", Yes: "Ja", no: "nej", No: "Nej", ok: "ok", on: "on", off: "off" }
}, },
"en_AU": { "en_AU": {
lang: "en_AU", lang: "en_AU",
decimal_point: ".", decimal_point: ".",
thousands_sep: ",", thousands_sep: ",",
currency_symbol: "$", currency_symbol: "$",
int_curr_symbol: "AUD", int_curr_symbol: "AUD",
speed: "mph", speed: "mph",
distance: { 0: "mi", 1: "kmi" }, distance: { 0: "mi", 1: "kmi" },
temperature: "°F", temperature: "°F",
ampm: { 0: "am", 1: "pm" }, ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %B %d, %Y", "1": "%m/%d/%y" }, // Sunday, 1 March 2020 // 1/3/20 datePattern: { 0: "%A, %B %d, %Y", "1": "%m/%d/%y" }, // Sunday, 1 March 2020 // 1/3/20
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December", month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english... // No translation for english...
}, },
"de_AT": { "de_AT": {
lang: "de_AT", lang: "de_AT",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%y" }, // Sonntag, 1. März 2020 // 01.03.20 datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%y" }, // Sonntag, 1. März 2020 // 01.03.20
abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
month: "Jänner,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", month: "Jänner,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
abday: "So,Mo,Di,Mi,Do,Fr,Sa", abday: "So,Mo,Di,Mi,Do,Fr,Sa",
day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }
}, },
"en_IL": { "en_IL": {
lang: "en_IL", lang: "en_IL",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "₪", currency_symbol: "₪",
int_curr_symbol: "ILS", int_curr_symbol: "ILS",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "am", 1: "pm" }, ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020 datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December", month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english... // No translation for english...
}, },
"es_ES": { "es_ES": {
lang: "es_ES", lang: "es_ES",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %d de %B de %Y", "1": "%d/%m/%y" }, // domingo, 1 de marzo de 2020 // 01/03/20 datePattern: { 0: "%A, %d de %B de %Y", "1": "%d/%m/%y" }, // domingo, 1 de marzo de 2020 // 01/03/20
abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic", abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic",
month: "enero,febrero,marzo,abril,mayo,junio,julio,agosto,septiembre,octubre,noviembre,diciembre", month: "enero,febrero,marzo,abril,mayo,junio,julio,agosto,septiembre,octubre,noviembre,diciembre",
abday: "dom,lun,mar,mié,jue,vie,sáb", abday: "dom,lun,mar,mié,jue,vie,sáb",
day: "domingo,lunes,martes,miércoles,jueves,viernes,sábado", day: "domingo,lunes,martes,miércoles,jueves,viernes,sábado",
trans: { yes: "sí", Yes: "Sí", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "sí", Yes: "Sí", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"fr_BE": { "fr_BE": {
lang: "fr_BE", lang: "fr_BE",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20
abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
abday: "dim,lun,mar,mer,jeu,ven,sam", abday: "dim,lun,mar,mer,jeu,ven,sam",
day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"fi_FI": { "fi_FI": {
lang: "fi_FI", lang: "fi_FI",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "ap", 1: "ip" }, ampm: { 0: "ap", 1: "ip" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, // 17.00.00 // 17.00 timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, // 17.00.00 // 17.00
datePattern: { 0: "%A %d. %B %Y", "1": "%-d/%-m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 datePattern: { 0: "%A %d. %B %Y", "1": "%-d/%-m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020
abmonth: "tammik,helmik,maalisk,huhtik,toukok,kesäk,heinäk,elok,syysk,lokak,marrask,jouluk", abmonth: "tammik,helmik,maalisk,huhtik,toukok,kesäk,heinäk,elok,syysk,lokak,marrask,jouluk",
month: "tammikuuta,helmikuuta,maaliskuuta,huhtikuuta,toukokuuta,kesäkuuta,heinäkuuta,elokuuta,syyskuuta,lokakuuta,marraskuuta,joulukuuta", month: "tammikuuta,helmikuuta,maaliskuuta,huhtikuuta,toukokuuta,kesäkuuta,heinäkuuta,elokuuta,syyskuuta,lokakuuta,marraskuuta,joulukuuta",
abday: "su,ma,ti,ke,to,pe,la", abday: "su,ma,ti,ke,to,pe,la",
day: "sunnuntaina,maanantaina,tiistaina,keskiviikkona,torstaina,perjantaina,lauantaina", day: "sunnuntaina,maanantaina,tiistaina,keskiviikkona,torstaina,perjantaina,lauantaina",
trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"de_CH": { "de_CH": {
lang: "de_CH", lang: "de_CH",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "CHF", currency_symbol: "CHF",
int_curr_symbol: "CHF", int_curr_symbol: "CHF",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "vorm", 1: " nachm" }, ampm: { 0: "vorm", 1: " nachm" },
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 1.3.2020 datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 1.3.2020
abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
abday: "So,Mo,Di,Mi,Do,Fr,Sa", abday: "So,Mo,Di,Mi,Do,Fr,Sa",
day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }
}, },
"fr_CH": { "fr_CH": {
lang: "fr_CH", lang: "fr_CH",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "CHF", currency_symbol: "CHF",
int_curr_symbol: "CHF", int_curr_symbol: "CHF",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "AM", 1: "PM" }, ampm: { 0: "AM", 1: "PM" },
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20
abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
abday: "dim,lun,mar,mer,jeu,ven,sam", abday: "dim,lun,mar,mer,jeu,ven,sam",
day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"it_CH": { "it_CH": {
lang: "it_CH", lang: "it_CH",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "CHF", currency_symbol: "CHF",
int_curr_symbol: "CHF", int_curr_symbol: "CHF",
speed: 'kmh', speed: 'kmh',
distance: { "0": "m", "1": "km" }, distance: { "0": "m", "1": "km" },
temperature: '°C', temperature: '°C',
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00
datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020
abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic",
month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre", month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre",
abday: "dom,lun,mar,mer,gio,ven,sab", abday: "dom,lun,mar,mer,gio,ven,sab",
day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato", day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato",
trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"it_IT": { "it_IT": {
lang: "it_IT", lang: "it_IT",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "\x80", currency_symbol: "\x80",
int_curr_symbol: "EUR", int_curr_symbol: "EUR",
speed: 'kmh', speed: 'kmh',
distance: { "0": "m", "1": "km" }, distance: { "0": "m", "1": "km" },
temperature: '°C', temperature: '°C',
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00
datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020
abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic",
month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre", month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre",
abday: "dom,lun,mar,mer,gio,ven,sab", abday: "dom,lun,mar,mer,gio,ven,sab",
day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato", day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato",
trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"wae_CH": { "wae_CH": {
lang: "wae_CH", lang: "wae_CH",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "CHF", currency_symbol: "CHF",
int_curr_symbol: "CHF", int_curr_symbol: "CHF",
speed: 'kmh', speed: 'kmh',
distance: { "0": "m", "1": "km" }, distance: { "0": "m", "1": "km" },
temperature: '°C', temperature: '°C',
ampm: { 0: "", 1: "" }, ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00
datePattern: { 0: "%A, %d. %B %Y", "1": "%Y-%m-%d" }, // Sunntag, 1. Märze 2020 // 2020-03-01 datePattern: { 0: "%A, %d. %B %Y", "1": "%Y-%m-%d" }, // Sunntag, 1. Märze 2020 // 2020-03-01
abmonth: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr", abmonth: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr",
month: "Jenner,Hornig,Märze,Abrille,Meije,Bráčet,Heiwet,Öigšte,Herbštmánet,Wímánet,Wintermánet,Chrištmánet", month: "Jenner,Hornig,Märze,Abrille,Meije,Bráčet,Heiwet,Öigšte,Herbštmánet,Wímánet,Wintermánet,Chrištmánet",
abday: "Sun,Män,Ziš,Mit,Fró,Fri,Sam", abday: "Sun,Män,Ziš,Mit,Fró,Fri,Sam",
day: "Sunntag,Mäntag,Zištag,Mittwuč,Fróntag,Fritag,Samštag", day: "Sunntag,Mäntag,Zištag,Mittwuč,Fróntag,Fritag,Samštag",
trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" }
}, },
"tr_TR": { // this is default "tr_TR": { // this is default
lang: "tr_TR", lang: "tr_TR",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "TL", currency_symbol: "TL",
int_curr_symbol: "TRY", int_curr_symbol: "TRY",
speed: 'kmh', speed: 'kmh',
distance: { "0": "m", "1": "km" }, distance: { "0": "m", "1": "km" },
temperature: '°C', temperature: '°C',
ampm: { 0: "öö", 1: "ös" }, ampm: { 0: "öö", 1: "ös" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%d %w %Y %A", 1: "%d/%m/%Y" }, // 1 Mart 2020 Pazar // "01/03/2020" datePattern: { 0: "%d %w %Y %A", 1: "%d/%m/%Y" }, // 1 Mart 2020 Pazar // "01/03/2020"
abmonth: "Oca,Sub,Mar,Nis,May,Haz,Tem,Agu,Eyl,Eki,Kas,Ara", abmonth: "Oca,Sub,Mar,Nis,May,Haz,Tem,Agu,Eyl,Eki,Kas,Ara",
month: "Ocak,Subat,Mart,Nisan,Mayis,Haziran,Temmuz,Agustos,Eylul,Ekim,Kasim,Aralik", month: "Ocak,Subat,Mart,Nisan,Mayis,Haziran,Temmuz,Agustos,Eylul,Ekim,Kasim,Aralik",
abday: "Paz,Pzt,Sal,Car,Per,Cum,Cmt", abday: "Paz,Pzt,Sal,Car,Per,Cum,Cmt",
day: "Pazar,Pazartesi,Sali,Carsamba,Persembe,Cuma,Cumartesi", day: "Pazar,Pazartesi,Sali,Carsamba,Persembe,Cuma,Cumartesi",
trans: { yes: "evet", Yes: "Evet", no: "hayir", No: "Hayir", ok: "tamam", on: "acik", off: "kapali" } trans: { yes: "evet", Yes: "Evet", no: "hayir", No: "Hayir", ok: "tamam", on: "acik", off: "kapali" }
}, },
"hu_HU": { "hu_HU": {
lang: "hu_HU", lang: "hu_HU",
decimal_point: ",", decimal_point: ",",
thousands_sep: " ", thousands_sep: " ",
currency_symbol: "Ft", currency_symbol: "Ft",
int_curr_symbol: "HUF", int_curr_symbol: "HUF",
speed: 'kph', speed: 'kph',
distance: { "0": "m", "1": "km" }, distance: { "0": "m", "1": "km" },
temperature: '°C', temperature: '°C',
ampm: { 0: "de", 1: "du" }, ampm: { 0: "de", 1: "du" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%Y %b %d, %A", 1: "%Y.%m.%d" }, // 2020 Feb 28, Péntek" // "2020.03.01."(short) datePattern: { 0: "%Y %b %d, %A", 1: "%Y.%m.%d" }, // 2020 Feb 28, Péntek" // "2020.03.01."(short)
abmonth: "Jan,Feb,Már,Ápr,Máj,Jún,Júl,Aug,Szep,Okt,Nov,Dec", abmonth: "Jan,Feb,Már,Ápr,Máj,Jún,Júl,Aug,Szep,Okt,Nov,Dec",
month: "Január,Február,Március,Április,Május,Június,Július,Augusztus,Szeptember,Október,November,December", month: "Január,Február,Március,Április,Május,Június,Július,Augusztus,Szeptember,Október,November,December",
abday: "Vas,Hét,Ke,Szer,Csüt,Pén,Szom", abday: "Vas,Hét,Ke,Szer,Csüt,Pén,Szom",
day: "Vasárnap,Hétfő,Kedd,Szerda,Csütörtök,Péntek,Szombat", day: "Vasárnap,Hétfő,Kedd,Szerda,Csütörtök,Péntek,Szombat",
trans: { yes: "igen", Yes: "Igen", no: "nem", No: "Nem", ok: "ok", on: "be", off: "ki" } trans: { yes: "igen", Yes: "Igen", no: "nem", No: "Nem", ok: "ok", on: "be", off: "ki" }
}, },
"pt_BR": { "pt_BR": {
lang: "pt_BR", lang: "pt_BR",
decimal_point: ",", decimal_point: ",",
thousands_sep: ".", thousands_sep: ".",
currency_symbol: "R$", currency_first: true, currency_symbol: "R$", currency_first: true,
int_curr_symbol: "BRL", int_curr_symbol: "BRL",
speed: "kmh", speed: "kmh",
distance: { 0: "m", 1: "km" }, distance: { 0: "m", 1: "km" },
temperature: "°C", temperature: "°C",
ampm: { 0: "am", 1: "pm" }, ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%d %b %Y", 1: "%d/%m/%y" }, datePattern: { 0: "%d %b %Y", 1: "%d/%m/%y" },
abmonth: "Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez", abmonth: "Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez",
month: "Janeiro,Fevereiro,Março,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro", month: "Janeiro,Fevereiro,Março,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro",
abday: "Dom,Seg,Ter,Qua,Qui,Sex,Sab", abday: "Dom,Seg,Ter,Qua,Qui,Sex,Sab",
day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado", day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado",
trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "certo", on: "ligado", off: "desligado" } trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "certo", on: "ligado", off: "desligado" }
}, },
"cs_CZ": { "cs_CZ": {
lang: "cs_CZ", lang: "cs_CZ",
decimal_point: ",", decimal_point: ",",
thousands_sep: " ", thousands_sep: " ",
currency_symbol: "Kč", currency_symbol: "Kč",
int_curr_symbol: " CZK", int_curr_symbol: " CZK",
speed: 'kmh', speed: 'kmh',
distance: { "0": "m", "1": "km" }, distance: { "0": "m", "1": "km" },
temperature: '°C', temperature: '°C',
ampm: { 0: "dop", 1: "odp" }, ampm: { 0: "dop", 1: "odp" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%d. %b %Y", 1: "%d.%m.%Y" }, // "30. led 2020" // "30.01.2020"(short) datePattern: { 0: "%d. %b %Y", 1: "%d.%m.%Y" }, // "30. led 2020" // "30.01.2020"(short)
abmonth: "led,úno,bře,dub,kvě,čvn,čvc,srp,zář,říj,lis,pro", abmonth: "led,úno,bře,dub,kvě,čvn,čvc,srp,zář,říj,lis,pro",
month: "leden,únor,březen,duben,květen,červen,červenec,srpen,září,říjen,listopad,prosinec", month: "leden,únor,březen,duben,květen,červen,červenec,srpen,září,říjen,listopad,prosinec",
abday: "ne,po,út,st,čt,pá,so", abday: "ne,po,út,st,čt,pá,so",
day: "neděle,pondělí,úterý,středa,čtvrtek,pátek,sobota", day: "neděle,pondělí,úterý,středa,čtvrtek,pátek,sobota",
trans: { yes: "tak", Yes: "Tak", no: "nie", No: "Nie", ok: "ok", on: "na", off: "poza" } trans: { yes: "tak", Yes: "Tak", no: "nie", No: "Nie", ok: "ok", on: "na", off: "poza" }
} },
"sl_SI": {
lang: "sl_SI",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
int_curr_symbol: "EUR",
speed: "km/h",
distance: { 0: "m", 1: "km" },
temperature: "°C",
ampm: { 0: "dop.", 1: "pop." },
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
datePattern: { 0: "%d. %b %Y", 1: "%d.%m.%Y" }, // "30. jan. 2020" // "30.01.2020"(short)
abmonth: "jan.,feb.,mar.,apr.,maj,jun.,jul.,avg.,sep.,okt.,nov.,dec.",
month: "januar,februar,marec,april,maj,junij,julij,avgust,september,oktober,november,december",
abday: "ned.,pon.,tor.,sre.,čet.,pet.,sob.",
day: "nedelja,ponedeljek,torek,sreda,četrtek,petek,sobota",
trans: { yes: "da", Yes: "Da", no: "ne", No: "Ne", ok: "ok", on: "On", off: "Off" }
}
}; };

View File

@ -96,30 +96,30 @@ function phoneOutbound(msg) {
} }
function phoneClearMessage() { function phoneClearMessage() {
if (phone.message === null) return; if (phone.message === null) return;
if (phone.messageTimeout) { if (phone.messageTimeout) {
clearTimeout(phone.messageTimeout); clearTimeout(phone.messageTimeout);
phone.messageTimeout = null; phone.messageTimeout = null;
} }
phone.message = null; phone.message = null;
phone.messageScrollX = null; phone.messageScrollX = null;
phone.messageType = null; phone.messageType = null;
} }
function phoneNewMessage(type, msg) { function phoneNewMessage(type, msg) {
Bangle.buzz(); Bangle.buzz();
phoneClearMessage(); phoneClearMessage();
phone.messageTimeout = setTimeout(() => phone.message = null, ONE_SECOND * 30); phone.messageTimeout = setTimeout(() => phone.message = null, ONE_SECOND * 30);
phone.message = msg; phone.message = msg;
phone.messageType = type; phone.messageType = type;
// Notify user and active screen // Notify user and active screen
if (!Bangle.isLCDOn()) { if (!Bangle.isLCDOn()) {
clearTimers(); clearTimers();
Bangle.setLCDPower(true); Bangle.setLCDPower(true);
} }
} }
function truncStr(str, max) { function truncStr(str, max) {
@ -258,7 +258,7 @@ function drawTrees() {
// remove first sprite if offscreen // remove first sprite if offscreen
let firstBackgroundSprite = backgroundArr[0]; let firstBackgroundSprite = backgroundArr[0];
if (firstBackgroundSprite) { if (firstBackgroundSprite) {
if (firstBackgroundSprite.x < -15) backgroundArr.splice(0, 1); if (firstBackgroundSprite.x < -15) backgroundArr.splice(0, 1);
} }
// set background sprite if array empty // set background sprite if array empty
@ -365,7 +365,7 @@ function drawNotice(x, y) {
function drawCharacter(date, character) { function drawCharacter(date, character) {
// calculate jumping // calculate jumping
const seconds = date.getSeconds(), const seconds = date.getSeconds(),
milliseconds = date.getMilliseconds(); milliseconds = date.getMilliseconds();
if (seconds == 59 && milliseconds > 800 && !characterSprite.isJumping) { if (seconds == 59 && milliseconds > 800 && !characterSprite.isJumping) {
characterSprite.isJumping = true; characterSprite.isJumping = true;
@ -486,22 +486,22 @@ function drawInfo(date) {
} }
xPos = phone.messageScrollX; xPos = phone.messageScrollX;
} else { } else {
xPos = (W - g.stringWidth(str)) / 2; xPos = (W - g.stringWidth(str)) / 2;
} }
} else { } else {
switch(infoMode) { switch(infoMode) {
case PHON_MODE: case PHON_MODE:
str = buildPhonStr(); str = buildPhonStr();
break; break;
case TEMP_MODE: case TEMP_MODE:
str = buildTempStr(); str = buildTempStr();
break; break;
case BATT_MODE: case BATT_MODE:
str = buildBatStr(); str = buildBatStr();
break; break;
case DATE_MODE: case DATE_MODE:
default: default:
str = buildDateStr(date); str = buildDateStr(date);
} }
xPos = (W - g.stringWidth(str)) / 2; xPos = (W - g.stringWidth(str)) / 2;
} }

View File

@ -16,98 +16,98 @@ var timeInterval;
n is the amount (0..1) n is the amount (0..1)
maxFive is true is this digit only counts 0..5 */ maxFive is true is this digit only counts 0..5 */
const DIGITS = { const DIGITS = {
" ":n=>[], " ":n=>[],
"0":n=>[ "0":n=>[
[n,0,1,0], [n,0,1,0],
[1,0,1,1], [1,0,1,1],
[1,1,1,2], [1,1,1,2],
[n,2,1,2], [n,2,1,2],
[n,1,n,2], [n,1,n,2],
[n,0,n,1]], [n,0,n,1]],
"1":n=>[ "1":n=>[
[1-n,0,1,0], [1-n,0,1,0],
[1,0,1,1], [1,0,1,1],
[1-n,1,1,1], [1-n,1,1,1],
[1-n,1,1-n,2], [1-n,1,1-n,2],
[1-n,2,1,2]], [1-n,2,1,2]],
"2":n=>[ "2":n=>[
[0,0,1,0], [0,0,1,0],
[1,0,1,1], [1,0,1,1],
[0,1,1,1], [0,1,1,1],
[0,1+n,0,2], [0,1+n,0,2],
[1,2-n,1,2], [1,2-n,1,2],
[0,2,1,2]], [0,2,1,2]],
"3":n=>[ "3":n=>[
[0,0,1-n,0], [0,0,1-n,0],
[0,0,0,n], [0,0,0,n],
[1,0,1,1], [1,0,1,1],
[0,1,1,1], [0,1,1,1],
[1,1,1,2], [1,1,1,2],
[n,2,1,2]], [n,2,1,2]],
"4":n=>[ "4":n=>[
[0,0,0,1], [0,0,0,1],
[1,0,1-n,0], [1,0,1-n,0],
[1,0,1,1-n], [1,0,1,1-n],
[0,1,1,1], [0,1,1,1],
[1,1,1,2], [1,1,1,2],
[1-n,2,1,2]], [1-n,2,1,2]],
"5to0": n=>[ // 5 -> 0 "5to0": n=>[ // 5 -> 0
[0,0,0,1], [0,0,0,1],
[0,0,1,0], [0,0,1,0],
[n,1,1,1], [n,1,1,1],
[1,1,1,2], [1,1,1,2],
[0,2,1,2], [0,2,1,2],
[0,2,0,2], [0,2,0,2],
[1,1-n,1,1], [1,1-n,1,1],
[0,1,0,1+n]], [0,1,0,1+n]],
"5to6": n=>[ // 5 -> 6 "5to6": n=>[ // 5 -> 6
[0,0,0,1], [0,0,0,1],
[0,0,1,0], [0,0,1,0],
[0,1,1,1], [0,1,1,1],
[1,1,1,2], [1,1,1,2],
[0,2,1,2], [0,2,1,2],
[0,2-n,0,2]], [0,2-n,0,2]],
"6":n=>[ "6":n=>[
[0,0,0,1-n], [0,0,0,1-n],
[0,0,1,0], [0,0,1,0],
[n,1,1,1], [n,1,1,1],
[1,1-n,1,1], [1,1-n,1,1],
[1,1,1,2], [1,1,1,2],
[n,2,1,2], [n,2,1,2],
[0,1-n,0,2-2*n]], [0,1-n,0,2-2*n]],
"7":n=>[ "7":n=>[
[0,0,0,n], [0,0,0,n],
[0,0,1,0], [0,0,1,0],
[1,0,1,1], [1,0,1,1],
[1-n,1,1,1], [1-n,1,1,1],
[1,1,1,2], [1,1,1,2],
[1-n,2,1,2], [1-n,2,1,2],
[1-n,1,1-n,2]], [1-n,1,1-n,2]],
"8":n=>[ "8":n=>[
[0,0,0,1], [0,0,0,1],
[0,0,1,0], [0,0,1,0],
[1,0,1,1], [1,0,1,1],
[0,1,1,1], [0,1,1,1],
[1,1,1,2], [1,1,1,2],
[0,2,1,2], [0,2,1,2],
[0,1,0,2-n]], [0,1,0,2-n]],
"9":n=>[ "9":n=>[
[0,0,0,1], [0,0,0,1],
[0,0,1,0], [0,0,1,0],
[1,0,1,1], [1,0,1,1],
[0,1,1-n,1], [0,1,1-n,1],
[0,1,0,1+n], [0,1,0,1+n],
[1,1,1,2], [1,1,1,2],
[0,2,1,2]], [0,2,1,2]],
":":n=>[ ":":n=>[
[0.4,0.4,0.6,0.4], [0.4,0.4,0.6,0.4],
[0.6,0.4,0.6,0.6], [0.6,0.4,0.6,0.6],
[0.6,0.6,0.4,0.6], [0.6,0.6,0.4,0.6],
[0.4,0.4,0.4,0.6], [0.4,0.4,0.4,0.6],
[0.4,1.4,0.6,1.4], [0.4,1.4,0.6,1.4],
[0.6,1.4,0.6,1.6], [0.6,1.4,0.6,1.6],
[0.6,1.6,0.4,1.6], [0.6,1.6,0.4,1.6],
[0.4,1.4,0.4,1.6]] [0.4,1.4,0.4,1.6]]
}; };
/* Draw a transition between lastText and thisText. /* Draw a transition between lastText and thisText.

View File

@ -29,23 +29,23 @@ function loadSettings() {
function changecolor() { function changecolor() {
const colors = { const colors = {
0: { value: 0xF800, name: "Red" }, 0: { value: 0xF800, name: "Red" },
1: { value: 0xFFFF, name: "White" }, 1: { value: 0xFFFF, name: "White" },
2: { value: 0x9492, name: "gray" }, 2: { value: 0x9492, name: "gray" },
3: { value: 0xFFFF, name: "White" }, 3: { value: 0xFFFF, name: "White" },
4: { value: 0x9492, name: "gray" }, 4: { value: 0x9492, name: "gray" },
5: { value: 0xFFFF, name: "White" }, 5: { value: 0xFFFF, name: "White" },
6: { value: 0x9492, name: "gray" }, 6: { value: 0x9492, name: "gray" },
7: { value: 0xFFFF, name: "White" }, 7: { value: 0xFFFF, name: "White" },
}; };
g.setColor(colors[cindex].value); g.setColor(colors[cindex].value);
if (cindex == setting('beatsperbar')-1) { if (cindex == setting('beatsperbar')-1) {
cindex = 0; cindex = 0;
} }
else { else {
cindex += 1; cindex += 1;
} }
return cindex; return cindex;
} }
function updateScreen() { function updateScreen() {
@ -63,27 +63,27 @@ function updateScreen() {
Bangle.on('touch', function(button) { Bangle.on('touch', function(button) {
// setting bpm by tapping the screen. Uses the mean time difference between several tappings. // setting bpm by tapping the screen. Uses the mean time difference between several tappings.
if (tindex < time_diffs.length) { if (tindex < time_diffs.length) {
if (Date.now()-tStart < 5000) { if (Date.now()-tStart < 5000) {
time_diffs[tindex] = Date.now()-tStart; time_diffs[tindex] = Date.now()-tStart;
}
} else {
tindex=0;
time_diffs[tindex] = Date.now()-tStart;
}
tindex += 1;
mean_time = 0.0;
for(count = 0; count < time_diffs.length; count++) {
mean_time += time_diffs[count];
} }
time_diff = mean_time/count; } else {
tindex=0;
time_diffs[tindex] = Date.now()-tStart;
}
tindex += 1;
mean_time = 0.0;
for(count = 0; count < time_diffs.length; count++) {
mean_time += time_diffs[count];
}
time_diff = mean_time/count;
tStart = Date.now(); tStart = Date.now();
clearInterval(time_diff); clearInterval(time_diff);
bpm = (60 * 1000/(time_diff)); bpm = (60 * 1000/(time_diff));
updateScreen(); updateScreen();
clearInterval(interval); clearInterval(interval);
interval = setInterval(updateScreen, 60000 / bpm); interval = setInterval(updateScreen, 60000 / bpm);
return bpm; return bpm;
}); });
@ -96,9 +96,9 @@ setWatch(() => {
setWatch(() => { setWatch(() => {
if (bpm > 1) { if (bpm > 1) {
bpm -= 1; bpm -= 1;
clearInterval(interval); clearInterval(interval);
interval = setInterval(updateScreen, 60000 / bpm); interval = setInterval(updateScreen, 60000 / bpm);
} }
}, BTN3, {repeat:true}); }, BTN3, {repeat:true});

View File

@ -4,73 +4,73 @@ const Radius = { "center": 8, "hour": 78, "min": 95, "dots": 102 };
const Center = { "x": 120, "y": 132 }; const Center = { "x": 120, "y": 132 };
function rotatePoint(x, y, d) { function rotatePoint(x, y, d) {
rad = -1 * d / 180 * Math.PI; rad = -1 * d / 180 * Math.PI;
var sin = Math.sin(rad); var sin = Math.sin(rad);
var cos = Math.cos(rad); var cos = Math.cos(rad);
xn = ((Center.x + x * cos - y * sin) + 0.5) | 0; xn = ((Center.x + x * cos - y * sin) + 0.5) | 0;
yn = ((Center.y + x * sin - y * cos) + 0.5) | 0; yn = ((Center.y + x * sin - y * cos) + 0.5) | 0;
p = [xn, yn]; p = [xn, yn];
return p; return p;
} }
function drawMixedClock() { function drawMixedClock() {
var date = new Date(); var date = new Date();
var dateArray = date.toString().split(" "); var dateArray = date.toString().split(" ");
var isEn = locale.name.startsWith("en"); var isEn = locale.name.startsWith("en");
var point = []; var point = [];
var minute = date.getMinutes(); var minute = date.getMinutes();
var hour = date.getHours(); var hour = date.getHours();
var radius; var radius;
// draw date // draw date
g.setColor(0x7be0); g.setColor(0x7be0);
g.setFont("6x8", 2); g.setFont("6x8", 2);
g.setFontAlign(-1, 0); g.setFontAlign(-1, 0);
g.drawString(locale.dow(date,true) + ' ', 4, 35, true); g.drawString(locale.dow(date,true) + ' ', 4, 35, true);
g.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), 4, 225, true); g.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), 4, 225, true);
g.setFontAlign(1, 0); g.setFontAlign(1, 0);
g.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), 237, 35, true); g.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), 237, 35, true);
g.drawString(dateArray[3], 237, 225, true); g.drawString(dateArray[3], 237, 225, true);
// draw hour and minute dots // draw hour and minute dots
g.setColor(0xFD20); // orange g.setColor(0xFD20); // orange
for (i = 0; i < 60; i++) { for (i = 0; i < 60; i++) {
radius = (i % 5) ? 2 : 4; radius = (i % 5) ? 2 : 4;
point = rotatePoint(0, Radius.dots, i * 6); point = rotatePoint(0, Radius.dots, i * 6);
g.fillCircle(point[0], point[1], radius); g.fillCircle(point[0], point[1], radius);
} }
// erase last minutes hand // erase last minutes hand
g.setColor(0); g.setColor(0);
point = rotatePoint(0, Radius.min, (minute - 1) * 6); point = rotatePoint(0, Radius.min, (minute - 1) * 6);
g.drawLine(Center.x, Center.y, point[0], point[1]); g.drawLine(Center.x, Center.y, point[0], point[1]);
// erase last two hour hands // erase last two hour hands
g.setColor(0); g.setColor(0);
p = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 2) / 2 | 0); p = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 2) / 2 | 0);
g.drawLine(Center.x, Center.y, p[0], p[1]); g.drawLine(Center.x, Center.y, p[0], p[1]);
point = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 1) / 2 | 0); point = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 1) / 2 | 0);
g.drawLine(Center.x, Center.y, point[0], point[1]); g.drawLine(Center.x, Center.y, point[0], point[1]);
// draw digital time // draw digital time
g.setFont("6x8", 3); g.setFont("6x8", 3);
g.setColor(0x7be0); g.setColor(0x7be0);
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
g.drawString(dateArray[4].substr(0, 5), 120, 180, true); g.drawString(dateArray[4].substr(0, 5), 120, 180, true);
// draw new minute hand // draw new minute hand
point = rotatePoint(0, Radius.min, minute * 6); point = rotatePoint(0, Radius.min, minute * 6);
g.setColor(0xFFFF); g.setColor(0xFFFF);
g.drawLine(Center.x, Center.y, point[0], point[1]); g.drawLine(Center.x, Center.y, point[0], point[1]);
// draw new hour hand // draw new hour hand
point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0); point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0);
g.setColor(0xFFFF); g.setColor(0xFFFF);
g.drawLine(Center.x, Center.y, point[0], point[1]); g.drawLine(Center.x, Center.y, point[0], point[1]);
// draw center // draw center
g.setColor(0xFD20); g.setColor(0xFD20);
g.fillCircle(Center.x, Center.y, Radius.center); g.fillCircle(Center.x, Center.y, Radius.center);
} }
Bangle.on('lcdPower', function(on) { Bangle.on('lcdPower', function(on) {
if (on) if (on)

View File

@ -32,8 +32,8 @@ function parseDevice(device) {
case 0x1009: event.fertility = d.getUint16(offset+3,true)/10; 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 // case 0x1007: break; // 3 bytes? got 84,0,0 or 68,0,0
default: event.code = code; default: event.code = code;
event.raw = new Uint8Array(d.buffer, offset+3, l); event.raw = new Uint8Array(d.buffer, offset+3, l);
break; break;
} }
//print(event); //print(event);
show(event); show(event);

View File

@ -7,12 +7,12 @@ but because we're going lower level we need to account for the
different pin. */ different pin. */
if (s.beep=="vib") { if (s.beep=="vib") {
function freq(f) { function freq(f) {
if (f===0) digitalWrite(D13, 0); if (f===0) digitalWrite(D13, 0);
else analogWrite(D13, 0.1, {freq: f}); else analogWrite(D13, 0.1, {freq: f});
} }
} else { } else {
function freq(f) { function freq(f) {
if (f===0) digitalWrite(D18, 0); if (f===0) digitalWrite(D18, 0);
else analogWrite(D18, 0.5, {freq: f}); else analogWrite(D18, 0.5, {freq: f});
} }
} }

View File

@ -8,22 +8,22 @@ var timer;
var fix; var fix;
var PI = Math.PI, var PI = Math.PI,
sin = Math.sin, sin = Math.sin,
cos = Math.cos, cos = Math.cos,
tan = Math.tan, tan = Math.tan,
asin = Math.asin, asin = Math.asin,
atan = Math.atan2, atan = Math.atan2,
acos = Math.acos, acos = Math.acos,
rad = PI / 180, rad = PI / 180,
dayMs = 1000 * 60 * 60 * 24, dayMs = 1000 * 60 * 60 * 24,
J1970 = 2440588, J1970 = 2440588,
J2000 = 2451545; J2000 = 2451545;
var SunCalc = {}; var SunCalc = {};
//pictures //pictures
function getImg(i) { function getImg(i) {
var data = { var data = {
"NewMoon": "AD8AAH/4AHwPgDwA8BwADg4AAcMAADHAAA5gAAGYAABsAAAPAAADwAAA8AAAPAAADwAAA2AAAZgAAGcAADjAAAw4AAcHAAOA8APAHwPgAf/gAA/AAA==", "NewMoon": "AD8AAH/4AHwPgDwA8BwADg4AAcMAADHAAA5gAAGYAABsAAAPAAADwAAA8AAAPAAADwAAA2AAAZgAAGcAADjAAAw4AAcHAAOA8APAHwPgAf/gAA/AAA==",
"WaxingCrescentNorth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==", "WaxingCrescentNorth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==",
"WaningCrescentSouth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==", "WaningCrescentSouth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==",
@ -38,12 +38,12 @@ function getImg(i) {
"LastQuarterSouth" : "AD8AAH/4AHx/gDwf8BwH/g4B/8MAf/HAH/5gB/+YAf/sAH//AB//wAf/8AH//AB//wAf/2AH/5gB/+cAf/jAH/w4B/8HAf+A8H/AHx/gAf/gAA/AAA==", "LastQuarterSouth" : "AD8AAH/4AHx/gDwf8BwH/g4B/8MAf/HAH/5gB/+YAf/sAH//AB//wAf/8AH//AB//wAf/2AH/5gB/+cAf/jAH/w4B/8HAf+A8H/AHx/gAf/gAA/AAA==",
"WaningCrescentNorth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA==", "WaningCrescentNorth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA==",
"WaxingCrescentSouth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA==" "WaxingCrescentSouth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA=="
}; };
return { return {
width : 26, height : 26, bpp : 1, width : 26, height : 26, bpp : 1,
transparent : 0, transparent : 0,
buffer : E.toArrayBuffer(atob(data[i])) buffer : E.toArrayBuffer(atob(data[i]))
}; };
} }
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
// date/time constants and conversions // date/time constants and conversions
@ -59,182 +59,182 @@ function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec
function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
function astroRefraction(h) { function astroRefraction(h) {
if (h < 0) // the following formula works for positive altitudes only. if (h < 0) // the following formula works for positive altitudes only.
h = 0; // if h = -0.08901179 a div/0 would occur. h = 0; // if h = -0.08901179 a div/0 would occur.
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
} }
// general sun calculations // general sun calculations
function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
function eclipticLongitude(M) { function eclipticLongitude(M) {
var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
P = rad * 102.9372; // perihelion of the Earth P = rad * 102.9372; // perihelion of the Earth
return M + C + P + PI; return M + C + P + PI;
} }
function sunCoords(d) { function sunCoords(d) {
var M = solarMeanAnomaly(d), var M = solarMeanAnomaly(d),
L = eclipticLongitude(M); L = eclipticLongitude(M);
return { return {
dec: declination(L, 0), dec: declination(L, 0),
ra: rightAscension(L, 0) ra: rightAscension(L, 0)
}; };
} }
// adds a custom time to the times config // adds a custom time to the times config
SunCalc.addTime = function (angle, riseName, setName) { SunCalc.addTime = function (angle, riseName, setName) {
times.push([angle, riseName, setName]); times.push([angle, riseName, setName]);
}; };
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas // moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
function moonCoords(d) { // geocentric ecliptic coordinates of the moon function moonCoords(d) { // geocentric ecliptic coordinates of the moon
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
M = rad * (134.963 + 13.064993 * d), // mean anomaly M = rad * (134.963 + 13.064993 * d), // mean anomaly
F = rad * (93.272 + 13.229350 * d), // mean distance F = rad * (93.272 + 13.229350 * d), // mean distance
l = L + rad * 6.289 * sin(M), // longitude l = L + rad * 6.289 * sin(M), // longitude
b = rad * 5.128 * sin(F), // latitude b = rad * 5.128 * sin(F), // latitude
dt = 385001 - 20905 * cos(M); // distance to the moon in km dt = 385001 - 20905 * cos(M); // distance to the moon in km
return { return {
ra: rightAscension(l, b), ra: rightAscension(l, b),
dec: declination(l, b), dec: declination(l, b),
dist: dt dist: dt
}; };
} }
SunCalc.getMoonPosition = function (date, lat, lng) { SunCalc.getMoonPosition = function (date, lat, lng) {
var lw = rad * -lng, var lw = rad * -lng,
phi = rad * lat, phi = rad * lat,
d = toDays(date), d = toDays(date),
c = moonCoords(d), c = moonCoords(d),
H = siderealTime(d, lw) - c.ra, H = siderealTime(d, lw) - c.ra,
h = altitude(H, phi, c.dec), h = altitude(H, phi, c.dec),
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
h = h + astroRefraction(h); // altitude correction for refraction h = h + astroRefraction(h); // altitude correction for refraction
return { return {
azimuth: azimuth(H, phi, c.dec), azimuth: azimuth(H, phi, c.dec),
altitude: h, altitude: h,
distance: c.dist, distance: c.dist,
parallacticAngle: pa parallacticAngle: pa
}; };
}; };
// calculations for illumination parameters of the moon, // calculations for illumination parameters of the moon,
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
SunCalc.getMoonIllumination = function (date) { SunCalc.getMoonIllumination = function (date) {
var year = date.getFullYear(); var year = date.getFullYear();
var month = date.getMonth(); var month = date.getMonth();
var day = date.getDate(); var day = date.getDate();
var Moon = { var Moon = {
phases: ['new', 'waxing-crescent', 'first-quarter', 'waxing-gibbous', 'full', 'waning-gibbous', 'last-quarter', 'waning-crescent'], phases: ['new', 'waxing-crescent', 'first-quarter', 'waxing-gibbous', 'full', 'waning-gibbous', 'last-quarter', 'waning-crescent'],
phase: function (year, month, day) { phase: function (year, month, day) {
let c = 0; let c = 0;
let e = 0; let e = 0;
let jd = 0; let jd = 0;
let b = 0; let b = 0;
if (month < 3) { if (month < 3) {
year--; year--;
month += 12; month += 12;
} }
++month; ++month;
c = 365.25 * year; c = 365.25 * year;
e = 30.6 * month; e = 30.6 * month;
jd = c + e + day - 694039.09; // jd is total days elapsed jd = c + e + day - 694039.09; // jd is total days elapsed
jd /= 29.5305882; // divide by the moon cycle jd /= 29.5305882; // divide by the moon cycle
b = parseInt(jd); // int(jd) -> b, take integer part of jd b = parseInt(jd); // int(jd) -> b, take integer part of jd
jd -= b; // subtract integer part to leave fractional part of original jd jd -= b; // subtract integer part to leave fractional part of original jd
b = Math.round(jd * 8); // scale fraction from 0-8 and round b = Math.round(jd * 8); // scale fraction from 0-8 and round
if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0 if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0
return {phase: b, name: Moon.phases[b]}; return {phase: b, name: Moon.phases[b]};
} }
}; };
return (Moon.phase(year, month, day)); return (Moon.phase(year, month, day));
}; };
function hoursLater(date, h) { function hoursLater(date, h) {
return new Date(date.valueOf() + h * dayMs / 24); return new Date(date.valueOf() + h * dayMs / 24);
} }
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article // calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
var t = new Date(date); var t = new Date(date);
if (inUTC) t.setUTCHours(0, 0, 0, 0); if (inUTC) t.setUTCHours(0, 0, 0, 0);
else t.setHours(0, 0, 0, 0); else t.setHours(0, 0, 0, 0);
var hc = 0.133 * rad, var hc = 0.133 * rad,
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
for (var i = 1; i <= 24; i += 2) { for (var i = 1; i <= 24; i += 2) {
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
a = (h0 + h2) / 2 - h1; a = (h0 + h2) / 2 - h1;
b = (h2 - h0) / 2; b = (h2 - h0) / 2;
xe = -b / (2 * a); xe = -b / (2 * a);
ye = (a * xe + b) * xe + h1; ye = (a * xe + b) * xe + h1;
d = b * b - 4 * a * h1; d = b * b - 4 * a * h1;
roots = 0; roots = 0;
if (d >= 0) { if (d >= 0) {
dx = Math.sqrt(d) / (Math.abs(a) * 2); dx = Math.sqrt(d) / (Math.abs(a) * 2);
x1 = xe - dx; x1 = xe - dx;
x2 = xe + dx; x2 = xe + dx;
if (Math.abs(x1) <= 1) roots++; if (Math.abs(x1) <= 1) roots++;
if (Math.abs(x2) <= 1) roots++; if (Math.abs(x2) <= 1) roots++;
if (x1 < -1) x1 = x2; if (x1 < -1) x1 = x2;
}
if (roots === 1) {
if (h0 < 0) rise = i + x1;
else set = i + x1;
} else if (roots === 2) {
rise = i + (ye < 0 ? x2 : x1);
set = i + (ye < 0 ? x1 : x2);
}
if (rise && set) break;
h0 = h2;
} }
var result = {}; if (roots === 1) {
if (rise) result.rise = hoursLater(t, rise); if (h0 < 0) rise = i + x1;
if (set) result.set = hoursLater(t, set); else set = i + x1;
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; } else if (roots === 2) {
return result; rise = i + (ye < 0 ? x2 : x1);
set = i + (ye < 0 ? x1 : x2);
}
if (rise && set) break;
h0 = h2;
}
var result = {};
if (rise) result.rise = hoursLater(t, rise);
if (set) result.set = hoursLater(t, set);
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
return result;
}; };
function getMPhaseComp (offset) { function getMPhaseComp (offset) {
var date = new Date(); var date = new Date();
date.setDate(date.getDate() + offset); date.setDate(date.getDate() + offset);
var dd = String(date.getDate()); var dd = String(date.getDate());
if(dd<10){dd='0'+dd;} if(dd<10){dd='0'+dd;}
var mm = String(date.getMonth() + 1); var mm = String(date.getMonth() + 1);
if(mm<10){mm='0'+mm;} if(mm<10){mm='0'+mm;}
var yyyy = date.getFullYear(); var yyyy = date.getFullYear();
var phase = SunCalc.getMoonIllumination(date); var phase = SunCalc.getMoonIllumination(date);
return dd + "." + mm + "." + yyyy + ": "+ phase.name; return dd + "." + mm + "." + yyyy + ": "+ phase.name;
} }
function getMPhaseSim (offset) { function getMPhaseSim (offset) {
var date = new Date(); var date = new Date();
date.setDate(date.getDate() + offset); date.setDate(date.getDate() + offset);
var dd = String(date.getDate()); var dd = String(date.getDate());
if(dd<10){dd='0'+dd;} if(dd<10){dd='0'+dd;}
var mm = String(date.getMonth() + 1); var mm = String(date.getMonth() + 1);
if(mm<10){mm='0'+mm;} if(mm<10){mm='0'+mm;}
var yyyy = date.getFullYear(); var yyyy = date.getFullYear();
var phase = SunCalc.getMoonIllumination(date); var phase = SunCalc.getMoonIllumination(date);
return phase.name; return phase.name;
} }
function drawMoonPhase(offset, x, y){ function drawMoonPhase(offset, x, y){
if (coords.lat >= 0 && coords.lat <= 90){ //Northern hemisphere if (coords.lat >= 0 && coords.lat <= 90){ //Northern hemisphere
if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);} if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);}
if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentNorth"), x, y);} if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentNorth"), x, y);}
if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterNorth"), x, y);} if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterNorth"), x, y);}
@ -243,8 +243,8 @@ function drawMoonPhase(offset, x, y){
if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousNorth"), x, y);} if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousNorth"), x, y);}
if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterNorth"), x, y);} if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterNorth"), x, y);}
if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentNorth"), x, y);} if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentNorth"), x, y);}
} }
else { //Southern hemisphere else { //Southern hemisphere
if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);} if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);}
if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentSouth"), x, y);} if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentSouth"), x, y);}
if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterSouth"), x, y);} if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterSouth"), x, y);}
@ -253,101 +253,101 @@ function drawMoonPhase(offset, x, y){
if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousSouth"), x, y);} if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousSouth"), x, y);}
if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterSouth"), x, y);} if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterSouth"), x, y);}
if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentSouth"), x, y);} if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentSouth"), x, y);}
} }
} }
function drawMoon(offset, x, y) { function drawMoon(offset, x, y) {
g.setFont("6x8"); g.setFont("6x8");
g.clear(); g.clear();
g.drawString("Key1: day+, Key2:today, Key3:day-",x,y-30); g.drawString("Key1: day+, Key2:today, Key3:day-",x,y-30);
g.drawString("Last known coordinates: " + coords.lat.toFixed(4) + " " + coords.lon.toFixed(4), x, y-20); g.drawString("Last known coordinates: " + coords.lat.toFixed(4) + " " + coords.lon.toFixed(4), x, y-20);
g.drawString("Press BTN4 to update",x, y-10); g.drawString("Press BTN4 to update",x, y-10);
g.drawString(getMPhaseComp(offset),x,y+30); g.drawString(getMPhaseComp(offset),x,y+30);
drawMoonPhase(offset, x+35, y+40); drawMoonPhase(offset, x+35, y+40);
g.drawString(getMPhaseComp(offset+2),x,y+70); g.drawString(getMPhaseComp(offset+2),x,y+70);
drawMoonPhase(offset+2, x+35, y+80); drawMoonPhase(offset+2, x+35, y+80);
g.drawString(getMPhaseComp(offset+4),x,y+110); g.drawString(getMPhaseComp(offset+4),x,y+110);
drawMoonPhase(offset+4, x+35, y+120); drawMoonPhase(offset+4, x+35, y+120);
g.drawString(getMPhaseComp(offset+6),x,y+150); g.drawString(getMPhaseComp(offset+6),x,y+150);
drawMoonPhase(offset+6, x+35, y+160); drawMoonPhase(offset+6, x+35, y+160);
} }
//Write coordinates to file //Write coordinates to file
function updateCoords() { function updateCoords() {
storage.write('coords.json', coords); storage.write('coords.json', coords);
} }
//set coordinates to default (city where I live) //set coordinates to default (city where I live)
function resetCoords() { function resetCoords() {
coords = { coords = {
lat : 52.96236, lat : 52.96236,
lon : 7.62571, lon : 7.62571,
}; };
updateCoords(); updateCoords();
} }
function getGpsFix() { function getGpsFix() {
Bangle.on('GPS', function(fix) { Bangle.on('GPS', function(fix) {
g.clear(); g.clear();
if (fix.fix == 1) { if (fix.fix == 1) {
var gpsString = "lat: " + fix.lat.toFixed(4) + " lon: " + fix.lon.toFixed(4); var gpsString = "lat: " + fix.lat.toFixed(4) + " lon: " + fix.lon.toFixed(4);
coords.lat = fix.lat; coords.lat = fix.lat;
coords.lon = fix.lon; coords.lon = fix.lon;
updateCoords(); updateCoords();
g.drawString("Got GPS fix and wrote coords to file",10,20); g.drawString("Got GPS fix and wrote coords to file",10,20);
g.drawString(gpsString,10,30); g.drawString(gpsString,10,30);
g.drawString("Press BTN5 to return to app",10,40); g.drawString("Press BTN5 to return to app",10,40);
clearInterval(timer); clearInterval(timer);
timer = undefined; timer = undefined;
} }
else { else {
g.drawString("Searching satellites...",10,20); g.drawString("Searching satellites...",10,20);
g.drawString("Press BTN5 to stop GPS",10, 30); g.drawString("Press BTN5 to stop GPS",10, 30);
} }
}); });
} }
function start() { function start() {
var x = 10; var x = 10;
var y = 50; var y = 50;
var offsetMoon = 0; var offsetMoon = 0;
coords = storage.readJSON('coords.json',1); //read coordinates from file coords = storage.readJSON('coords.json',1); //read coordinates from file
if (!coords) resetCoords(); //if coordinates could not be read, reset them if (!coords) resetCoords(); //if coordinates could not be read, reset them
drawMoon(offsetMoon, x, y); //offset, x, y
//define button functions
setWatch(function() { //BTN1
offsetMoon++; //jump to next day
drawMoon(offsetMoon, x, y); //offset, x, y drawMoon(offsetMoon, x, y); //offset, x, y
}, BTN1, {edge:"rising", debounce:50, repeat:true});
//define button functions setWatch(function() { //BTN2
setWatch(function() { //BTN1 offsetMoon = 0; //jump to today
offsetMoon++; //jump to next day drawMoon(offsetMoon, x, y); //offset, x, y
drawMoon(offsetMoon, x, y); //offset, x, y }, BTN2, {edge:"rising", debounce:50, repeat:true});
}, BTN1, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN2 setWatch(function() { //BTN3
offsetMoon = 0; //jump to today offsetMoon--; //jump to next day
drawMoon(offsetMoon, x, y); //offset, x, y drawMoon(offsetMoon, x, y); //offset, x, y
}, BTN2, {edge:"rising", debounce:50, repeat:true}); }, BTN3, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN3 setWatch(function() { //BTN4
offsetMoon--; //jump to next day g.drawString("--- Getting GPS signal ---",x, y);
drawMoon(offsetMoon, x, y); //offset, x, y Bangle.setGPSPower(1);
}, BTN3, {edge:"rising", debounce:50, repeat:true}); timer = setInterval(getGpsFix, 10000);
}, BTN4, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN4 setWatch(function() { //BTN5
g.drawString("--- Getting GPS signal ---",x, y); if (timer) clearInterval(timer);
Bangle.setGPSPower(1); timer = undefined;
timer = setInterval(getGpsFix, 10000); Bangle.setGPSPower(0);
}, BTN4, {edge:"rising", debounce:50, repeat:true}); drawMoon(offsetMoon, x, y); //offset, x, y
}, BTN5, {edge:"rising", debounce:50, repeat:true});
setWatch(function() { //BTN5
if (timer) clearInterval(timer);
timer = undefined;
Bangle.setGPSPower(0);
drawMoon(offsetMoon, x, y); //offset, x, y
}, BTN5, {edge:"rising", debounce:50, repeat:true});
} }
start(); start();

View File

@ -95,20 +95,20 @@ const beepItOut = () => {
// Could make buzz optional or switchable potentially // Could make buzz optional or switchable potentially
BUZZING ? Bangle.buzz(UNITS[UNIT_INDEX] === '.' ? UNIT : 3 * UNIT) : null BUZZING ? Bangle.buzz(UNITS[UNIT_INDEX] === '.' ? UNIT : 3 * UNIT) : null
]) ])
.then(() => { .then(() => {
if (UNITS[UNIT_INDEX + 1]) { if (UNITS[UNIT_INDEX + 1]) {
setTimeout(() => { setTimeout(() => {
UNIT_INDEX++; UNIT_INDEX++;
beepItOut(); beepItOut();
}, UNIT); }, UNIT);
} else { } else {
setTimeout(() => { setTimeout(() => {
BEEPING = false; BEEPING = false;
UNIT_INDEX = 0; UNIT_INDEX = 0;
writeLetter(); writeLetter();
}, 3 * UNIT); }, 3 * UNIT);
} }
}); });
}, wait); }, wait);
}; };
const startBeep = () => { const startBeep = () => {

View File

@ -53,7 +53,7 @@ const writeText = (txt) => {
var width = g.stringWidth(txt); var width = g.stringWidth(txt);
// Fit text to screen // Fit text to screen
var fontFix = FONT_SIZE; var fontFix = FONT_SIZE;
while(width > SCREEN_PIXELS-10){ while(width > SCREEN_PIXELS-10){
fontFix--; fontFix--;

View File

@ -118,7 +118,7 @@ function arrow(r,c) {
180+20*Math.sin(r+p), 180-20*Math.cos(r+p), 180+20*Math.sin(r+p), 180-20*Math.cos(r+p),
180-10*Math.sin(r), 180+10*Math.cos(r), 180-10*Math.sin(r), 180+10*Math.cos(r),
180+20*Math.sin(r+-p), 180-20*Math.cos(r-p), 180+20*Math.sin(r+-p), 180-20*Math.cos(r-p),
]); ]);
} }
function onCompass(m) { function onCompass(m) {

View File

@ -51,8 +51,8 @@ function drawNum(num,col,x,y,func){
let tx = x*100+25; let tx = x*100+25;
let ty = y*104+32; let ty = y*104+32;
for (let i=0;i<numerals[num].length;i++){ for (let i=0;i<numerals[num].length;i++){
if (i>0) g.setColor((func==fill)?"#000000":col); if (i>0) g.setColor((func==fill)?"#000000":col);
func(translate(tx,ty,numerals[num][i])); func(translate(tx,ty,numerals[num][i]));
} }
} }
@ -83,7 +83,7 @@ draw(settings.drawMode);
Bangle.on('lcdPower', function(on){ Bangle.on('lcdPower', function(on){
if (on){ if (on){
if (settings.color==0) _rCol = Math.floor(Math.random()*_hCol.length); if (settings.color==0) _rCol = Math.floor(Math.random()*_hCol.length);
draw(settings.drawMode); draw(settings.drawMode);
interval=setInterval(draw, REFRESH_RATE, settings.drawMode); interval=setInterval(draw, REFRESH_RATE, settings.drawMode);
}else }else
{ {

View File

@ -1,7 +1,7 @@
(function(back) { (function(back) {
function updateSettings() { function updateSettings() {
storage.write('numerals.json', numeralsSettings); storage.write('numerals.json', numeralsSettings);
}; }
function resetSettings() { function resetSettings() {
numeralsSettings = { numeralsSettings = {
color:0, color:0,
@ -17,25 +17,25 @@
let col = ["rnd","r/g","y/w","o/c","b/y"]; let col = ["rnd","r/g","y/w","o/c","b/y"];
let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]]; let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]];
var menu={ var menu={
"" : { "title":"Numerals"}, "" : { "title":"Numerals"},
"Colors": { "Colors": {
value: 0|numeralsSettings.color, value: 0|numeralsSettings.color,
min:0,max:4, min:0,max:4,
format: v=>col[v], format: v=>col[v],
onchange: v=> { numeralsSettings.color=v; updateSettings();} onchange: v=> { numeralsSettings.color=v; updateSettings();}
}, },
"Draw mode": { "Draw mode": {
value: 0|dm.indexOf(numeralsSettings.drawMode), value: 0|dm.indexOf(numeralsSettings.drawMode),
min:0,max:1, min:0,max:1,
format: v=>dm[v], format: v=>dm[v],
onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();}
}, },
"Menu button": { "Menu button": {
value: btn.findIndex(e=>e[0]==numeralsSettings.menuButton), value: btn.findIndex(e=>e[0]==numeralsSettings.menuButton),
min:0,max:4, min:0,max:4,
format: v=>btn[v][1], format: v=>btn[v][1],
onchange: v=> { numeralsSettings.menuButton=btn[v][0]; updateSettings();} onchange: v=> { numeralsSettings.menuButton=btn[v][0]; updateSettings();}
}, },
"< back": back "< back": back
}; };
E.showMenu(menu); E.showMenu(menu);

View File

@ -77,29 +77,29 @@ function boy() {
} }
function drawClock() { function drawClock() {
var t = new Date(); var t = new Date();
var h = t.getHours(); var h = t.getHours();
var m = t.getMinutes(); var m = t.getMinutes();
var dd = t.getDate(); var dd = t.getDate();
var mm = t.getMonth()+1; //month is zero-based var mm = t.getMonth()+1; //month is zero-based
var yy = t.getFullYear(); var yy = t.getFullYear();
var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2);
//create date string //create date string
if (dd.toString().length < 2) dd = '0' + dd; if (dd.toString().length < 2) dd = '0' + dd;
if (mm.toString().length < 2) mm = '0' + mm; if (mm.toString().length < 2) mm = '0' + mm;
var date = dd + "." + mm + "." + yy; var date = dd + "." + mm + "." + yy;
g.setFont("6x8",bigFont); g.setFont("6x8",bigFont);
g.setColor(green); g.setColor(green);
g.setFontAlign(0, -1, 0); g.setFontAlign(0, -1, 0);
g.clearRect(0, 110, 150, 140); g.clearRect(0, 110, 150, 140);
g.drawString(time, 70, 110); g.drawString(time, 70, 110);
//draw date //draw date
g.setFont("6x8", tinyFont); g.setFont("6x8", tinyFont);
g.drawString(date, 67, 177); g.drawString(date, 67, 177);
} }
function drawAll() { function drawAll() {

View File

@ -0,0 +1 @@
0.01: You can now time cooking a Pizza!

View File

@ -0,0 +1 @@
# Pizza Timer

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwkBiIA/AH4AwgCzUgEFqtVDIcQDpkQgtO9wACqAfCoAYKCwIVD93kCQMQgAcDAA8F73tqEAAAQXC6Fe8owIiFO9peBpvdAAIRBgvdHQIwIggKBhsNCoPUF4UEgtAp3gFxHlhsFgvQptAFAMQGoPUhpmCLoouB7tArvV7tVC4QEBAIPuC40O8hECAAVVIwXQKIPQC4xGB8FNotEgBBBXIMQhtAIwPQpx4FiBGCotFgFd7vQBQIUBF4NAhwIBLwpGC6ovCEwMAhvUqvVgsOSAsNRoJcCCwKlCgsNPoIXBCAJ2FLwJ2EgpeBGgKOBD4MEVAkQr3QaAIxCqgvBiFUNAMES4SQERwNA6tdBoPVhpeBCYVQQYKXBC4veNQMECIR2CAoUFoB/CC4vugoJBUgIABBgMQgtNoEFbQMA91RC4wAEgALCYoVQ6HQ7wvFOoYAB6DaBBoSMBBAMApxHGgC9BBgPUprbBB4RLBO4NNC4tVgqMBoHQYgQcBDAcAoFUR4tQhvQKoQuBroDBDAZLBKAYXCCoKzCJYKtBb4QHBGQYXEp3gC4XUVIYFBAQVQGYgACr3gCYVFAQJgCAwIKB6kEqAYFh3lU4JBCAQLDDUwNAH4IvFgnuhtF6FdCAJFDggGBgvuoAXFVANQC4NVhoxBqAUBPAVe9xfGPAKfBIgNNgsNhtVGAPVFwPlC40RhvkIgQqCLgQFBpw9BCwzHBKIKRFAANQIoIuIJAIwBgFUCodFgFd93tdggwGpwYBAAhEBIoIuIDAnu6lEolNCoIWNDAVUCYQAB6sACxoYCgEFqtQAgIVOAH4AC"))

270
apps/pizzatimer/app.js Normal file
View File

@ -0,0 +1,270 @@
/* UI GLOBALS */
const HOUR_SCENE = 0;
const MIN_SCENE = 1;
const SEC_SCENE = 2;
const COUNTDOWN_SCENE = 3;
var currentScene = 0;
var btn1Watch;
var btn2Watch;
var btn3Watch;
var drawInterval;
/* STATE GLOBALS */
var menuTime = new Uint8Array([0,0,0]);
var countdownTime = menuTime.slice(0);
var show = [true, true, true];
/* COUNTDOWN CONSTANTS */
const HOUR_INDEX = 0;
const MIN_INDEX = 1;
const SEC_INDEX = 2;
var flashIndex = HOUR_INDEX;
/* logic */
function setCountdownTime() {
countdownTime = menuTime.slice(0);
}
function countDownFinished() {
return countdownTime[HOUR_INDEX] <= 0 &&
countdownTime[MIN_INDEX] <= 0 &&
countdownTime[SEC_INDEX] <= 0;
}
function alertCountdownFinished() {
if (drawInterval) return;
Bangle.buzz()
.then(() => new Promise(resolve => setTimeout(resolve, 200)))
.then(() => Bangle.buzz());
setTimeout(alertCountdownFinished, 2000);
}
function unsetDrawInterval() {
clearInterval(drawInterval);
drawInterval = undefined;
}
function decrementCountdownTime() {
const allZero = countDownFinished();
if(allZero) {
return;
}
if (countdownTime[SEC_INDEX] !== 0) {
countdownTime[SEC_INDEX] = countdownTime[SEC_INDEX] - 1;
return;
}
countdownTime[SEC_INDEX] = 59;
if (countdownTime[MIN_INDEX] !== 0) {
countdownTime[MIN_INDEX] = countdownTime[MIN_INDEX] - 1;
return;
}
countdownTime[MIN_INDEX] = 59;
if (countdownTime[HOUR_INDEX] !== 0) {
countdownTime[HOUR_INDEX] = countdownTime[HOUR_INDEX] - 1;
return;
}
}
function toggleShow(timeIndex) {
show[timeIndex] = !show[timeIndex];
}
function twoPadded(i) {
return i.length < 2 ? "0" + i : i;
}
function getTimeString(t) {
let hour = t[HOUR_INDEX].toString();
let min = t[MIN_INDEX].toString();
let sec = t[SEC_INDEX].toString();
hour = show[HOUR_INDEX] ? twoPadded(hour) : " ";
min = show[MIN_INDEX] ? twoPadded(min) : " ";
sec = show[SEC_INDEX] ? twoPadded(sec) : " ";
return hour + ":" + min + ":" + sec;
}
/* drawing */
/*
shamelessly stollen from Bluetooth Music Controls
https://github.com/espruino/BangleApps/blob/6b09377414e02d575b8335bb051c831ecc9da9d9/apps/hidmsic/hid-music.js#L42
*/
function drawArrows() {
function c(a) {
return {
width: 8,
height: a.length,
bpp: 1,
buffer: (new Uint8Array(a)).buffer
};
}
const d = g.getWidth() - 18;
g.drawImage(c([16,56,124,254,16,16,16,16]),d,40);
g.drawImage(c([16,16,16,16,254,124,56,16]),d,194);
g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);
}
function drawTime(input) {
g.clear();
g.setFontAlign(0,0);
g.setFont("4x6",5);
g.drawString(input, g.getWidth() / 2, g.getHeight() / 2);
}
function drawMenu() {
const timeString = getTimeString(menuTime);
drawTime(timeString);
drawArrows();
}
function drawCountdown() {
const timeString = getTimeString(countdownTime);
drawTime(timeString);
}
/* button callbacks */
function getMaxSelectableTime() {
return flashIndex === HOUR_INDEX ? 23 : 59;
}
/* btn1 */
function incrementMenuTime() {
const maxTime = getMaxSelectableTime();
const currentTime = menuTime[flashIndex];
const newTime = currentTime < maxTime ? currentTime + 1 : 0;
menuTime[flashIndex] = newTime;
}
/* btn2 */
function incrementScene() {
currentScene++;
}
function incrementFlashIndex() {
flashIndex++;
}
function showAll() {
for(var i = 0; i < show.length; i++) {
show[i] = true;
}
}
function showFlashIndex() {
show[flashIndex] = true;
}
function hideFlashIndex() {
show[flashIndex] = false;
}
function next() {
incrementScene();
if (currentScene === COUNTDOWN_SCENE) {
showAll();
startCountdownScene();
} else {
showFlashIndex();
incrementFlashIndex();
hideFlashIndex();
}
}
/* btn3 */
function decrementMenuTime() {
const maxTime = getMaxSelectableTime();
const currentTime = menuTime[flashIndex];
const newTime = currentTime > 0 ? currentTime - 1 : maxTime;
menuTime[flashIndex] = newTime;
}
/* watches */
function setupMenuWatches() {
clearWatch();
btn1Watch = setWatch(incrementMenuTime, BTN1, {repeat: true});
btn2Watch = setWatch(next, BTN2, {repeat: true});
btn3Watch = setWatch(decrementMenuTime, BTN3, {repeat: true});
}
function setupCountdownWatches() {
clearWatch();
btn2Watch = setWatch(main, BTN2, {repeat: true});
}
/* scenes */
function menu() {
drawMenu();
toggleShow(flashIndex);
}
function countdown() {
decrementCountdownTime();
drawCountdown();
if (countDownFinished()) {
unsetDrawInterval();
alertCountdownFinished();
}
}
/* init */
function unsetDrawInterval() {
if (!drawInterval) return;
clearInterval(drawInterval);
drawInterval = undefined;
}
function startMenuScene() {
setupMenuWatches();
unsetDrawInterval();
menu();
drawInterval = setInterval(menu, 500);
}
function startCountdownScene() {
setupCountdownWatches();
unsetDrawInterval();
setCountdownTime();
showAll();
drawCountdown();
drawInterval = setInterval(countdown, 1000);
}
/* main */
function reset() {
currentScene = 0;
flashIndex = HOUR_INDEX;
hideFlashIndex();
}
function main() {
reset();
startMenuScene();
}
main();

BIN
apps/pizzatimer/pizza.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -3,254 +3,254 @@ const storage = require("Storage");
const DEFAULT_TIME = 1500; // 25m const DEFAULT_TIME = 1500; // 25m
const TIME_BREAK = 300; const TIME_BREAK = 300;
const STATES = { const STATES = {
INIT: 1, INIT: 1,
STARTED: 2, STARTED: 2,
DONE: 3, DONE: 3,
BREAK: 4 BREAK: 4
}; };
var counterInterval; var counterInterval;
class State { class State {
constructor (state) { constructor (state) {
this.state = state; this.state = state;
this.next = null; this.next = null;
}
setNext (next) {
this.next = next;
}
setButtons () {}
clear () {
clearWatch();
g.clear();
g.setFontAlign(0, 0);
}
draw () {
g.clear();
}
init () { }
go (nextState) {
if (nextState) {
this.next = nextState;
} }
setNext (next) { this.clear();
this.next = next; this.init();
} this.setButtons();
this.draw();
setButtons () {} }
clear () {
clearWatch();
g.clear();
g.setFontAlign(0, 0);
}
draw () {
g.clear();
}
init () { }
go (nextState) {
if (nextState) {
this.next = nextState;
}
this.clear();
this.init();
this.setButtons();
this.draw();
}
} }
class InitState extends State { class InitState extends State {
constructor (time) { constructor (time) {
super(STATES.INIT); super(STATES.INIT);
this.timeCounter = parseInt(storage.read(".pomodo") || DEFAULT_TIME, 10); this.timeCounter = parseInt(storage.read(".pomodo") || DEFAULT_TIME, 10);
} }
saveTime () { saveTime () {
storage.write('.pomodo', '' + this.timeCounter); storage.write('.pomodo', '' + this.timeCounter);
} }
setButtons () { setButtons () {
setWatch(() => { setWatch(() => {
if (this.timeCounter + 300 > 3599) { if (this.timeCounter + 300 > 3599) {
this.timeCounter = 3599; this.timeCounter = 3599;
} else { } else {
this.timeCounter += 300; this.timeCounter += 300;
} }
this.draw(); this.draw();
}, BTN1, { repeat: true }); }, BTN1, { repeat: true });
setWatch(() => { setWatch(() => {
if (this.timeCounter - 300 > 0) { if (this.timeCounter - 300 > 0) {
this.timeCounter -= 300; this.timeCounter -= 300;
this.draw(); this.draw();
} }
}, BTN3, { repeat: true }); }, BTN3, { repeat: true });
setWatch(() => { setWatch(() => {
if (this.timeCounter - 60 > 0) { if (this.timeCounter - 60 > 0) {
this.timeCounter -= 60; this.timeCounter -= 60;
this.draw(); this.draw();
} }
}, BTN4, { repeat: true }); }, BTN4, { repeat: true });
setWatch(() => { setWatch(() => {
if (this.timeCounter + 60 > 3599) { if (this.timeCounter + 60 > 3599) {
this.timeCounter = 3599; this.timeCounter = 3599;
} else { } else {
this.timeCounter += 60; this.timeCounter += 60;
} }
this.draw(); this.draw();
}, BTN5, { repeat: true }); }, BTN5, { repeat: true });
setWatch(() => { setWatch(() => {
this.saveTime(); this.saveTime();
const startedState = new StartedState(this.timeCounter); const startedState = new StartedState(this.timeCounter);
this.setNext(startedState); this.setNext(startedState);
this.next.go(); this.next.go();
}, BTN2, { repeat: true }); }, BTN2, { repeat: true });
} }
draw () { draw () {
g.clear(); g.clear();
g.setFontAlign(0, 0); // center font g.setFontAlign(0, 0); // center font
g.setFont("Vector", 50); // vector font, 80px g.setFont("Vector", 50); // vector font, 80px
drawCounter(this.timeCounter); drawCounter(this.timeCounter);
} }
} }
class StartedState extends State { class StartedState extends State {
constructor (timeCounter) { constructor (timeCounter) {
super(STATES.STARTED); super(STATES.STARTED);
this.timeCounter = timeCounter; this.timeCounter = timeCounter;
}
draw () {
drawCounter(this.timeCounter, 120, 120);
}
init () {
function countDown () {
this.timeCounter--;
// Out of time
if (this.timeCounter <= 0) {
clearInterval(counterInterval);
counterInterval = undefined;
this.next.go();
return;
}
this.draw();
} }
draw () { const doneState = new DoneState();
drawCounter(this.timeCounter, 120, 120); this.setNext(doneState);
} counterInterval = setInterval(countDown.bind(this), 1000);
}
init () {
function countDown () {
this.timeCounter--;
// Out of time
if (this.timeCounter <= 0) {
clearInterval(counterInterval);
counterInterval = undefined;
this.next.go();
return;
}
this.draw();
}
const doneState = new DoneState();
this.setNext(doneState);
counterInterval = setInterval(countDown.bind(this), 1000);
}
} }
class BreakState extends State { class BreakState extends State {
constructor () { constructor () {
super(STATES.BREAK); super(STATES.BREAK);
} }
draw () { draw () {
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
} }
init () { init () {
const startedState = new StartedState(TIME_BREAK); const startedState = new StartedState(TIME_BREAK);
this.setNext(startedState); this.setNext(startedState);
this.next.go(); this.next.go();
} }
} }
class DoneState extends State { class DoneState extends State {
constructor () { constructor () {
super(STATES.DONE); super(STATES.DONE);
}
setButtons () {
setWatch(() => {
const initState = new InitState();
clearTimeout(this.timeout);
initState.go();
}, BTN1, { repeat: true });
setWatch(() => {
const breakState = new BreakState();
clearTimeout(this.timeout);
breakState.go();
}, BTN3, { repeat: true });
setWatch(() => {
}, BTN2, { repeat: true });
}
draw () {
g.clear();
g.setFont("6x8", 2);
g.setFontAlign(0, 0, 3);
g.drawString("AGAIN", 230, 50);
g.drawString("BREAK", 230, 190);
g.setFont("Vector", 45);
g.setFontAlign(-1, -1);
g.drawString('You\nare\na\nhero!', 50, 40);
}
init () {
function buzz () {
Bangle.buzz();
Bangle.beep(200, 4000)
.then(() => new Promise(resolve => setTimeout(resolve, 50)))
.then(() => Bangle.beep(200, 3000))
.then(() => new Promise(resolve => setTimeout(resolve, 200)))
.then(() => Bangle.beep(200, 3000))
.then(() => new Promise(resolve => setTimeout(resolve, 300)))
.then(() => {
Bangle.beep(200, 3000);
Bangle.buzz()
});
} }
setButtons () { buzz();
setWatch(() => { // again, 10 secs later
const initState = new InitState(); this.timeout = setTimeout(buzz.bind(this), 10000);
clearTimeout(this.timeout); }
initState.go();
}, BTN1, { repeat: true });
setWatch(() => {
const breakState = new BreakState();
clearTimeout(this.timeout);
breakState.go();
}, BTN3, { repeat: true });
setWatch(() => {
}, BTN2, { repeat: true });
}
draw () {
g.clear();
g.setFont("6x8", 2);
g.setFontAlign(0, 0, 3);
g.drawString("AGAIN", 230, 50);
g.drawString("BREAK", 230, 190);
g.setFont("Vector", 45);
g.setFontAlign(-1, -1);
g.drawString('You\nare\na\nhero!', 50, 40);
}
init () {
function buzz () {
Bangle.buzz();
Bangle.beep(200, 4000)
.then(() => new Promise(resolve => setTimeout(resolve, 50)))
.then(() => Bangle.beep(200, 3000))
.then(() => new Promise(resolve => setTimeout(resolve, 200)))
.then(() => Bangle.beep(200, 3000))
.then(() => new Promise(resolve => setTimeout(resolve, 300)))
.then(() => {
Bangle.beep(200, 3000);
Bangle.buzz()
});
}
buzz();
// again, 10 secs later
this.timeout = setTimeout(buzz.bind(this), 10000);
}
} }
function drawCounter (currentValue, x, y) { function drawCounter (currentValue, x, y) {
if (currentValue < 0) { if (currentValue < 0) {
return; return;
} }
x = x || 120; x = x || 120;
y = y || 120; y = y || 120;
let minutes = 0; let minutes = 0;
let seconds = 0; let seconds = 0;
if (currentValue >= 60) { if (currentValue >= 60) {
minutes = Math.floor(currentValue / 60); minutes = Math.floor(currentValue / 60);
seconds = currentValue % 60; seconds = currentValue % 60;
} else { } else {
seconds = currentValue; seconds = currentValue;
} }
let minutesString = '' + minutes; let minutesString = '' + minutes;
let secondsString = '' + seconds; let secondsString = '' + seconds;
if (minutes < 10) { if (minutes < 10) {
minutesString = '0' + minutes; minutesString = '0' + minutes;
} }
if (seconds < 10) { if (seconds < 10) {
secondsString = '0' + seconds; secondsString = '0' + seconds;
} }
g.clear(); g.clear();
g.drawString(minutesString + ':' + secondsString, x, y); g.drawString(minutesString + ':' + secondsString, x, y);
} }
function init () { function init () {
const initState = new InitState(); const initState = new InitState();
initState.go(); initState.go();
} }
init(); init();

View File

@ -167,7 +167,7 @@
g.drawString(date, settings.date.center, settings.date.middle); g.drawString(date, settings.date.center, settings.date.middle);
}; };
//setInterval for HR visualisation //setInterval for HR visualisation
const newBeats = function (hr) { const newBeats = function (hr) {
if (id != 0) { if (id != 0) {
changeInterval(id, 6e3 / hr.bpm); changeInterval(id, 6e3 / hr.bpm);
@ -206,7 +206,7 @@
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
//manage when things should be enabled and not //manage when things should be enabled and not
Bangle.on('lcdPower', function (on) { Bangle.on('lcdPower', function (on) {
if (on) { if (on) {
Bangle.setHRMPower(1); Bangle.setHRMPower(1);

View File

@ -1,2 +1,3 @@
0.01: New widget 0.01: New widget
0.02: Less invasive, change default clock setting instead of directly loading the new clock (no longer breaks Gadgetbridge notifications) 0.02: Less invasive, change default clock setting instead of directly loading the new clock (no longer breaks Gadgetbridge notifications)
0.03: Only changes when the widget id reloaded (no longer uses LCD turning off)

View File

@ -1,6 +1,6 @@
# Summary # Summary
Random Clock is a widget that will randomly show one of the installed watch faces each time the LCD is turned on. Random Clock is a widget that will randomly show one of the installed watch faces each time after the widget is (re-)loaded.
# How it works # How it works
Everytime the LCD is turned off, the widget randomly changes the clock. When you long press BTN 3 the next time, Everytime the widget is reloaded, it randomly changes the clock. When you long press BTN 3 the next time,
you might (or might not, it's random after all) see another watch face. you might (or might not, it's random after all) see another watch face.

View File

@ -16,20 +16,18 @@
if (clockApps && clockApps.length > 0) { if (clockApps && clockApps.length > 0) {
var clockIndex = getRandomInt(clockApps.length); var clockIndex = getRandomInt(clockApps.length);
// Only update the file if the clock really change to be nice to the FLASH mem // Only update the file if the clock really changed to be nice to the FLASH mem
if (clockApps[clockIndex].src != currentClock) { if (clockApps[clockIndex].src != currentClock) {
currentClock = clockApps[clockIndex].src; currentClock = clockApps[clockIndex].src;
settings = require("Storage").readJSON('setting.json', 1); settings = require("Storage").readJSON('setting.json', 1);
settings.clock = clockApps[clockIndex].src; settings.clock = clockApps[clockIndex].src;
require("Storage").write('setting.json', settings); require("Storage").write('setting.json', settings);
console.log("RandomClockWidget set the clock to '" + clockApps[clockIndex].name + "'");
} }
} }
} }
Bangle.on('lcdPower', (on) => { loadRandomClock();
if (!on) {
loadRandomClock();
}
});
})(); })();

View File

@ -1,60 +1,60 @@
/* jshint esversion: 6 */ /* jshint esversion: 6 */
(function() { (function() {
const colors = { const colors = {
0: { value: 0x0000, name: "Black" }, 0: { value: 0x0000, name: "Black" },
1: { value: 0x000F, name: "Navy" }, 1: { value: 0x000F, name: "Navy" },
2: { value: 0x03E0, name: "DarkGreen" }, 2: { value: 0x03E0, name: "DarkGreen" },
3: { value: 0x03EF, name: "DarkCyan" }, 3: { value: 0x03EF, name: "DarkCyan" },
4: { value: 0x7800, name: "Maroon" }, 4: { value: 0x7800, name: "Maroon" },
5: { value: 0x780F, name: "Purple" }, 5: { value: 0x780F, name: "Purple" },
6: { value: 0x7BE0, name: "Olive" }, 6: { value: 0x7BE0, name: "Olive" },
7: { value: 0xC618, name: "LightGray" }, 7: { value: 0xC618, name: "LightGray" },
8: { value: 0x7BEF, name: "DarkGrey" }, 8: { value: 0x7BEF, name: "DarkGrey" },
9: { value: 0x001F, name: "Blue" }, 9: { value: 0x001F, name: "Blue" },
10: { value: 0x07E0, name: "Green" }, 10: { value: 0x07E0, name: "Green" },
11: { value: 0x07FF, name: "Cyan" }, 11: { value: 0x07FF, name: "Cyan" },
12: { value: 0xF800, name: "Red" }, 12: { value: 0xF800, name: "Red" },
13: { value: 0xF81F, name: "Magenta" }, 13: { value: 0xF81F, name: "Magenta" },
14: { value: 0xFFE0, name: "Yellow" }, 14: { value: 0xFFE0, name: "Yellow" },
15: { value: 0xFFFF, name: "White" }, 15: { value: 0xFFFF, name: "White" },
16: { value: 0xFD20, name: "Orange" }, 16: { value: 0xFD20, name: "Orange" },
17: { value: 0xAFE5, name: "GreenYellow" }, 17: { value: 0xAFE5, name: "GreenYellow" },
18: { value: 0xF81F, name: "Pink" }, 18: { value: 0xF81F, name: "Pink" },
}; };
const maxColors = 19; const maxColors = 19;
var index = 0; var index = 0;
function drawColor() { function drawColor() {
// draw filled rectangle // draw filled rectangle
g.setColor(colors[index % maxColors].value); g.setColor(colors[index % maxColors].value);
g.fillRect(0, 24, g.getWidth(), g.getHeight()); g.fillRect(0, 24, g.getWidth(), g.getHeight());
// draw value name of color // draw value name of color
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
g.setColor(0xFFFF); g.setColor(0xFFFF);
if (colors[index % maxColors].name == "White") if (colors[index % maxColors].name == "White")
g.setColor(0); g.setColor(0);
g.setFont("6x8", 4); g.setFont("6x8", 4);
g.drawString('0x' + colors[index % maxColors].value.toString(16), 120, 80); g.drawString('0x' + colors[index % maxColors].value.toString(16), 120, 80);
g.setFont("6x8", 3); g.setFont("6x8", 3);
g.drawString(colors[index % maxColors].name, 120, 160); g.drawString(colors[index % maxColors].name, 120, 160);
// draw next button info // draw next button info
g.setFont("6x8", 2); g.setFont("6x8", 2);
g.setFontAlign(0, 0, 3); g.setFontAlign(0, 0, 3);
g.drawString("Next", 230, 60); g.drawString("Next", 230, 60);
// set watches for button 1 // set watches for button 1
index++; index++;
setWatch(drawColor, BTN1, { repeate: true }); setWatch(drawColor, BTN1, { repeate: true });
} }
g.clear(); g.clear();
setWatch(drawColor, BTN1, { repeate: false }); setWatch(drawColor, BTN1, { repeate: false });
E.showMessage("Press BTN1\nto start"); E.showMessage("Press BTN1\nto start");
})(); })();

View File

@ -2,3 +2,4 @@
0.02: Add widgets to app 0.02: Add widgets to app
0.03: Use offscreen buffer (not doublebuffer) 0.03: Use offscreen buffer (not doublebuffer)
Use 'locale' to get internationalised speed Use 'locale' to get internationalised speed
0.04: Start GPS after loading app, just in case widgets affect it (#449)

View File

@ -1,4 +1,3 @@
Bangle.setGPSPower(1);
var buf = Graphics.createArrayBuffer(240,120,1,{msb:true}); var buf = Graphics.createArrayBuffer(240,120,1,{msb:true});
var lastFix = {fix:0,satellites:0}; var lastFix = {fix:0,satellites:0};
function onGPS(fix) { function onGPS(fix) {
@ -31,3 +30,4 @@ Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
Bangle.on('GPS', onGPS); Bangle.on('GPS', onGPS);
Bangle.setGPSPower(1);

View File

@ -11,8 +11,8 @@ var hrm;
var SPEAKER_PIN = D18; var SPEAKER_PIN = D18;
function freq(f) { function freq(f) {
console.log("frequency: ", f); console.log("frequency: ", f);
if (f===0) digitalWrite(SPEAKER_PIN, 0); if (f===0) digitalWrite(SPEAKER_PIN, 0);
else analogWrite(SPEAKER_PIN, 0.5, {freq: f}); else analogWrite(SPEAKER_PIN, 0.5, {freq: f});
} }

View File

@ -83,8 +83,8 @@ setWatch(function() { // Start/stop
Bangle.beep(); Bangle.beep();
if (started) if (started)
tStart = Date.now()+tStart-tCurrent; tStart = Date.now()+tStart-tCurrent;
tTotal = Date.now()+tTotal-tCurrent; tTotal = Date.now()+tTotal-tCurrent;
tCurrent = Date.now(); tCurrent = Date.now();
if (displayInterval) { if (displayInterval) {
clearInterval(displayInterval); clearInterval(displayInterval);
displayInterval = undefined; displayInterval = undefined;

View File

@ -1,26 +1,26 @@
(function() { (function() {
var clickTimes = []; var clickTimes = [];
var clickPattern = ""; var clickPattern = "";
var TAPS = 4; // number of taps var TAPS = 4; // number of taps
var PERIOD = 1; // seconds var PERIOD = 1; // seconds
// we don't actually create/draw a widget here at all... // we don't actually create/draw a widget here at all...
Bangle.on("lcdPower",function(on) { Bangle.on("lcdPower",function(on) {
// First click (that turns LCD on) isn't given to // First click (that turns LCD on) isn't given to
// setWatch, so handle it here // setWatch, so handle it here
if (!on) return; if (!on) return;
clickTimes=[getTime()]; clickTimes=[getTime()];
clickPattern="x"; clickPattern="x";
}); });
function tap(e,c) { function tap(e,c) {
clickPattern = clickPattern.substr(-3)+c; clickPattern = clickPattern.substr(-3)+c;
while (clickTimes.length>=TAPS) clickTimes.shift(); while (clickTimes.length>=TAPS) clickTimes.shift();
clickTimes.push(e.time); clickTimes.push(e.time);
var clickPeriod = e.time-clickTimes[0]; var clickPeriod = e.time-clickTimes[0];
if (clickPeriod<PERIOD && clickPattern.match(/.313/)) { if (clickPeriod<PERIOD && clickPattern.match(/.313/)) {
load("torch.app.js"); load("torch.app.js");
}
} }
} setWatch(function(e) { tap(e,"1"); }, BTN1, {repeat:true, edge:"rising"});
setWatch(function(e) { tap(e,"1"); }, BTN1, {repeat:true, edge:"rising"}); setWatch(function(e) { tap(e,"3"); }, BTN3, {repeat:true, edge:"rising"});
setWatch(function(e) { tap(e,"3"); }, BTN3, {repeat:true, edge:"rising"});
})(); })();

View File

@ -32,18 +32,18 @@ function getPosition(index){
} }
function getApps(){ function getApps(){
const exit_app = { const exit_app = {
name: 'Exit', name: 'Exit',
special: true special: true
}; };
const raw_apps = Storage.list(/\.info$/).filter(app => app.endsWith('.info')).map(app => Storage.readJSON(app,1) || { name: "DEAD: "+app.substr(1) }) const raw_apps = Storage.list(/\.info$/).filter(app => app.endsWith('.info')).map(app => Storage.readJSON(app,1) || { name: "DEAD: "+app.substr(1) })
.filter(app=>app.type=="app" || app.type=="clock" || !app.type) .filter(app=>app.type=="app" || app.type=="clock" || !app.type)
.sort((a,b)=>{ .sort((a,b)=>{
var n=(0|a.sortorder)-(0|b.sortorder); var n=(0|a.sortorder)-(0|b.sortorder);
if (n) return n; // do sortorder first if (n) return n; // do sortorder first
if (a.name<b.name) return -1; if (a.name<b.name) return -1;
if (a.name>b.name) return 1; if (a.name>b.name) return 1;
return 0; return 0;
}).map(raw => ({ }).map(raw => ({
name: raw.name, name: raw.name,
src: raw.src, src: raw.src,
@ -51,12 +51,12 @@ function getApps(){
version: raw.version version: raw.version
})); }));
const apps = [Object.assign({}, exit_app)].concat(raw_apps); const apps = [Object.assign({}, exit_app)].concat(raw_apps);
apps.push(exit_app); apps.push(exit_app);
return apps.map((app, i) => { return apps.map((app, i) => {
app.x = getPosition(i); app.x = getPosition(i);
return app; return app;
}); });
} }
const APPS = getApps(); const APPS = getApps();
@ -105,8 +105,8 @@ function render(){
//draw icon //draw icon
const icon = app.icon ? const icon = app.icon ?
icons[app.name] ? icons[app.name] : Storage.read(app.icon) icons[app.name] ? icons[app.name] : Storage.read(app.icon)
: null; : null;
if(icon){ if(icon){
icons[app.name] = icon; icons[app.name] = icon;
@ -132,13 +132,13 @@ function render(){
} }
if(settings.highres){ if(settings.highres){
const type = app.type ? app.type : 'App'; const type = app.type ? app.type : 'App';
const version = app.version ? app.version : '0.00'; const version = app.version ? app.version : '0.00';
const info = type+' v'+version; const info = type+' v'+version;
g.setFontAlign(0,1); g.setFontAlign(0,1);
g.setFont('6x8', 1.5); g.setFont('6x8', 1.5);
g.setColor(scale,scale,scale); g.setColor(scale,scale,scale);
g.drawString(info, HALF, 215, { scale: scale }); g.drawString(info, HALF, 215, { scale: scale });
} }
}); });

View File

@ -1,39 +1,39 @@
/* jshint esversion: 6 */ /* jshint esversion: 6 */
const allWords = [ const allWords = [
"ATWENTYD", "ATWENTYD",
"QUARTERY", "QUARTERY",
"FIVEHALF", "FIVEHALF",
"DPASTORO", "DPASTORO",
"FIVEIGHT", "FIVEIGHT",
"SIXTHREE", "SIXTHREE",
"TWELEVEN", "TWELEVEN",
"FOURNINE" "FOURNINE"
]; ];
const hours = { const hours = {
0: ["", 0, 0], 0: ["", 0, 0],
1: ["ONE", 17, 47, 77], 1: ["ONE", 17, 47, 77],
2: ["TWO", 06, 16, 17], 2: ["TWO", 06, 16, 17],
3: ["THREE", 35, 45, 55, 65, 75], 3: ["THREE", 35, 45, 55, 65, 75],
4: ["FOUR", 07, 17, 27, 37], 4: ["FOUR", 07, 17, 27, 37],
5: ["FIVE", 04, 14, 24, 34], 5: ["FIVE", 04, 14, 24, 34],
6: ["SIX", 05, 15, 25], 6: ["SIX", 05, 15, 25],
7: ["SEVEN", 05, 46, 56, 66, 67], 7: ["SEVEN", 05, 46, 56, 66, 67],
8: ["EIGHT", 34, 44, 54, 64, 74], 8: ["EIGHT", 34, 44, 54, 64, 74],
9: ["NINE", 47, 57, 67, 77], 9: ["NINE", 47, 57, 67, 77],
10: ["TEN", 74, 75, 76], 10: ["TEN", 74, 75, 76],
11: ["ELEVEN", 26, 36, 46, 56, 66, 76], 11: ["ELEVEN", 26, 36, 46, 56, 66, 76],
12: ["TWELVE", 06, 16, 26, 36, 56, 66] 12: ["TWELVE", 06, 16, 26, 36, 56, 66]
}; };
const mins = { const mins = {
0: ["A", 0, 0], 0: ["A", 0, 0],
1: ["FIVE", 02, 12, 22, 32], 1: ["FIVE", 02, 12, 22, 32],
2: ["TEN", 10, 30, 40], 2: ["TEN", 10, 30, 40],
3: ["QUARTER", 01, 11, 21, 31, 41, 51, 61], 3: ["QUARTER", 01, 11, 21, 31, 41, 51, 61],
4: ["TWENTY", 10, 20, 30, 40, 50, 60], 4: ["TWENTY", 10, 20, 30, 40, 50, 60],
5: ["HALF", 42, 52, 62, 72], 5: ["HALF", 42, 52, 62, 72],
6: ["PAST", 13, 23, 33, 43], 6: ["PAST", 13, 23, 33, 43],
7: ["TO", 43, 53] 7: ["TO", 43, 53]
}; };
// offsets and incerments // offsets and incerments
@ -49,71 +49,71 @@ const activeColor = 0xF800 /*red*/ ;
function drawWordClock() { function drawWordClock() {
// get time // get time
var t = new Date(); var t = new Date();
var h = t.getHours(); var h = t.getHours();
var m = t.getMinutes(); var m = t.getMinutes();
var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2);
var hidx; var hidx;
var midx; var midx;
var midxA = []; var midxA = [];
g.setFont("6x8",fontSize); g.setFont("6x8",fontSize);
g.setColor(passivColor); g.setColor(passivColor);
g.setFontAlign(0, -1, 0); g.setFontAlign(0, -1, 0);
// draw allWords // draw allWords
var c; var c;
var y = ys; var y = ys;
var x = xs; var x = xs;
allWords.forEach((line) => { allWords.forEach((line) => {
x = xs; x = xs;
for (c in line) { for (c in line) {
g.drawString(line[c], x, y); g.drawString(line[c], x, y);
x += dx; x += dx;
}
y += dy;
});
// calc indexes
midx = Math.round(m / 5);
hidx = h % 12;
if (hidx === 0) { hidx = 12; }
if (midx > 6) {
if (midx == 12) { midx = 0; }
hidx++;
} }
if (midx !== 0) { y += dy;
if (midx <= 6) { });
midxA = [midx, 6];
} else { // calc indexes
midxA = [12 - midx, 7]; midx = Math.round(m / 5);
} hidx = h % 12;
if (hidx === 0) { hidx = 12; }
if (midx > 6) {
if (midx == 12) { midx = 0; }
hidx++;
}
if (midx !== 0) {
if (midx <= 6) {
midxA = [midx, 6];
} else {
midxA = [12 - midx, 7];
} }
}
// write hour in active color // write hour in active color
g.setColor(activeColor); g.setColor(activeColor);
hours[hidx][0].split('').forEach((c, pos) => { hours[hidx][0].split('').forEach((c, pos) => {
x = xs + (hours[hidx][pos + 1] / 10 | 0) * dx; x = xs + (hours[hidx][pos + 1] / 10 | 0) * dx;
y = ys + (hours[hidx][pos + 1] % 10) * dy; y = ys + (hours[hidx][pos + 1] % 10) * dy;
g.drawString(c, x, y); g.drawString(c, x, y);
});
// write min words in active color
midxA.forEach(idx => {
mins[idx][0].split('').forEach((c, pos) => {
x = xs + (mins[idx][pos + 1] / 10 | 0) * dx;
y = ys + (mins[idx][pos + 1] % 10) * dy;
g.drawString(c, x, y);
}); });
});
// write min words in active color // display digital time
midxA.forEach(idx => { g.setColor(activeColor);
mins[idx][0].split('').forEach((c, pos) => { g.clearRect(0, 215, 240, 240);
x = xs + (mins[idx][pos + 1] / 10 | 0) * dx; g.drawString(time, 120, 215);
y = ys + (mins[idx][pos + 1] % 10) * dy;
g.drawString(c, x, y);
});
});
// display digital time
g.setColor(activeColor);
g.clearRect(0, 215, 240, 240);
g.drawString(time, 120, 215);
} }
Bangle.on('lcdPower', function(on) { Bangle.on('lcdPower', function(on) {

View File

@ -87,7 +87,7 @@ var scenes = [
()=>{g.setFont("Vector",36);g.drawString("1",200,40);}, ()=>{g.setFont("Vector",36);g.drawString("1",200,40);},
()=>g.drawString("2",200,120), ()=>g.drawString("2",200,120),
()=>g.drawString("3",200,200) ()=>g.drawString("3",200,200)
],200); ],200);
}, },
function() { function() {
g.reset(); g.reset();
@ -138,15 +138,15 @@ var scenes = [
var x = 120, y = 10, h=21; var x = 120, y = 10, h=21;
animate([ animate([
()=>{g.drawString("Bangle.js has a",x,y+=h); ()=>{g.drawString("Bangle.js has a",x,y+=h);
g.drawString("simple touchscreen",x,y+=h);}, g.drawString("simple touchscreen",x,y+=h);},
0,0, 0,0,
()=>{g.drawString("It'll detect touch",x,y+=h*2); ()=>{g.drawString("It'll detect touch",x,y+=h*2);
g.drawString("on left and right",x,y+=h);}, g.drawString("on left and right",x,y+=h);},
0,0, 0,0,
()=>{g.drawString("Horizontal swipes",x,y+=h*2); ()=>{g.drawString("Horizontal swipes",x,y+=h*2);
g.drawString("work too. Try now",x,y+=h); g.drawString("work too. Try now",x,y+=h);
g.drawString("to change page.",x,y+=h);} g.drawString("to change page.",x,y+=h);}
],300); ],300);
}, },
function() { function() {
g.reset(); g.reset();
@ -156,15 +156,15 @@ var scenes = [
var x = 120, y = 10, h=21; var x = 120, y = 10, h=21;
animate([ animate([
()=>{g.drawString("Bangle.js",x,y+=h); ()=>{g.drawString("Bangle.js",x,y+=h);
g.drawString("comes with",x,y+=h); g.drawString("comes with",x,y+=h);
g.drawString("a few simple",x,y+=h); g.drawString("a few simple",x,y+=h);
g.drawString("apps installed",x,y+=h);}, g.drawString("apps installed",x,y+=h);},
0,0, 0,0,
()=>{g.drawString("To add more, visit",x,y+=h*2); ()=>{g.drawString("To add more, visit",x,y+=h*2);
g.drawString("banglejs.com/apps",x,y+=h); g.drawString("banglejs.com/apps",x,y+=h);
g.drawString("with a Bluetooth",x,y+=h); g.drawString("with a Bluetooth",x,y+=h);
g.drawString("capable device",x,y+=h);}, g.drawString("capable device",x,y+=h);},
],400); ],400);
}, },
function() { function() {
g.reset(); g.reset();
@ -186,9 +186,9 @@ var scenes = [
rx += 0.1; rx += 0.1;
ry += 0.11; ry += 0.11;
var rcx=Math.cos(rx), var rcx=Math.cos(rx),
rsx=Math.sin(rx), rsx=Math.sin(rx),
rcy=Math.cos(ry), rcy=Math.cos(ry),
rsy=Math.sin(ry); rsy=Math.sin(ry);
// Project 3D coordinates into 2D // Project 3D coordinates into 2D
function p(x,y,z) { function p(x,y,z) {
var t; var t;
@ -240,10 +240,10 @@ var scenes = [
animate([ animate([
()=>g.drawString("That's it!",x,y+=h), ()=>g.drawString("That's it!",x,y+=h),
()=>{g.drawString("Press",x,y+=h*3); ()=>{g.drawString("Press",x,y+=h*3);
g.drawString("Button 2",x,y+=h); g.drawString("Button 2",x,y+=h);
g.drawString("to start",x,y+=h); g.drawString("to start",x,y+=h);
g.drawString("Bangle.js",x,y+=h);} g.drawString("Bangle.js",x,y+=h);}
],400); ],400);
} }
]; ];

View File

@ -1,43 +1,43 @@
(function(){ (function(){
var CHARGING = 0x07E0; var CHARGING = 0x07E0;
function setWidth() { function setWidth() {
WIDGETS["bat"].width = 40 + (Bangle.isCharging()?16:0); WIDGETS["bat"].width = 40 + (Bangle.isCharging()?16:0);
}
function draw() {
var s = 39;
var x = this.x, y = this.y;
if (Bangle.isCharging()) {
g.setColor(CHARGING).drawImage(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y);
x+=16;
} }
g.setColor(-1); function draw() {
g.fillRect(x,y+2,x+s-4,y+21); var s = 39;
g.clearRect(x+2,y+4,x+s-6,y+19); var x = this.x, y = this.y;
g.fillRect(x+s-3,y+10,x+s,y+14); if (Bangle.isCharging()) {
g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17); g.setColor(CHARGING).drawImage(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y);
g.setColor(-1); x+=16;
} }
Bangle.on('charging',function(charging) { g.setColor(-1);
if(charging) Bangle.buzz(); g.fillRect(x,y+2,x+s-4,y+21);
g.clearRect(x+2,y+4,x+s-6,y+19);
g.fillRect(x+s-3,y+10,x+s,y+14);
g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17);
g.setColor(-1);
}
Bangle.on('charging',function(charging) {
if(charging) Bangle.buzz();
setWidth();
Bangle.drawWidgets(); // relayout widgets
g.flip();
});
var batteryInterval;
Bangle.on('lcdPower', function(on) {
if (on) {
WIDGETS["bat"].draw();
// refresh once a minute if LCD on
if (!batteryInterval)
batteryInterval = setInterval(()=>WIDGETS["bat"].draw(), 60000);
} else {
if (batteryInterval) {
clearInterval(batteryInterval);
batteryInterval = undefined;
}
}
});
WIDGETS["bat"]={area:"tr",width:40,draw:draw};
setWidth(); setWidth();
Bangle.drawWidgets(); // relayout widgets
g.flip();
});
var batteryInterval;
Bangle.on('lcdPower', function(on) {
if (on) {
WIDGETS["bat"].draw();
// refresh once a minute if LCD on
if (!batteryInterval)
batteryInterval = setInterval(()=>WIDGETS["bat"].draw(), 60000);
} else {
if (batteryInterval) {
clearInterval(batteryInterval);
batteryInterval = undefined;
}
}
});
WIDGETS["bat"]={area:"tr",width:40,draw:draw};
setWidth();
})() })()

View File

@ -52,8 +52,8 @@
const newIndex = (oldIndex + 1) % COLORS.length const newIndex = (oldIndex + 1) % COLORS.length
s.color = COLORS[newIndex] s.color = COLORS[newIndex]
save('color')(s.color) save('color')(s.color)
} }
}, },
'Hide if >': { 'Hide if >': {
value: s.hideifmorethan||100, value: s.hideifmorethan||100,
min: 10, min: 10,
@ -61,7 +61,7 @@
step: 10, step: 10,
format: x => x+"%", format: x => x+"%",
onchange: save('hideifmorethan'), onchange: save('hideifmorethan'),
}, },
} }
E.showMenu(menu) E.showMenu(menu)
}) })

View File

@ -1,140 +1,140 @@
(function(){ (function(){
const COLORS = { const COLORS = {
'white': -1, 'white': -1,
'charging': 0x07E0, // "Green" 'charging': 0x07E0, // "Green"
'high': 0x05E0, // slightly darker green 'high': 0x05E0, // slightly darker green
'ok': 0xFD20, // "Orange" 'ok': 0xFD20, // "Orange"
'low':0xF800, // "Red" 'low':0xF800, // "Red"
} }
const SETTINGS_FILE = 'widbatpc.json' const SETTINGS_FILE = 'widbatpc.json'
let settings let settings
function loadSettings() { function loadSettings() {
settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {} settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}
const DEFAULTS = { const DEFAULTS = {
'color': 'By Level', 'color': 'By Level',
'percentage': true, 'percentage': true,
'charger': true, 'charger': true,
'hideifmorethan': 100, 'hideifmorethan': 100,
}; };
Object.keys(DEFAULTS).forEach(k=>{ Object.keys(DEFAULTS).forEach(k=>{
if (settings[k]===undefined) settings[k]=DEFAULTS[k] if (settings[k]===undefined) settings[k]=DEFAULTS[k]
}); });
} }
function setting(key) { function setting(key) {
if (!settings) { loadSettings() } if (!settings) { loadSettings() }
return settings[key]; return settings[key];
} }
const levelColor = (l) => { const levelColor = (l) => {
// "charging" is very bright -> percentage is hard to read, "high" is ok(ish) // "charging" is very bright -> percentage is hard to read, "high" is ok(ish)
const green = setting('percentage') ? COLORS.high : COLORS.charging const green = setting('percentage') ? COLORS.high : COLORS.charging
switch (setting('color')) { switch (setting('color')) {
case 'Monochrome': return COLORS.white; // no chance of reading the percentage here :-( case 'Monochrome': return COLORS.white; // no chance of reading the percentage here :-(
case 'Green': return green; case 'Green': return green;
case 'By Level': // fall through case 'By Level': // fall through
default: default:
if (setting('charger')) { if (setting('charger')) {
// charger icon -> always make percentage readable // charger icon -> always make percentage readable
if (Bangle.isCharging() || l >= 50) return green; if (Bangle.isCharging() || l >= 50) return green;
} else { } else {
// no icon -> brightest green to indicate charging, even when showing percentage // no icon -> brightest green to indicate charging, even when showing percentage
if (Bangle.isCharging()) return COLORS.charging; if (Bangle.isCharging()) return COLORS.charging;
if (l >= 50) return COLORS.high; if (l >= 50) return COLORS.high;
} }
if (l >= 15) return COLORS.ok; if (l >= 15) return COLORS.ok;
return COLORS.low; return COLORS.low;
}
} }
} const chargerColor = () => {
const chargerColor = () => { return (setting('color') === 'Monochrome') ? COLORS.white : COLORS.charging
return (setting('color') === 'Monochrome') ? COLORS.white : COLORS.charging }
} // sets width, returns true if it changed
// sets width, returns true if it changed function setWidth() {
function setWidth() { var w = 40;
var w = 40; if (Bangle.isCharging() && setting('charger'))
if (Bangle.isCharging() && setting('charger')) w += 16;
w += 16; if (E.getBattery() > setting('hideifmorethan'))
if (E.getBattery() > setting('hideifmorethan')) w = 0;
w = 0; var changed = WIDGETS["batpc"].width != w;
var changed = WIDGETS["batpc"].width != w; WIDGETS["batpc"].width = w;
WIDGETS["batpc"].width = w; return changed;
return changed; }
} function draw() {
function draw() {
// if hidden, don't draw // if hidden, don't draw
if (!WIDGETS["batpc"].width) return; if (!WIDGETS["batpc"].width) return;
// else... // else...
var s = 39; var s = 39;
var x = this.x, y = this.y; var x = this.x, y = this.y;
const l = E.getBattery(), const l = E.getBattery(),
c = levelColor(l); c = levelColor(l);
const xl = x+4+l*(s-12)/100 const xl = x+4+l*(s-12)/100
if (Bangle.isCharging() && setting('charger')) { if (Bangle.isCharging() && setting('charger')) {
g.setColor(chargerColor()).drawImage(atob( g.setColor(chargerColor()).drawImage(atob(
"DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); "DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y);
x+=16; x+=16;
} }
g.setColor(-1); g.setColor(-1);
g.fillRect(x,y+2,x+s-4,y+21); g.fillRect(x,y+2,x+s-4,y+21);
g.clearRect(x+2,y+4,x+s-6,y+19); g.clearRect(x+2,y+4,x+s-6,y+19);
g.fillRect(x+s-3,y+10,x+s,y+14); g.fillRect(x+s-3,y+10,x+s,y+14);
g.setColor(c).fillRect(x+4,y+6,xl,y+17); g.setColor(c).fillRect(x+4,y+6,xl,y+17);
g.setColor(-1); g.setColor(-1);
if (!setting('percentage')) { if (!setting('percentage')) {
return; return;
} }
let gfx = g let gfx = g
if (setting('color') === 'Monochrome') { if (setting('color') === 'Monochrome') {
// draw text inverted on battery level // draw text inverted on battery level
gfx = Graphics.createCallback(240, 240, 1, gfx = Graphics.createCallback(240, 240, 1,
(x,y) => {g.setPixel(x,y,x<=xl?0:-1)}) (x,y) => {g.setPixel(x,y,x<=xl?0:-1)})
}
gfx.setFontAlign(-1,-1);
if (l >= 100) {
gfx.setFont('4x6', 2);
gfx.drawString(l, x + 6, y + 7);
} else {
if (l < 10) x+=6;
gfx.setFont('6x8', 2);
gfx.drawString(l, x + 6, y + 4);
}
} }
gfx.setFontAlign(-1,-1); // reload widget, e.g. when settings have changed
if (l >= 100) { function reload() {
gfx.setFont('4x6', 2); loadSettings()
gfx.drawString(l, x + 6, y + 7); // need to redraw all widgets, because changing the "charger" setting
} else { // can affect the width and mess with the whole widget layout
if (l < 10) x+=6; setWidth()
gfx.setFont('6x8', 2); g.clear();
gfx.drawString(l, x + 6, y + 4); Bangle.drawWidgets();
}
// update widget - redraw just widget, or all widgets if size changed
function update() {
if (setWidth()) Bangle.drawWidgets();
else WIDGETS["batpc"].draw();
} }
}
// reload widget, e.g. when settings have changed
function reload() {
loadSettings()
// need to redraw all widgets, because changing the "charger" setting
// can affect the width and mess with the whole widget layout
setWidth()
g.clear();
Bangle.drawWidgets();
}
// update widget - redraw just widget, or all widgets if size changed
function update() {
if (setWidth()) Bangle.drawWidgets();
else WIDGETS["batpc"].draw();
}
Bangle.on('charging',function(charging) { Bangle.on('charging',function(charging) {
if(charging) Bangle.buzz(); if(charging) Bangle.buzz();
update(); update();
g.flip(); g.flip();
}); });
var batteryInterval; var batteryInterval;
Bangle.on('lcdPower', function(on) { Bangle.on('lcdPower', function(on) {
if (on) { if (on) {
update(); update();
// refresh once a minute if LCD on // refresh once a minute if LCD on
if (!batteryInterval) if (!batteryInterval)
batteryInterval = setInterval(update, 60000); batteryInterval = setInterval(update, 60000);
} else { } else {
if (batteryInterval) { if (batteryInterval) {
clearInterval(batteryInterval); clearInterval(batteryInterval);
batteryInterval = undefined; batteryInterval = undefined;
} }
} }
}); });
WIDGETS["batpc"]={area:"tr",width:40,draw:draw,reload:reload}; WIDGETS["batpc"]={area:"tr",width:40,draw:draw,reload:reload};
setWidth(); setWidth();
})() })()

View File

@ -1,19 +1,19 @@
(function(){ (function(){
var img_bt = E.toArrayBuffer(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==")); var img_bt = E.toArrayBuffer(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="));
function draw() { function draw() {
g.reset(); g.reset();
if (NRF.getSecurityStatus().connected) if (NRF.getSecurityStatus().connected)
g.setColor(0,0.5,1); g.setColor(0,0.5,1);
else else
g.setColor(0.3,0.3,0.3); g.setColor(0.3,0.3,0.3);
g.drawImage(img_bt,10+this.x,2+this.y); g.drawImage(img_bt,10+this.x,2+this.y);
} }
function changed() { function changed() {
WIDGETS["bluetooth"].draw(); WIDGETS["bluetooth"].draw();
g.flip();// turns screen on g.flip();// turns screen on
} }
NRF.on('connect',changed); NRF.on('connect',changed);
NRF.on('disconnect',changed); NRF.on('disconnect',changed);
WIDGETS["bluetooth"]={area:"tr",width:24,draw:draw}; WIDGETS["bluetooth"]={area:"tr",width:24,draw:draw};
})() })()

View File

@ -1,27 +1,27 @@
(() => { (() => {
let intervalRef = null; let intervalRef = null;
var width = 5 * 6*2 var width = 5 * 6*2
function draw() { function draw() {
g.reset().setFont("6x8", 2).setFontAlign(-1, 0); g.reset().setFont("6x8", 2).setFontAlign(-1, 0);
var time = require("locale").time(new Date(),1); var time = require("locale").time(new Date(),1);
g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60
}
function clearTimers(){
if(intervalRef) {
clearInterval(intervalRef);
intervalRef = null;
} }
function clearTimers(){ }
if(intervalRef) { function startTimers(){
clearInterval(intervalRef); intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000);
intervalRef = null; WIDGETS["wdclk"].draw();
} }
} Bangle.on('lcdPower', (on) => {
function startTimers(){ clearTimers();
intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); if (on) startTimers();
WIDGETS["wdclk"].draw(); });
}
Bangle.on('lcdPower', (on) => {
clearTimers();
if (on) startTimers();
});
WIDGETS["wdclk"]={area:"tr",width:width,draw:draw}; WIDGETS["wdclk"]={area:"tr",width:width,draw:draw};
if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000);
})() })()

View File

@ -5,7 +5,7 @@
function draw() { function draw() {
var width = 24; var width = 24;
g.reset(); g.reset();
g.setFont("6x8", 1); g.setFont("6x8", 1);
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
g.clearRect(this.x,this.y+15,this.x+width,this.y+23); // erase background g.clearRect(this.x,this.y+15,this.x+width,this.y+23); // erase background

View File

@ -1,23 +1,23 @@
/* jshint esversion: 6 */ /* jshint esversion: 6 */
(() => { (() => {
var icon = require("heatshrink").decompress(atob("jEYwIKHgwCBhwCBh4CEggPCkACBmAXDBwVZ+EB+F4gEsjl8EgMP+EChk/gEMh+ehkA+YIBxwxBnF/4HggH/wEAj0AA==")); var icon = require("heatshrink").decompress(atob("jEYwIKHgwCBhwCBh4CEggPCkACBmAXDBwVZ+EB+F4gEsjl8EgMP+EChk/gEMh+ehkA+YIBxwxBnF/4HggH/wEAj0AA=="));
var color = 0x4A69; var color = 0x4A69;
function draw() { function draw() {
g.reset().setColor(color).drawImage(icon, this.x + 1, 0); g.reset().setColor(color).drawImage(icon, this.x + 1, 0);
} }
WIDGETS["widhwt"] = { area: "tr", width: 26, draw: draw }; WIDGETS["widhwt"] = { area: "tr", width: 26, draw: draw };
Bangle.on('swipe', function() { Bangle.on('swipe', function() {
color = 0x41f; color = 0x41f;
Bangle.buzz(); Bangle.buzz();
Bangle.drawWidgets(); Bangle.drawWidgets();
setTimeout(() => { setTimeout(() => {
color = 0x4A69; color = 0x4A69;
Bangle.buzz(1E3, 1); Bangle.buzz(1E3, 1);
Bangle.drawWidgets(); Bangle.drawWidgets();
}, 35E3); }, 35E3);
}); });
})(); })();

View File

@ -1,12 +1,12 @@
/* jshint esversion: 6 */ /* jshint esversion: 6 */
(() => { (() => {
var id = NRF.getAddress().substr().substr(12).split(":"); var id = NRF.getAddress().substr().substr(12).split(":");
// draw your widget at xpos // draw your widget at xpos
function draw() { function draw() {
g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); g.reset().setColor(0, 0.5, 1).setFont("6x8", 1);
g.drawString(id[0], this.x+2, this.y+4, true); g.drawString(id[0], this.x+2, this.y+4, true);
g.drawString(id[1], this.x+2, this.y+14, true); g.drawString(id[1], this.x+2, this.y+14, true);
} }
WIDGETS["widid"] = { area:"tr", width:16, draw: draw }; WIDGETS["widid"] = { area:"tr", width:16, draw: draw };
})(); })();

View File

@ -1,33 +1,33 @@
/* jshint esversion: 6 */ /* jshint esversion: 6 */
(() => { (() => {
const BLACK = 0, MOON = 0x41f, MC = 29.5305882, NM = 694039.09; const BLACK = 0, MOON = 0x41f, MC = 29.5305882, NM = 694039.09;
var r = 12, mx = 0, my = 0; var r = 12, mx = 0, my = 0;
var moon = { var moon = {
0: () => { g.reset().setColor(BLACK).fillRect(mx - r, my - r, mx + r, my + r);}, 0: () => { g.reset().setColor(BLACK).fillRect(mx - r, my - r, mx + r, my + r);},
1: () => { moon[0](); g.setColor(MOON).drawCircle(mx, my, r);}, 1: () => { moon[0](); g.setColor(MOON).drawCircle(mx, my, r);},
2: () => { moon[3](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, 2: () => { moon[3](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);},
3: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx - r, my - r, mx, my + r);}, 3: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx - r, my - r, mx, my + r);},
4: () => { moon[3](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, 4: () => { moon[3](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);},
5: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r);}, 5: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r);},
6: () => { moon[7](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, 6: () => { moon[7](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);},
7: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx, my - r, mx + r + r, my + r);}, 7: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx, my - r, mx + r + r, my + r);},
8: () => { moon[7](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);} 8: () => { moon[7](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}
}; };
function moonPhase(d) { function moonPhase(d) {
var tmp, month = d.getMonth(), year = d.getFullYear(), day = d.getDate(); var tmp, month = d.getMonth(), year = d.getFullYear(), day = d.getDate();
if (month < 3) {year--; month += 12;} if (month < 3) {year--; month += 12;}
tmp = ((365.25 * year + 30.6 * ++month + day - NM) / MC); tmp = ((365.25 * year + 30.6 * ++month + day - NM) / MC);
return Math.round(((tmp - (tmp | 0)) * 7)+1); return Math.round(((tmp - (tmp | 0)) * 7)+1);
} }
function draw() { function draw() {
mx = this.x; my = this.y + 12; mx = this.x; my = this.y + 12;
moon[moonPhase(Date())](); moon[moonPhase(Date())]();
} }
WIDGETS["widmoon"] = { area: "tr", width: 24, draw: draw }; WIDGETS["widmoon"] = { area: "tr", width: 24, draw: draw };
})(); })();

View File

@ -1,7 +1,7 @@
(() => { (() => {
function draw() { function draw() {
g.reset(); g.reset();
var m = process.memory(); var m = process.memory();
var pc = Math.round(m.usage*100/m.total); var pc = Math.round(m.usage*100/m.total);
g.drawImage(atob("BwgBqgP////AVQ=="), this.x+(24-7)/2, this.y+4); g.drawImage(atob("BwgBqgP////AVQ=="), this.x+(24-7)/2, this.y+4);
g.setColor(pc>70 ? "#ff0000" : (pc>50 ? "#ffff00" : "#ffffff")); g.setColor(pc>70 ? "#ff0000" : (pc>50 ? "#ffff00" : "#ffffff"));
@ -10,14 +10,14 @@
var ramInterval; var ramInterval;
Bangle.on('lcdPower', function(on) { Bangle.on('lcdPower', function(on) {
if (on) { if (on) {
WIDGETS["ram"].draw(); WIDGETS["ram"].draw();
if (!ramInterval) ramInterval = setInterval(()=>WIDGETS["ram"].draw(), 10000); if (!ramInterval) ramInterval = setInterval(()=>WIDGETS["ram"].draw(), 10000);
} else { } else {
if (ramInterval) { if (ramInterval) {
clearInterval(ramInterval); clearInterval(ramInterval);
ramInterval = undefined; ramInterval = undefined;
} }
} }
}); });
WIDGETS["ram"]={area:"tl",width: 24,draw:draw}; WIDGETS["ram"]={area:"tl",width: 24,draw:draw};
})() })()

Some files were not shown because too many files have changed in this diff Show More