diff --git a/.gitignore b/.gitignore index a9398e871..f4588ac6f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ tests/Layout/testresult.bmp apps.local.json _site .jekyll-cache +.owncloudsync.log +Desktop.ini +.sync_*.db* diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index aa174b2d2..aa6672a4f 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -149,11 +149,11 @@ function drawHSeg(x1,y1,x2,y2,Num,Color,Size) { if (Color == "fg") { g.setColor(g.theme.fg); } else { - g.setColor(mColor[0],mColor[1],mColor[2]); + g.setColor(mColor[0],mColor[1],mColor[2]); } g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,Size); } else { - g.setColor(bColor[0],bColor[1],bColor[2]); + g.setColor(bColor[0],bColor[1],bColor[2]); g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,1); } } @@ -166,7 +166,7 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { for (let j = 1; j < 8; j++) { if (Font[Num][j-1][i-1] == 1) { if (Color == "fg") { - g.setColor(sColor[0],sColor[1],sColor[2]); + g.setColor(sColor[0],sColor[1],sColor[2]); } else { g.setColor(g.theme.fg); //g.setColor(0.7,0.7,0.7); @@ -253,8 +253,8 @@ function actions(v){ if(BTN1.read() === true) { print("BTN pressed"); Bangle.showLauncher(); - } - + } + if(v==-1){ print("up swipe event"); if(settings.swupApp != "") load(settings.swupApp); @@ -269,7 +269,7 @@ function actions(v){ } // Get Messages status -var messages = require("Storage").readJSON("messages.json",1)||[]; +var messages_installed = require("Storage").read("messages") !== undefined; //var BTconnected = NRF.getSecurityStatus().connected; //NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected); @@ -289,27 +289,27 @@ function drawWidgeds() { g.setColor((g.getBPP()>8) ? "#07f" : (g.theme.dark ? "#0ff" : "#00f")); else g.setColor(g.theme.dark ? "#666" : "#999"); - g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),x1Bt,y1Bt); + g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),x1Bt,y1Bt); + - //Battery //print(E.getBattery()); //print(Bangle.isCharging()); - + var x1B = 130; var y1B = 2; var x2B = x1B + 20; var y2B = y1B + 15; - + g.setColor(g.theme.bg); g.clearRect(x1B,y1B,x2B,y2B); - + g.setColor(g.theme.fg); g.drawRect(x1B,y1B,x2B,y2B); g.fillRect(x1B,y1B,x1B+(E.getBattery()*(x2B-x1B)/100),y2B); g.fillRect(x2B,y1B+(y2B-y1B)/2-3,x2B+4,y1B+(y2B-y1B)/2+3); - + //Messages @@ -318,25 +318,25 @@ function drawWidgeds() { var x2M = x1M + 25; var y2M = y2B; - if (messages.some(m=>m.new)) { + if (messages_installed && require("messages").status() == "new") { g.setColor(g.theme.fg); g.fillRect(x1M,y1M,x2M,y2M); g.setColor(g.theme.bg); g.drawLine(x1M,y1M,x1M+(x2M-x1M)/2,y1M+(y2M-y1M)/2); g.drawLine(x1M+(x2M-x1M)/2,y1M+(y2M-y1M)/2,x2M,y1M); } - + var strDow = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; var d = new Date(); var dow = d.getDay(),day = d.getDate(), month = d.getMonth() + 1, year = d.getFullYear(); print(strDow[dow] + ' ' + day + '.' + month + ' ' + year); - + g.setColor(g.theme.fg); g.setFontAlign(-1, -1,0); g.setFont("Vector", 20); g.drawString(strDow[dow] + ' ' + day, 0, 0, true); - + } @@ -354,7 +354,7 @@ function SetFull(on) { } else { Ys = 30; Bangle.setUI("updown",actions); - Bangle.on('swipe', function(direction) { + Bangle.on('swipe', function(direction) { switch (direction) { case 1: print("swipe left event"); @@ -362,7 +362,7 @@ function SetFull(on) { print(settings.swleftApp); break; case -1: - print("swipe right event"); + print("swipe right event"); if(settings.swrightApp != "") load(settings.swrightApp); print(settings.swrightApp); break; @@ -374,7 +374,7 @@ function SetFull(on) { SegH = (Ye-Ys)/2; Dy = SegH/16; - + draw(); if (on != true) { diff --git a/apps/7x7dotsclock/ChangeLog b/apps/7x7dotsclock/ChangeLog index d2c98a472..5e8e48b0b 100644 --- a/apps/7x7dotsclock/ChangeLog +++ b/apps/7x7dotsclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: Initial version for upload -0.02: better theme support, configurable colors, small improvements +0.02: Better theme support, configurable colors, small improvements +0.03: Use `messages` library to check for new messages \ No newline at end of file diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 41f0836d3..ba1996544 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -1,7 +1,7 @@ { "id": "7x7dotsclock", "name": "7x7 Dots Clock", "shortName":"7x7 Dots Clock", - "version":"0.02", + "version":"0.03", "description": "A clock with a big 7x7 dots Font", "icon": "dotsfontclock.png", "tags": "clock", diff --git a/apps/90sclk/ChangeLog b/apps/90sclk/ChangeLog index feb008f5f..057d6ff73 100644 --- a/apps/90sclk/ChangeLog +++ b/apps/90sclk/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! -0.02: Fullscreen settings. \ No newline at end of file +0.02: Fullscreen settings. +0.03: Tell clock widgets to hide. diff --git a/apps/90sclk/app.js b/apps/90sclk/app.js index 6babbfec2..351c235e0 100644 --- a/apps/90sclk/app.js +++ b/apps/90sclk/app.js @@ -115,6 +115,9 @@ function draw() { } } +// Show launcher when middle button pressed +Bangle.setUI("clock"); + Bangle.loadWidgets(); // Clear the screen once, at startup @@ -140,5 +143,3 @@ Bangle.on('lock', function(isLocked) { }); -// Show launcher when middle button pressed -Bangle.setUI("clock"); diff --git a/apps/90sclk/metadata.json b/apps/90sclk/metadata.json index fb2824a6f..59b627427 100644 --- a/apps/90sclk/metadata.json +++ b/apps/90sclk/metadata.json @@ -1,7 +1,7 @@ { "id": "90sclk", "name": "90s Clock", - "version": "0.02", + "version": "0.03", "description": "A 90s style watch-face", "readme": "README.md", "icon": "app.png", diff --git a/apps/a_dndtoggle/ChangeLog b/apps/a_dndtoggle/ChangeLog new file mode 100644 index 000000000..ec66c5568 --- /dev/null +++ b/apps/a_dndtoggle/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version diff --git a/apps/a_dndtoggle/README.md b/apps/a_dndtoggle/README.md new file mode 100644 index 000000000..bd0981c5b --- /dev/null +++ b/apps/a_dndtoggle/README.md @@ -0,0 +1,13 @@ +# a_dndtoggle - Toggle Quiet Mode of the watch + +When Quiet mode is off, just start this app to set quiet mode. Start it again to turn off quiet mode. +Work in progress. + +#ToDo +Settings page, current status indicator. + +## Creator + +Hank - contact at http://forum.espruino.com + + diff --git a/apps/a_dndtoggle/a_dndtoggle.app.js b/apps/a_dndtoggle/a_dndtoggle.app.js new file mode 100644 index 000000000..c0b968f2c --- /dev/null +++ b/apps/a_dndtoggle/a_dndtoggle.app.js @@ -0,0 +1,43 @@ + +const modeNames = [/*LANG*/"Noisy", /*LANG*/"Alarms", /*LANG*/"Silent"]; +let bSettings = require('Storage').readJSON('setting.json',true)||{}; +let current = 0|bSettings.quiet; +//0 off +//1 alarms +//2 silent + +console.log("old: " + current); + +switch (current) { + case 0: + bSettings.quiet = 2; + Bangle.buzz(); + setTimeout('Bangle.buzz();',500); + break; + case 1: + bSettings.quiet = 0; + Bangle.buzz(); + break; + case 2: + bSettings.quiet = 0; + Bangle.buzz(); + break; + default: + bSettings.quiet = 0; + Bangle.buzz(); +} + +console.log("new: " + bSettings.quiet); + +E.showMessage(modeNames[current] + " -> " + modeNames[bSettings.quiet]); +setTimeout('exitApp();', 2000); + + +function exitApp(){ + +require("Storage").writeJSON("setting.json", bSettings); +// reload clocks with new theme, otherwise just wait for user to switch apps + +load() + +} \ No newline at end of file diff --git a/apps/a_dndtoggle/a_dndtoggle.png b/apps/a_dndtoggle/a_dndtoggle.png new file mode 100644 index 000000000..4c8b74c0c Binary files /dev/null and b/apps/a_dndtoggle/a_dndtoggle.png differ diff --git a/apps/a_dndtoggle/app-icon.js b/apps/a_dndtoggle/app-icon.js new file mode 100644 index 000000000..0b08cc65b --- /dev/null +++ b/apps/a_dndtoggle/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwJC/AAl/Agf/AAUAgIFDwEHAofgh/g/0Ag/wj+AnwVB/EegEfEIN4nkAh+AgE8vgVBAoV4Aoce/EAgfADQIFcjwpFHYIFCnxBFJopZBn5ZCMopxFPoqJFSowA/gA=")) \ No newline at end of file diff --git a/apps/a_dndtoggle/metadata.json b/apps/a_dndtoggle/metadata.json new file mode 100644 index 000000000..f5ae9cc31 --- /dev/null +++ b/apps/a_dndtoggle/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "a_dndtoggle", + "name": "a_dndtoggle - Toggle Quiet Mode of the watch", + "shortName": "A_DND Toggle", + "version": "0.01", + "description": "Toggle Quiet Mode of the watch just by starting this app.", + "icon": "a_dndtoggle.png", + "type": "app", + "tags": "tool", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"a_dndtoggle.app.js","url":"a_dndtoggle.app.js"}, + {"name":"a_dndtoggle.img","url":"app-icon.js","evaluate":true} + ], + "readme": "README.md" +} diff --git a/apps/about/ChangeLog b/apps/about/ChangeLog index f5638fdd2..ffe9de081 100644 --- a/apps/about/ChangeLog +++ b/apps/about/ChangeLog @@ -10,3 +10,4 @@ 0.10: Added separate Bangle.js 2 file with Bangle.js 2 kickstarter pixels (as of 28 Oct 2021) 0.11: Bangle.js2: New pixels, btn1 to exit 0.12: Actual pixels as of 29th Nov 2021 +0.13: Bangle.js 2: Use setUI to add software back button diff --git a/apps/about/app-bangle2.js b/apps/about/app-bangle2.js index 978d36193..0c40314a8 100644 --- a/apps/about/app-bangle2.js +++ b/apps/about/app-bangle2.js @@ -69,4 +69,7 @@ function drawImage() { // TODO: a nice little animation before setTimeout(drawInfo, 1000); -setWatch(_=>load(), BTN1); +Bangle.setUI({ + mode : "custom", + back : load +}); diff --git a/apps/about/metadata.json b/apps/about/metadata.json index 6c22bdc56..648576576 100644 --- a/apps/about/metadata.json +++ b/apps/about/metadata.json @@ -1,7 +1,7 @@ { "id": "about", "name": "About", - "version": "0.12", + "version": "0.13", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "icon": "app.png", "tags": "tool,system", diff --git a/apps/activityreminder/ChangeLog b/apps/activityreminder/ChangeLog index 37820dce6..3811425ac 100644 --- a/apps/activityreminder/ChangeLog +++ b/apps/activityreminder/ChangeLog @@ -6,3 +6,5 @@ 0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night 0.07: Fix bug on the cutting edge firmware 0.08: Use default Bangle formatter for booleans +0.09: New app screen (instead of showing settings or the alert) and some optimisations +0.10: Add software back button via setUI diff --git a/apps/activityreminder/alert.js b/apps/activityreminder/alert.js new file mode 100644 index 000000000..96a9b76c4 --- /dev/null +++ b/apps/activityreminder/alert.js @@ -0,0 +1,37 @@ +(function () { + // load variable before defining functions cause it can trigger a ReferenceError + const activityreminder = require("activityreminder"); + const storage = require("Storage"); + let activityreminder_data = activityreminder.loadData(); + + function run() { + E.showPrompt("Inactivity detected", { + title: "Activity reminder", + buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 } + }).then(function (v) { + if (v == 1) { + activityreminder_data.okDate = new Date(); + } + if (v == 2) { + activityreminder_data.dismissDate = new Date(); + } + if (v == 3) { + activityreminder_data.pauseDate = new Date(); + } + activityreminder.saveData(activityreminder_data); + load(); + }); + + // Obey system quiet mode: + if (!(storage.readJSON('setting.json', 1) || {}).quiet) { + Bangle.buzz(400); + } + setTimeout(load, 20000); + } + + g.clear(); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + run(); + +})(); \ No newline at end of file diff --git a/apps/activityreminder/app.js b/apps/activityreminder/app.js index c2b626fb3..81e10d8dd 100644 --- a/apps/activityreminder/app.js +++ b/apps/activityreminder/app.js @@ -1,46 +1,58 @@ (function () { - // load variable before defining functions cause it can trigger a ReferenceError - const activityreminder = require("activityreminder"); - const storage = require("Storage"); - const activityreminder_settings = activityreminder.loadSettings(); - let activityreminder_data = activityreminder.loadData(); + // load variable before defining functions cause it can trigger a ReferenceError + const activityreminder = require("activityreminder"); + let activityreminder_data = activityreminder.loadData(); + let W = g.getWidth(); + // let H = g.getHeight(); - function drawAlert() { - E.showPrompt("Inactivity detected", { - title: "Activity reminder", - buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 } - }).then(function (v) { - if (v == 1) { - activityreminder_data.okDate = new Date(); - } - if (v == 2) { - activityreminder_data.dismissDate = new Date(); - } - if (v == 3) { - activityreminder_data.pauseDate = new Date(); - } - activityreminder.saveData(activityreminder_data); - load(); - }); - - // Obey system quiet mode: - if (!(storage.readJSON('setting.json', 1) || {}).quiet) { - Bangle.buzz(400); - } - setTimeout(load, 20000); - } - - function run() { - if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) { - drawAlert(); - } else { - eval(storage.read("activityreminder.settings.js"))(() => load()); - } - } + function getHoursMins(date){ + var h = date.getHours(); + var m = date.getMinutes(); + return (""+h).substr(-2) + ":" + ("0"+m).substr(-2); + } + function drawData(name, value, y){ + g.drawString(name, 10, y); + g.drawString(value, 100, y); + } + + function drawInfo() { + var h=18, y = h; + g.setColor(g.theme.fg); + g.setFont("Vector",h).setFontAlign(-1,-1); + + // Header + g.drawLine(0,25,W,25); + g.drawLine(0,26,W,26); + + g.drawString("Current Cycle", 10, y+=h); + drawData("Start", getHoursMins(activityreminder_data.stepsDate), y+=h); + drawData("Steps", getCurrentSteps(), y+=h); + + /* + g.drawString("Button Press", 10, y+=h*2); + drawData("Ok", getHoursMins(activityreminder_data.okDate), y+=h); + drawData("Dismiss", getHoursMins(activityreminder_data.dismissDate), y+=h); + drawData("Pause", getHoursMins(activityreminder_data.pauseDate), y+=h); + */ + } + + function getCurrentSteps(){ + let health = Bangle.getHealthStatus("day"); + return health.steps - activityreminder_data.stepsOnDate; + } + + function run() { g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); - run(); - -})(); \ No newline at end of file + drawInfo(); + Bangle.setUI({ + mode : "custom", + back : load + }) + } + + run(); + +})(); diff --git a/apps/activityreminder/boot.js b/apps/activityreminder/boot.js index f97cf274d..5a11d73b8 100644 --- a/apps/activityreminder/boot.js +++ b/apps/activityreminder/boot.js @@ -1,70 +1,81 @@ (function () { - // load variable before defining functions cause it can trigger a ReferenceError - const activityreminder = require("activityreminder"); - const activityreminder_settings = activityreminder.loadSettings(); - let activityreminder_data = activityreminder.loadData(); - - if (activityreminder_data.firstLoad) { - activityreminder_data.firstLoad = false; + // load variable before defining functions cause it can trigger a ReferenceError + const activityreminder = require("activityreminder"); + const activityreminder_settings = activityreminder.loadSettings(); + let activityreminder_data = activityreminder.loadData(); + + if (activityreminder_data.firstLoad) { + activityreminder_data.firstLoad = false; + activityreminder.saveData(activityreminder_data); + } + + function run() { + if (isNotWorn()) return; + let now = new Date(); + let h = now.getHours(); + + if (isDuringAlertHours(h)) { + let health = Bangle.getHealthStatus("day"); + if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed + || health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch + activityreminder_data.stepsOnDate = health.steps; + activityreminder_data.stepsDate = now; activityreminder.saveData(activityreminder_data); - } - - function run() { - if (isNotWorn()) return; - let now = new Date(); - let h = now.getHours(); - - if (isDuringAlertHours(h)) { - let health = Bangle.getHealthStatus("day"); - if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed - || health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch - activityreminder_data.stepsOnDate = health.steps; - activityreminder_data.stepsDate = now; - activityreminder.saveData(activityreminder_data); - /* todo in a futur release - Add settimer to trigger like 30 secs after going in this part cause the person have been walking - (pass some argument to run() to handle long walks and not triggering so often) - */ - } - - if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) { - load('activityreminder.app.js'); - } - } - - } - - function isNotWorn() { - return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature()); - } - - function isDuringAlertHours(h) { - if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight - return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour); - } else { // passing through midnight - return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour); - } - } - - Bangle.on('midnight', function () { - /* - Usefull trick to have the app working smothly for people using it at night - */ - let now = new Date(); - let h = now.getHours(); - if (activityreminder_settings.enabled && isDuringAlertHours(h)) { - // updating only the steps and keeping the original stepsDate on purpose - activityreminder_data.stepsOnDate = 0; - activityreminder.saveData(activityreminder_data); - } - }); - - - if (activityreminder_settings.enabled) { - setInterval(run, 60000); /* todo in a futur release - increase setInterval time to something that is still sensible (5 mins ?) - when we added a settimer + Add settimer to trigger like 30 secs after going in this part cause the person have been walking + (pass some argument to run() to handle long walks and not triggering so often) */ + } + + if (mustAlert(now)) { + load('activityreminder.alert.js'); + } } + + } + + function isNotWorn() { + return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature()); + } + + function isDuringAlertHours(h) { + if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight + return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour); + } else { // passing through midnight + return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour); + } + } + + function mustAlert(now) { + if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected + if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago + (now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago + (now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago + return true; + } + } + return false; + } + + Bangle.on('midnight', function () { + /* + Usefull trick to have the app working smothly for people using it at night + */ + let now = new Date(); + let h = now.getHours(); + if (activityreminder_settings.enabled && isDuringAlertHours(h)) { + // updating only the steps and keeping the original stepsDate on purpose + activityreminder_data.stepsOnDate = 0; + activityreminder.saveData(activityreminder_data); + } + }); + + + if (activityreminder_settings.enabled) { + setInterval(run, 60000); + /* todo in a futur release + increase setInterval time to something that is still sensible (5 mins ?) + when we added a settimer + */ + } })(); diff --git a/apps/activityreminder/lib.js b/apps/activityreminder/lib.js index 704d35641..a5c35190c 100644 --- a/apps/activityreminder/lib.js +++ b/apps/activityreminder/lib.js @@ -1,56 +1,44 @@ exports.loadSettings = function () { - return Object.assign({ - enabled: true, - startHour: 9, - endHour: 20, - maxInnactivityMin: 30, - dismissDelayMin: 15, - pauseDelayMin: 120, - minSteps: 50, - tempThreshold: 27 - }, require("Storage").readJSON("activityreminder.s.json", true) || {}); + return Object.assign({ + enabled: true, + startHour: 9, + endHour: 20, + maxInnactivityMin: 30, + dismissDelayMin: 15, + pauseDelayMin: 120, + minSteps: 50, + tempThreshold: 27 + }, require("Storage").readJSON("activityreminder.s.json", true) || {}); }; exports.writeSettings = function (settings) { - require("Storage").writeJSON("activityreminder.s.json", settings); + require("Storage").writeJSON("activityreminder.s.json", settings); }; exports.saveData = function (data) { - require("Storage").writeJSON("activityreminder.data.json", data); + require("Storage").writeJSON("activityreminder.data.json", data); }; exports.loadData = function () { - let health = Bangle.getHealthStatus("day"); - let data = Object.assign({ - firstLoad: true, - stepsDate: new Date(), - stepsOnDate: health.steps, - okDate: new Date(1970), - dismissDate: new Date(1970), - pauseDate: new Date(1970), - }, + let health = Bangle.getHealthStatus("day"); + let data = Object.assign({ + firstLoad: true, + stepsDate: new Date(), + stepsOnDate: health.steps, + okDate: new Date(1970), + dismissDate: new Date(1970), + pauseDate: new Date(1970), + }, require("Storage").readJSON("activityreminder.data.json") || {}); - if(typeof(data.stepsDate) == "string") - data.stepsDate = new Date(data.stepsDate); - if(typeof(data.okDate) == "string") - data.okDate = new Date(data.okDate); - if(typeof(data.dismissDate) == "string") - data.dismissDate = new Date(data.dismissDate); - if(typeof(data.pauseDate) == "string") - data.pauseDate = new Date(data.pauseDate); + if (typeof (data.stepsDate) == "string") + data.stepsDate = new Date(data.stepsDate); + if (typeof (data.okDate) == "string") + data.okDate = new Date(data.okDate); + if (typeof (data.dismissDate) == "string") + data.dismissDate = new Date(data.dismissDate); + if (typeof (data.pauseDate) == "string") + data.pauseDate = new Date(data.pauseDate); - return data; + return data; }; - -exports.mustAlert = function(activityreminder_data, activityreminder_settings) { - let now = new Date(); - if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected - if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago - (now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago - (now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago - return true; - } - } - return false; -} \ No newline at end of file diff --git a/apps/activityreminder/metadata.json b/apps/activityreminder/metadata.json index 75ebf80b2..a7fb0c487 100644 --- a/apps/activityreminder/metadata.json +++ b/apps/activityreminder/metadata.json @@ -3,7 +3,7 @@ "name": "Activity Reminder", "shortName":"Activity Reminder", "description": "A reminder to take short walks for the ones with a sedentary lifestyle", - "version":"0.08", + "version":"0.10", "icon": "app.png", "type": "app", "tags": "tool,activity", @@ -13,11 +13,12 @@ {"name": "activityreminder.app.js", "url":"app.js"}, {"name": "activityreminder.boot.js", "url": "boot.js"}, {"name": "activityreminder.settings.js", "url": "settings.js"}, + {"name": "activityreminder.alert.js", "url": "alert.js"}, {"name": "activityreminder", "url": "lib.js"}, {"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true} ], "data": [ {"name": "activityreminder.s.json"}, - {"name": "activityreminder.data.json"} + {"name": "activityreminder.data.json", "storageFile": true} ] } diff --git a/apps/activityreminder/settings.js b/apps/activityreminder/settings.js index de490b796..051c0dcd8 100644 --- a/apps/activityreminder/settings.js +++ b/apps/activityreminder/settings.js @@ -1,80 +1,86 @@ (function (back) { - // Load settings - const activityreminder = require("activityreminder"); - let settings = activityreminder.loadSettings(); + // Load settings + const activityreminder = require("activityreminder"); + let settings = activityreminder.loadSettings(); - // Show the menu - E.showMenu({ - "": { "title": "Activity Reminder" }, - "< Back": () => back(), - 'Enable': { - value: settings.enabled, - onchange: v => { - settings.enabled = v; - activityreminder.writeSettings(settings); - } - }, - 'Start hour': { - value: settings.startHour, - min: 0, max: 24, - onchange: v => { - settings.startHour = v; - activityreminder.writeSettings(settings); - } - }, - 'End hour': { - value: settings.endHour, - min: 0, max: 24, - onchange: v => { - settings.endHour = v; - activityreminder.writeSettings(settings); - } - }, - 'Max inactivity': { - value: settings.maxInnactivityMin, - min: 15, max: 120, - onchange: v => { - settings.maxInnactivityMin = v; - activityreminder.writeSettings(settings); - }, - format: x => x + "m" - }, - 'Dismiss delay': { - value: settings.dismissDelayMin, - min: 5, max: 60, - onchange: v => { - settings.dismissDelayMin = v; - activityreminder.writeSettings(settings); - }, - format: x => x + "m" - }, - 'Pause delay': { - value: settings.pauseDelayMin, - min: 30, max: 240, step: 5, - onchange: v => { - settings.pauseDelayMin = v; - activityreminder.writeSettings(settings); - }, - format: x => { - return x + "m"; - } - }, - 'Min steps': { - value: settings.minSteps, - min: 10, max: 500, step: 10, - onchange: v => { - settings.minSteps = v; - activityreminder.writeSettings(settings); - } - }, - 'Temp Threshold': { - value: settings.tempThreshold, - min: 20, max: 40, step: 0.5, - format: v => v + "°C", - onchange: v => { - settings.tempThreshold = v; - activityreminder.writeSettings(settings); - } + function getMainMenu(){ + var mainMenu = { + "": { "title": "Activity Reminder" }, + "< Back": () => back(), + 'Enable': { + value: settings.enabled, + onchange: v => { + settings.enabled = v; + activityreminder.writeSettings(settings); } - }); + }, + 'Start hour': { + value: settings.startHour, + min: 0, max: 24, + onchange: v => { + settings.startHour = v; + activityreminder.writeSettings(settings); + } + }, + 'End hour': { + value: settings.endHour, + min: 0, max: 24, + onchange: v => { + settings.endHour = v; + activityreminder.writeSettings(settings); + } + }, + 'Max inactivity': { + value: settings.maxInnactivityMin, + min: 15, max: 120, + onchange: v => { + settings.maxInnactivityMin = v; + activityreminder.writeSettings(settings); + }, + format: x => x + "m" + }, + 'Dismiss delay': { + value: settings.dismissDelayMin, + min: 5, max: 60, + onchange: v => { + settings.dismissDelayMin = v; + activityreminder.writeSettings(settings); + }, + format: x => x + "m" + }, + 'Pause delay': { + value: settings.pauseDelayMin, + min: 30, max: 240, step: 5, + onchange: v => { + settings.pauseDelayMin = v; + activityreminder.writeSettings(settings); + }, + format: x => { + return x + "m"; + } + }, + 'Min steps': { + value: settings.minSteps, + min: 10, max: 500, step: 10, + onchange: v => { + settings.minSteps = v; + activityreminder.writeSettings(settings); + } + }, + 'Temp Threshold': { + value: settings.tempThreshold, + min: 20, max: 40, step: 0.5, + format: v => v + "°C", + onchange: v => { + settings.tempThreshold = v; + activityreminder.writeSettings(settings); + } + } + }; + + return mainMenu; + } + + // Show the menu + E.showMenu(getMainMenu()); }) diff --git a/apps/advcasio/ChangeLog b/apps/advcasio/ChangeLog index 7de176672..a1b528cf6 100644 --- a/apps/advcasio/ChangeLog +++ b/apps/advcasio/ChangeLog @@ -1 +1,3 @@ 0.01: AdvCasio first version +0.02: Remove un-needed fonts to improve memory usage +0.03: Tell clock widgets to hide. diff --git a/apps/advcasio/app.js b/apps/advcasio/app.js index 8c27b7823..8cb904f90 100644 --- a/apps/advcasio/app.js +++ b/apps/advcasio/app.js @@ -1,7 +1,5 @@ const storage = require('Storage'); -require("Font6x12").add(Graphics); -require("Font6x8").add(Graphics); require("Font8x12").add(Graphics); require("Font7x11Numeric7Seg").add(Graphics); @@ -257,7 +255,6 @@ function draw() { g.setColor(0, 0, 0); - g.setFont("6x12"); if(dataJson && dataJson.weather) drawWeather(dataJson.weather); if(dataJson && dataJson.tasks) drawTasks(dataJson.tasks); @@ -297,9 +294,10 @@ Bangle.on("lock", (locked) => { }); +Bangle.setUI("clock"); + // Load widgets, but don't show them Bangle.loadWidgets(); -Bangle.setUI("clock"); g.reset(); g.clear(); diff --git a/apps/advcasio/metadata.json b/apps/advcasio/metadata.json index 0f0c75c07..152f47132 100644 --- a/apps/advcasio/metadata.json +++ b/apps/advcasio/metadata.json @@ -1,7 +1,7 @@ { "id": "advcasio", "name": "Advanced Casio Clock", "shortName":"advcasio", - "version":"0.01", + "version":"0.03", "description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.", "icon": "app.png", "tags": "clock", diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog index ae650deeb..16a90242b 100644 --- a/apps/agenda/ChangeLog +++ b/apps/agenda/ChangeLog @@ -1,2 +1,6 @@ 0.01: Basic agenda with events from GB 0.02: Added settings page to force calendar sync +0.03: Disable past events display from settings +0.04: Added awareness of allDay field +0.05: Displaying calendar colour and name +0.06: Added clkinfo for clocks. \ No newline at end of file diff --git a/apps/agenda/README.md b/apps/agenda/README.md index a546e0a89..7063a70a2 100644 --- a/apps/agenda/README.md +++ b/apps/agenda/README.md @@ -1,3 +1,20 @@ # Agenda -Basic agenda reading the events synchronised from GadgetBridge +Basic agenda reading the events synchronised from GadgetBridge. + +### Functionalities + +* List all events in the next week (or whatever is synchronized) +* Optionally view past events (until GB removes them) +* Show start time and location of the events in the list +* Show the colour of the calendar in the list +* Display description, location and calendar name after tapping on events + +### Report a bug + +You can easily open an issue in the espruino repo, but I won't be notified and it might take time. +If you want a (hopefully) quicker response, just report [on my fork](https://github.com/glemco/BangleApps). + +### Known Problems + +Any all-day event lasts just one day: that is a GB limitation that we will likely fix in the future. diff --git a/apps/agenda/agenda.clkinfo.js b/apps/agenda/agenda.clkinfo.js new file mode 100644 index 000000000..a80c09002 --- /dev/null +++ b/apps/agenda/agenda.clkinfo.js @@ -0,0 +1,29 @@ +(function() { + var agendaItems = { + name: "Agenda", + img: atob("GBiBAf////////85z/AAAPAAAPgAAP////AAAPAAAPAAAPAAAOAAAeAAAeAAAcAAA8AAAoAABgAADP//+P//8PAAAPAAAPgAAf///w=="), + items: [] + }; + + var now = new Date(); + var agenda = storage.readJSON("android.calendar.json") + .filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000) + .sort((a,b)=>a.timestamp - b.timestamp); + + agenda.forEach((entry, i) => { + + var title = entry.title.slice(0,18); + var date = new Date(entry.timestamp*1000); + var dateStr = locale.date(date).replace(/\d\d\d\d/,""); + dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : ""; + + agendaItems.items.push({ + name: "agendaEntry-" + i, + get: () => ({ text: title + "\n" + dateStr, img: null}), + show: function() { agendaItems.items[i].emit("redraw"); }, + hide: function () {} + }); + }); + + return agendaItems; +}) \ No newline at end of file diff --git a/apps/agenda/agenda.js b/apps/agenda/agenda.js index f39e31c75..9cffe0265 100644 --- a/apps/agenda/agenda.js +++ b/apps/agenda/agenda.js @@ -6,6 +6,8 @@ title, description, location, + color:int, + calName, allDay: bool, } */ @@ -24,19 +26,23 @@ var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4"; //FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?) var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[]; +var settings = require("Storage").readJSON("agenda.settings.json",true)||{}; -CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp) +CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp); function getDate(timestamp) { return new Date(timestamp*1000); } -function formatDateLong(date, includeDay) { - if(includeDay) - return Locale.date(date)+" "+Locale.time(date,1); - return Locale.time(date,1); +function formatDateLong(date, includeDay, allDay) { + let shortTime = Locale.time(date,1)+Locale.meridian(date); + if(allDay) shortTime = ""; + if(includeDay || allDay) + return Locale.date(date)+" "+shortTime; + return shortTime; } -function formatDateShort(date) { - return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1); +function formatDateShort(date, allDay) { + return Locale.date(date).replace(/\d\d\d\d/,"")+(allDay? + "" : Locale.time(date,1)+Locale.meridian(date)); } var lines = []; @@ -45,7 +51,7 @@ function showEvent(ev) { if(!ev) return; g.setFont(bodyFont); //var lines = []; - if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10) + if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10); var titleCnt = lines.length; var start = getDate(ev.timestamp); var end = getDate((+ev.timestamp) + (+ev.durationInSeconds)); @@ -53,22 +59,24 @@ function showEvent(ev) { if (titleCnt) lines.push(""); // add blank line after title if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth()) includeDay = false; - if(includeDay) { + if(includeDay || ev.allDay) { lines = lines.concat( /*LANG*/"Start:", - g.wrapString(formatDateLong(start, includeDay), g.getWidth()-10), + g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10), /*LANG*/"End:", - g.wrapString(formatDateLong(end, includeDay), g.getWidth()-10)); + g.wrapString(formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10)); } else { lines = lines.concat( g.wrapString(Locale.date(start), g.getWidth()-10), - g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay), g.getWidth()-10), - g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay), g.getWidth()-10)); + g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10), + g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10)); } if(ev.location) lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10)); if(ev.description) lines = lines.concat("",g.wrapString(ev.description, g.getWidth()-10)); + if(ev.calName) + lines = lines.concat(/*LANG*/"Calendar"+": ", g.wrapString(ev.calName, g.getWidth()-10)); lines = lines.concat(["",/*LANG*/"< Back"]); E.showScroller({ h : g.getFontHeight(), // height of each menu item in pixels @@ -89,6 +97,12 @@ function showEvent(ev) { } function showList() { + //it might take time for GB to delete old events, decide whether to show them grayed out or hide entirely + if(!settings.pastEvents) { + let now = new Date(); + //TODO add threshold here? + CALENDAR = CALENDAR.filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000); + } if(CALENDAR.length == 0) { E.showMessage("No events"); return; @@ -101,24 +115,21 @@ function showList() { g.setColor(g.theme.fg); g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h); if (!ev) return; - var isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000; + var isPast = false; var x = r.x+2, title = ev.title; - var body = formatDateShort(getDate(ev.timestamp))+"\n"+ev.location; - var m = ev.title+"\n"+ev.location, longBody=false; + var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location"); + if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000; if (title) g.setFontAlign(-1,-1).setFont(fontBig) - .setColor(isPast ? "#888" : g.theme.fg).drawString(title, x,r.y+2); + .setColor(isPast ? "#888" : g.theme.fg).drawString(title, x+4,r.y+2); if (body) { g.setFontAlign(-1,-1).setFont(fontMedium).setColor(isPast ? "#888" : g.theme.fg); - var l = g.wrapString(body, r.w-(x+14)); - if (l.length>3) { - l = l.slice(0,3); - l[l.length-1]+="..."; - } - longBody = l.length>2; - g.drawString(l.join("\n"), x+10,r.y+20); + g.drawString(body, x+10,r.y+20); } - //if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2); g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items + if(ev.color) { + g.setColor("#"+(0x1000000+Number(ev.color)).toString(16).padStart(6,"0")); + g.fillRect(r.x,r.y+4,r.x+3, r.y+r.h-4); + } }, select : idx => showEvent(CALENDAR[idx]), back : () => load() diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index ce8438686..2bce8ca56 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "0.02", + "version": "0.06", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], @@ -12,6 +12,8 @@ "storage": [ {"name":"agenda.app.js","url":"agenda.js"}, {"name":"agenda.settings.js","url":"settings.js"}, + {"name":"agenda.clkinfo.js","url":"agenda.clkinfo.js"}, {"name":"agenda.img","url":"agenda-icon.js","evaluate":true} - ] + ], + "data": [{"name":"agenda.settings.json"}] } diff --git a/apps/agenda/settings.js b/apps/agenda/settings.js index fe9dab2d8..4220fcb63 100644 --- a/apps/agenda/settings.js +++ b/apps/agenda/settings.js @@ -3,6 +3,10 @@ Bluetooth.println(""); Bluetooth.println(JSON.stringify(message)); } + var settings = require("Storage").readJSON("agenda.settings.json",1)||{}; + function updateSettings() { + require("Storage").writeJSON("agenda.settings.json", settings); + } var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[]; var mainmenu = { "" : { "title" : "Agenda" }, @@ -32,6 +36,13 @@ E.showAlert(/*LANG*/"You are not connected").then(()=>E.showMenu(mainmenu)); } }, + /*LANG*/"Show past events" : { + value : !!settings.pastEvents, + onchange: v => { + settings.pastEvents = v; + updateSettings(); + } + }, }; E.showMenu(mainmenu); }) diff --git a/apps/agpsdata/metadata.json b/apps/agpsdata/metadata.json index d3863be52..e2f818d97 100644 --- a/apps/agpsdata/metadata.json +++ b/apps/agpsdata/metadata.json @@ -1,9 +1,9 @@ { "id": "agpsdata", - "name": "A-GPS Data", + "name": "A-GPS Data Downloader App", "shortName":"A-GPS Data", "icon": "agpsdata.png", "version":"0.02", - "description": "Download assisted GPS (A-GPS) data directly to your Bangle.js **using Gadgetbridge**", + "description": "Once installed, this app allows you to download assisted GPS (A-GPS) data directly to your Bangle.js **via Gadgetbridge on an Android phone** when you run the app. If you just want to upload the latest AGPS data from this app loader, please use the `Assisted GPS Update (AGPS)` app.", "tags": "boot,tool,assisted,gps,agps,http", "allow_emulator":true, "supports": ["BANGLEJS2"], diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index 76658af49..0cc7aedd4 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -11,4 +11,5 @@ 0.10: Fix SMS bug 0.12: Use default Bangle formatter for booleans 0.13: Added Bangle.http function (see Readme file for more info) -0.14: Fix timeout of http function not beeing cleaned up +0.14: Fix timeout of http function not being cleaned up +0.15: Allow method/body/headers to be specified for `http` (needs Gadgetbridge 0.68.0b or later) diff --git a/apps/android/boot.js b/apps/android/boot.js index 99d4dbb2c..bc8e3032d 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -150,6 +150,9 @@ //send the request var req = {t: "http", url:url, id:options.id}; if (options.xpath) req.xpath = options.xpath; + if (options.method) req.method = options.method; + if (options.body) req.body = options.body; + if (options.headers) req.headers = options.headers; gbSend(req); //create the promise var promise = new Promise(function(resolve,reject) { diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 91f74c36f..5d1b2f561 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.14", + "version": "0.15", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", diff --git a/apps/animclk/ChangeLog b/apps/animclk/ChangeLog index 348448c34..76d15bdb1 100644 --- a/apps/animclk/ChangeLog +++ b/apps/animclk/ChangeLog @@ -1,3 +1,5 @@ 0.01: New App! 0.02: Fix bug if image clock wasn't installed 0.03: Update to use setUI +0.04: Tell clock widgets to hide. Move loadWidgets() so it only runs on +startup and not on every draw. diff --git a/apps/animclk/app.js b/apps/animclk/app.js index 4bf63daf6..bdc399fbe 100644 --- a/apps/animclk/app.js +++ b/apps/animclk/app.js @@ -87,7 +87,6 @@ if (g.drawImages) { draw(); var secondInterval = setInterval(draw,100); // load widgets - Bangle.loadWidgets(); Bangle.drawWidgets(); // Stop when LCD goes off Bangle.on('lcdPower',on=>{ @@ -104,3 +103,5 @@ if (g.drawImages) { } // Show launcher when button pressed Bangle.setUI("clock"); + +Bangle.loadWidgets(); diff --git a/apps/animclk/metadata.json b/apps/animclk/metadata.json index 31dfe453f..0b426a37d 100644 --- a/apps/animclk/metadata.json +++ b/apps/animclk/metadata.json @@ -2,7 +2,7 @@ "id": "animclk", "name": "Animated Clock", "shortName": "Anim Clock", - "version": "0.03", + "version": "0.04", "description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art", "icon": "app.png", "type": "clock", diff --git a/apps/antonclk/ChangeLog b/apps/antonclk/ChangeLog index f7e95b5fa..9e75d889a 100644 --- a/apps/antonclk/ChangeLog +++ b/apps/antonclk/ChangeLog @@ -10,4 +10,5 @@ week is buffered until date or timezone changes 0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) 0.08: fixed calendar weeknumber not shortened to two digits -0.09: Use default Bangle formatter for booleans \ No newline at end of file +0.09: Use default Bangle formatter for booleans +0.10: Use Bangle.setUI({remove:...}) to allow loading the launcher without a full reset on 2v16 diff --git a/apps/antonclk/app.js b/apps/antonclk/app.js index 4b1e71bda..07f67f696 100644 --- a/apps/antonclk/app.js +++ b/apps/antonclk/app.js @@ -1,7 +1,4 @@ // Clock with large digits using the "Anton" bold font - -const SETTINGSFILE = "antonclk.json"; - Graphics.prototype.setFontAnton = function(scale) { // Actual height 69 (68 - 0) g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16)); @@ -12,23 +9,28 @@ Graphics.prototype.setFontAntonSmall = function(scale) { g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAAAAAAAAAAAAAMAAAAAAAAD8AAAAAAAA/8AAAAAAAf/8AAAAAAH//8AAAAAB///8AAAAA////8AAAAP////8AAAD/////8AAB//////8AAf//////8AH///////4A///////+AA///////AAA//////wAAA/////8AAAA////+AAAAA////gAAAAA///4AAAAAA//8AAAAAAA//AAAAAAAA/wAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/////wAAA//////8AAB//////+AAH///////gAH///////gAP///////wAf///////4Af///////4A////////8A////////8A////////8A//AAAAD/8A/8AAAAA/8A/8AAAAA/8A/8AAAAA/8A/+AAAAB/8A////////8A////////8A////////8Af///////4Af///////4AP///////wAP///////wAH///////gAD///////AAA//////8AAAP/////wAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAAA/4AAAAAAAA/4AAAAAAAB/wAAAAAAAB/wAAAAAAAD/wAAAAAAAD/gAAAAAAAH///////8AP///////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAP8AA//4AAA/8AB//4AAH/8AH//4AAP/8AP//4AA//8AP//4AB//8Af//4AD//8Af//4AP//8A///4Af//8A///4A///8A///4D///8A//AAH///8A/8AAP///8A/8AA//+/8A/8AD//8/8A/+Af//w/8A//////g/8A/////+A/8A/////8A/8Af////4A/8Af////wA/8AP////AA/8AP///+AA/8AH///8AA/8AD///wAA/8AA///AAA/8AAP/4AAA/8AAAAAAAAAAAAAAAAAAAAAAH4AAf/gAAA/4AAf/8AAD/4AAf//AAH/4AAf//gAP/4AAf//wAP/4AAf//wAf/4AAf//4Af/4AAf//4A//4AAf//8A//4AAf//8A//4AAP//8A//A/8AB/8A/8A/8AA/8A/8B/8AA/8A/8B/8AA/8A/+D//AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////gAH//9////gAD//4///+AAB//wf//4AAAP/AH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAB//wAAAAAAP//wAAAAAD///wAAAAA////wAAAAH////wAAAB/////wAAAf/////wAAD//////wAA///////wAA/////h/wAA////wB/wAA///8AB/wAA///AAB/wAA//gAAB/wAA////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AA////4P/+AA////4P//AA////4P//gA////4P//wA////4P//wA////4P//4A////4P//4A////4P//8A////4P//8A////4P//8A/8H/AAB/8A/8H+AAA/8A/8P+AAA/8A/8P+AAA/8A/8P/gAD/8A/8P/////8A/8P/////8A/8P/////8A/8P/////4A/8H/////4A/8H/////wA/8D/////wA/8B/////gA/8A////+AA/8AP///4AAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////wAAAf/////8AAB///////AAH///////gAP///////wAP///////wAf///////4Af///////4A////////8A////////8A////////8A/+AH/AB/8A/8AP+AA/8A/4Af+AA/8A/8Af+AA/8A/8Af/gH/8A//4f////8A//4f////8A//4f////8Af/4f////4Af/4f////4AP/4P////wAP/4P////gAH/4H////AAD/4D///+AAB/4B///4AAAP4AP//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAA/8AAAAAAAA/8AAAAAB8A/8AAAAB/8A/8AAAAf/8A/8AAAH//8A/8AAA///8A/8AAH///8A/8AA////8A/8AD////8A/8Af////8A/8B/////8A/8P/////8A/8//////8A////////AA///////AAA//////gAAA/////4AAAA/////AAAAA////4AAAAA////AAAAAA///8AAAAAA///gAAAAAA//+AAAAAAA//wAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gD//gAAA//4P//8AAD//8f///AAH//+////gAH///////wAP///////4AP///////8Af///////8Af///////+Af///////+A////////+A//B//AB/+A/+A/+AA/+A/8Af+AA/+A/+Af+AA/+A//A//AB/+A////////+Af///////+Af///////+Af///////8Af///////8AP///////4AH///////4AH//+////wAD//+////AAA//4P//+AAAP/gH//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAfgAAA///8A/8AAB///+A//AAH////A//gAH////g//wAP////g//wAf////w//4Af////w//4A/////w//8A/////w//8A/////w//8A//gP/wA/8A/8AD/wA/8A/8AD/wAf8A/8AD/gA/8A/+AH/AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////wAH///////gAD//////+AAA//////4AAAP/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DhgeFB4eHh4eHh4eDw=="), 60 + (scale << 8) + (1 << 16)); }; +{ // must be inside our own scope here so that when we are unloaded everything disappears + +const SETTINGSFILE = "antonclk.json"; +const isBangle1 = (process.env.HWVERSION == 1); + // variables defined from settings -var secondsMode; -var secondsColoured; -var secondsWithColon; -var dateOnMain; -var dateOnSecs; -var weekDay; -var calWeek; -var upperCase; -var vectorFont; +let secondsMode; +let secondsColoured; +let secondsWithColon; +let dateOnMain; +let dateOnSecs; +let weekDay; +let calWeek; +let upperCase; +let vectorFont; // dynamic variables -var drawTimeout; -var queueMillis = 1000; -var secondsScreen = true; +let drawTimeout; +let queueMillis = 1000; +let secondsScreen = true; + -var isBangle1 = (process.env.HWVERSION == 1); //For development purposes /* @@ -102,7 +104,7 @@ function isoStr(date) { return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2); } -var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) +let calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 dateNoTime = date; dateNoTime.setHours(0,0,0,0); if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2]; @@ -215,16 +217,21 @@ g.clear(); // Set dynamic state and perform initial drawing updateState(); // Register hooks for LCD on/off event and screen lock on/off event -Bangle.on('lcdPower', on => { - updateState(); -}); -Bangle.on('lock', on => { - updateState(); -}); +Bangle.on('lcdPower', updateState); +Bangle.on('lock', updateState); // Show launcher when middle button pressed -Bangle.setUI("clock"); +Bangle.setUI({ + mode : "clock", + remove : function() { + // Called to unload all of the clock app + Bangle.removeListener('lcdPower', updateState); + Bangle.removeListener('lock', updateState); + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + delete Graphics.prototype.setFontAnton; + delete Graphics.prototype.setFontAntonSmall; + }}); // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); - -// end of file \ No newline at end of file +} diff --git a/apps/antonclk/metadata.json b/apps/antonclk/metadata.json index 16bdf3aa8..b6134d1a1 100644 --- a/apps/antonclk/metadata.json +++ b/apps/antonclk/metadata.json @@ -1,7 +1,7 @@ { "id": "antonclk", "name": "Anton Clock", - "version": "0.09", + "version": "0.10", "description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.", "readme":"README.md", "icon": "app.png", diff --git a/apps/assistedgps/metadata.json b/apps/assistedgps/metadata.json index 1dbc42c87..4c91dcd35 100644 --- a/apps/assistedgps/metadata.json +++ b/apps/assistedgps/metadata.json @@ -1,11 +1,12 @@ { "id": "assistedgps", - "name": "Assisted GPS Update (AGPS)", + "name": "Assisted GPS Updater (AGPS)", "version": "0.03", - "description": "Downloads assisted GPS (AGPS) data to Bangle.js 1 or 2 for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", + "description": "Downloads assisted GPS (AGPS) data to Bangle.js for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", + "sortorder": -1, "icon": "app.png", "type": "RAM", - "tags": "tool,outdoors,agps", + "tags": "tool,outdoors,agps,gps,a-gps", "supports": ["BANGLEJS","BANGLEJS2"], "custom": "custom.html", "customConnect": true, diff --git a/apps/astral/ChangeLog b/apps/astral/ChangeLog index a51c96760..c93c2b6c2 100644 --- a/apps/astral/ChangeLog +++ b/apps/astral/ChangeLog @@ -1,3 +1,4 @@ 0.01: Create astral clock app 0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget 0.03: Update to use Bangle.setUI instead of setWatch +0.04: Tell clock widgets to hide. diff --git a/apps/astral/app.js b/apps/astral/app.js index c445463f2..c4339bc09 100644 --- a/apps/astral/app.js +++ b/apps/astral/app.js @@ -767,6 +767,24 @@ function draw() { g.clear(); current_moonphase = getMoonPhase(); +Bangle.setUI("clockupdown", btn => { + if (btn==0) { + if (!processing) { + if (!modeswitch) { + modeswitch = true; + if (mode == "planetary") mode = "extras"; + else mode = "planetary"; + } + else + modeswitch = false; + } + } else { + if (!processing) + ready_to_compute = true; + } +}); + + // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -799,23 +817,6 @@ Bangle.setGPSPower(1); // Show launcher when button pressed Bangle.setClockMode(); -Bangle.setUI("clockupdown", btn => { - if (btn==0) { - if (!processing) { - if (!modeswitch) { - modeswitch = true; - if (mode == "planetary") mode = "extras"; - else mode = "planetary"; - } - else - modeswitch = false; - } - } else { - if (!processing) - ready_to_compute = true; - } -}); - setWatch(function () { if (!astral_settings.astral_default) { colours_switched = true; diff --git a/apps/astral/metadata.json b/apps/astral/metadata.json index 3317092db..d7120878b 100644 --- a/apps/astral/metadata.json +++ b/apps/astral/metadata.json @@ -1,7 +1,7 @@ { "id": "astral", "name": "Astral Clock", - "version": "0.03", + "version": "0.04", "description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.", "icon": "app-icon.png", "type": "clock", diff --git a/apps/banglexercise/ChangeLog b/apps/banglexercise/ChangeLog index 5f1d3bd7d..6cf589541 100644 --- a/apps/banglexercise/ChangeLog +++ b/apps/banglexercise/ChangeLog @@ -2,3 +2,4 @@ 0.02: Add sit ups Add more feedback to the user about the exercises Clean up code +0.03: Add software back button on main menu diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index bc6e35f07..9659ee81f 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -71,7 +71,8 @@ function showMainMenu() { let menu; menu = { "": { - title: "BanglExercise" + title: "BanglExercise", + back: load } }; @@ -381,4 +382,5 @@ Bangle.on('HRM', function(hrm) { }); g.clear(1); +Bangle.loadWidgets(); showMainMenu(); diff --git a/apps/banglexercise/metadata.json b/apps/banglexercise/metadata.json index 9bb93f112..f4ce1894b 100644 --- a/apps/banglexercise/metadata.json +++ b/apps/banglexercise/metadata.json @@ -1,7 +1,7 @@ { "id": "banglexercise", "name": "BanglExercise", "shortName":"BanglExercise", - "version":"0.02", + "version":"0.03", "description": "Can automatically track exercises while wearing the Bangle.js watch.", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/barcode/ChangeLog b/apps/barcode/ChangeLog index 4f99f15ac..7ab5d8587 100644 --- a/apps/barcode/ChangeLog +++ b/apps/barcode/ChangeLog @@ -7,3 +7,4 @@ 0.07: Step count resets at midnight 0.08: Step count stored in memory to survive reloads. Now shows step count daily and since last reboot. 0.09: NOW it really should reset daily (instead of every other day...) +0.10: Tell clock widgets to hide. diff --git a/apps/barcode/barcode.app.js b/apps/barcode/barcode.app.js index 89419f33c..0d9df78d5 100644 --- a/apps/barcode/barcode.app.js +++ b/apps/barcode/barcode.app.js @@ -416,13 +416,13 @@ var layout = new Layout( { // Clear the screen once, at startup g.clear(); +Bangle.setUI("clock"); Bangle.loadWidgets(); Bangle.drawWidgets(); -Bangle.setUI("clock"); layout.render(); Bangle.on('lock', function(locked) { if(!locked) { layout.render(); } -}); \ No newline at end of file +}); diff --git a/apps/barcode/metadata.json b/apps/barcode/metadata.json index cef267b2b..3f6bf06e6 100644 --- a/apps/barcode/metadata.json +++ b/apps/barcode/metadata.json @@ -2,7 +2,7 @@ "name": "Barcode clock", "shortName":"Barcode clock", "icon": "barcode.icon.png", - "version":"0.09", + "version":"0.10", "description": "EAN-8 compatible barcode clock.", "tags": "barcode,ean,ean-8,watchface,clock,clockface", "type": "clock", diff --git a/apps/batclock/ChangeLog b/apps/batclock/ChangeLog index e6e21b146..2a2d91b74 100644 --- a/apps/batclock/ChangeLog +++ b/apps/batclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: App Created! 0.02: Update to use Bangle.setUI instead of setWatch +0.03: Tell clock widgets to hide. diff --git a/apps/batclock/bat-clock.app.js b/apps/batclock/bat-clock.app.js index 31b8f5b9b..dc649160f 100644 --- a/apps/batclock/bat-clock.app.js +++ b/apps/batclock/bat-clock.app.js @@ -249,6 +249,9 @@ g.clear(); g.setColor(0, 0.5, 0).drawImage(bg_crack); g.setColor(1, 1, 1).drawImage(batman); +// Show launcher when button pressed +Bangle.setUI("clock"); + Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -256,5 +259,3 @@ Bangle.drawWidgets(); timeInterval = setInterval(showTime, 1000); showTime(); -// Show launcher when button pressed -Bangle.setUI("clock"); diff --git a/apps/batclock/metadata.json b/apps/batclock/metadata.json index 8aa115780..e6520cb90 100644 --- a/apps/batclock/metadata.json +++ b/apps/batclock/metadata.json @@ -2,7 +2,7 @@ "id": "batclock", "name": "Bat Clock", "shortName": "Bat Clock", - "version": "0.02", + "version": "0.03", "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", "icon": "bat-clock.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/bclock/ChangeLog b/apps/bclock/ChangeLog index 5b2cf598c..79c198431 100644 --- a/apps/bclock/ChangeLog +++ b/apps/bclock/ChangeLog @@ -1,2 +1,3 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Update to use Bangle.setUI instead of setWatch +0.04: Tell clock widgets to hide. diff --git a/apps/bclock/clock-binary.js b/apps/bclock/clock-binary.js index fdf945ee6..c08a7abe6 100644 --- a/apps/bclock/clock-binary.js +++ b/apps/bclock/clock-binary.js @@ -100,10 +100,12 @@ Bangle.on('lcdPower', on => { if (on) drawClock(); }); +// Show launcher when button pressed +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); setInterval(() => { drawClock(); }, 1000); drawClock(); -// Show launcher when button pressed -Bangle.setUI("clock"); + diff --git a/apps/bclock/metadata.json b/apps/bclock/metadata.json index 94219a30b..c6a24d89f 100644 --- a/apps/bclock/metadata.json +++ b/apps/bclock/metadata.json @@ -1,7 +1,7 @@ { "id": "bclock", "name": "Binary Clock", - "version": "0.03", + "version": "0.04", "description": "A simple binary clock watch face", "icon": "clock-binary.png", "type": "clock", diff --git a/apps/bigdclock/ChangeLog b/apps/bigdclock/ChangeLog index 09cc978fb..c92d139bb 100644 --- a/apps/bigdclock/ChangeLog +++ b/apps/bigdclock/ChangeLog @@ -3,3 +3,5 @@ 0.03: Internationalisation; bug fix - battery icon responds promptly to charging state 0.04: bug fix 0.05: proper fix for the race condition in queueDraw() +0.06: Tell clock widgets to hide. +0.07: Better battery graphic - now has green, yellow and red sections; battery status reflected in the bar across the middle of the screen; current battery state checked only once every 15 minutes, leading to longer-lasting battery charge diff --git a/apps/bigdclock/bigdclock.app.js b/apps/bigdclock/bigdclock.app.js index c013c6188..a8e2b38df 100644 --- a/apps/bigdclock/bigdclock.app.js +++ b/apps/bigdclock/bigdclock.app.js @@ -11,6 +11,8 @@ Graphics.prototype.setFontOpenSans = function(scale) { }; var drawTimeout; +var lastBattCheck = 0; +var width = 0; function queueDraw(millis_now) { if (drawTimeout) clearTimeout(drawTimeout); @@ -24,12 +26,15 @@ function draw() { var date = new Date(); var h = date.getHours(), m = date.getMinutes(); - var d = date.getDate(), - w = date.getDay(); // d=1..31; w=0..6 - const level = E.getBattery(); - const width = level + (level/2); + var d = date.getDate(); var is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; - var dows = require("date_utils").dows(0,1); + var dow = require("date_utils").dows(0,1)[date.getDay()]; + + if ((date.getTime() >= lastBattCheck + 15*60000) || Bangle.isCharging()) { + lastBattcheck = date.getTime(); + width = E.getBattery(); + width += width/2; + } g.reset(); g.clear(); @@ -47,24 +52,35 @@ function draw() { g.drawString(d, g.getWidth() -6, 98); g.setFont('Vector', 52); g.setFontAlign(-1, -1); - g.drawString(dows[w].slice(0,2).toUpperCase(), 6, 103); + g.drawString(dow.slice(0,2).toUpperCase(), 6, 103); g.fillRect(9,159,166,171); g.fillRect(167,163,170,167); if (Bangle.isCharging()) { g.setColor(1,1,0); - } else if (level > 40) { - g.setColor(0,1,0); + g.fillRect(12,162,12+width,168); } else { g.setColor(1,0,0); + g.fillRect(12,162,57,168); + g.setColor(1,1,0); + g.fillRect(58,162,72,168); + g.setColor(0,1,0); + g.fillRect(73,162,162,168); } - g.fillRect(12,162,12+width,168); - if (level < 100) { + if (width < 150) { g.setColor(g.theme.bg); g.fillRect(12+width+1,162,162,168); } - g.setColor(0, 1, 0); + if (Bangle.isCharging()) { + g.setColor(1,1,0); + } else if (width <= 45) { + g.setColor(1,0,0); + } else if (width <= 60) { + g.setColor(1,1,0); + } else { + g.setColor(0, 1, 0); + } g.fillRect(0, 90, g.getWidth(), 94); // widget redraw @@ -85,7 +101,8 @@ Bangle.on('charging', (charging) => { draw(); }); +Bangle.setUI("clock"); + Bangle.loadWidgets(); draw(); -Bangle.setUI("clock"); diff --git a/apps/bigdclock/metadata.json b/apps/bigdclock/metadata.json index 7359bcf20..30352ca1a 100644 --- a/apps/bigdclock/metadata.json +++ b/apps/bigdclock/metadata.json @@ -1,7 +1,7 @@ { "id": "bigdclock", "name": "Big digit clock containing just the essentials", "shortName":"Big digit clk", - "version":"0.05", + "version":"0.07", "description": "A clock containing just the essentials, made as easy to read as possible for those of us that need glasses. It contains the time, the day-of-week, the day-of-month, and the current battery state-of-charge.", "icon": "bigdclock.png", "type": "clock", diff --git a/apps/bigdclock/screenshot.png b/apps/bigdclock/screenshot.png index 8a12b266e..acac53ea9 100644 Binary files a/apps/bigdclock/screenshot.png and b/apps/bigdclock/screenshot.png differ diff --git a/apps/binclock/ChangeLog b/apps/binclock/ChangeLog index dc4ed8308..7c31cc0d3 100644 --- a/apps/binclock/ChangeLog +++ b/apps/binclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Fixed bug where screen didn't clear so incorrect time displayed. 0.03: Update to use Bangle.setUI instead of setWatch +0.04: Tell clock widgets to hide. diff --git a/apps/binclock/app.js b/apps/binclock/app.js index f8cbe8dd5..d9c74e6ce 100644 --- a/apps/binclock/app.js +++ b/apps/binclock/app.js @@ -164,9 +164,6 @@ Bangle.on('lcdPower',on=>{ draw(); // draw immediately } }); -// Load widgets -Bangle.loadWidgets(); -Bangle.drawWidgets(); // Show launcher when button pressed Bangle.setUI("clockupdown", btn=>{ if (btn!=1) return; @@ -176,3 +173,6 @@ Bangle.setUI("clockupdown", btn=>{ displayTime = 0; } }); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/binclock/metadata.json b/apps/binclock/metadata.json index d17045868..2ca2755a6 100644 --- a/apps/binclock/metadata.json +++ b/apps/binclock/metadata.json @@ -2,7 +2,7 @@ "id": "binclock", "name": "Binary Clock", "shortName": "Binary Clock", - "version": "0.03", + "version": "0.04", "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", "icon": "app.png", "type": "clock", diff --git a/apps/binwatch/ChangeLog b/apps/binwatch/ChangeLog index 1e54f489c..e355155b3 100644 --- a/apps/binwatch/ChangeLog +++ b/apps/binwatch/ChangeLog @@ -2,3 +2,5 @@ 0.02: first running version for BangleJs2 0.03: corrected icon, added screen shot, extended description 0.04: corrected format of background image (raw binary) +0.05: move setUI() up before draw() as to not have a false positive 'sanity +check' when building on github. diff --git a/apps/binwatch/app.js b/apps/binwatch/app.js index 28d7a06a5..153bebb32 100644 --- a/apps/binwatch/app.js +++ b/apps/binwatch/app.js @@ -334,6 +334,7 @@ function setRuntimeValues(resolution) { var hour = 0, minute = 1, second = 50; var batVLevel = 20; +Bangle.setUI("clock"); function draw() { var d = new Date(); @@ -371,7 +372,6 @@ function draw() { } // Show launcher when button pressed -Bangle.setUI("clock"); setRuntimeValues(g.getWidth()); g.reset().clear(); Bangle.loadWidgets(); diff --git a/apps/binwatch/metadata.json b/apps/binwatch/metadata.json index 0b5fb2c72..0b4dbc697 100644 --- a/apps/binwatch/metadata.json +++ b/apps/binwatch/metadata.json @@ -3,7 +3,7 @@ "shortName":"BinWatch", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], - "version":"0.04", + "version":"0.05", "supports": ["BANGLEJS2"], "readme": "README.md", "allow_emulator":true, diff --git a/apps/blobclk/ChangeLog b/apps/blobclk/ChangeLog index 9c4ef5b7b..193eb5024 100644 --- a/apps/blobclk/ChangeLog +++ b/apps/blobclk/ChangeLog @@ -5,3 +5,4 @@ 0.04: Modified to account for changes in the behavior of Graphics.fillPoly 0.05: Slight increase to draw speed after LCD on 0.06: Update to use Bangle.setUI instead of setWatch, allow themes and different size screens +0.07: Tell clock widgets to hide. diff --git a/apps/blobclk/clock-blob.js b/apps/blobclk/clock-blob.js index c84b8a1e6..d23e18ff9 100644 --- a/apps/blobclk/clock-blob.js +++ b/apps/blobclk/clock-blob.js @@ -99,6 +99,10 @@ function startTimers() { Bangle.drawWidgets(); intervalRef = setInterval(redraw,1000); } + +// Show launcher when button pressed +Bangle.setUI("clock"); + Bangle.loadWidgets(); startTimers(); Bangle.on('lcdPower',function(on) { @@ -108,5 +112,3 @@ Bangle.on('lcdPower',function(on) { clearTimers(); } }); -// Show launcher when button pressed -Bangle.setUI("clock"); diff --git a/apps/blobclk/metadata.json b/apps/blobclk/metadata.json index 85d7deabe..3ae8de222 100644 --- a/apps/blobclk/metadata.json +++ b/apps/blobclk/metadata.json @@ -2,7 +2,7 @@ "id": "blobclk", "name": "Large Digit Blob Clock", "shortName": "Blob Clock", - "version": "0.06", + "version": "0.07", "description": "A clock with big digits", "icon": "clock-blob.png", "type": "clock", diff --git a/apps/boldclk/ChangeLog b/apps/boldclk/ChangeLog index 30ac31c61..0c6e8cb52 100644 --- a/apps/boldclk/ChangeLog +++ b/apps/boldclk/ChangeLog @@ -3,3 +3,4 @@ 0.04: Work with themes, smaller screens 0.05: Adjust hand lengths to be within 'tick' points 0.06: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". +0.07: Tell clock widgets to hide. diff --git a/apps/boldclk/bold_clock.js b/apps/boldclk/bold_clock.js index 9d3ea0756..763530a32 100644 --- a/apps/boldclk/bold_clock.js +++ b/apps/boldclk/bold_clock.js @@ -130,9 +130,10 @@ Bangle.on('lcdPower', (on) => { } }); +// Show launcher when button pressed +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); startTimers(); -// Show launcher when button pressed -Bangle.setUI("clock"); diff --git a/apps/boldclk/metadata.json b/apps/boldclk/metadata.json index cf961347d..086203142 100644 --- a/apps/boldclk/metadata.json +++ b/apps/boldclk/metadata.json @@ -1,7 +1,7 @@ { "id": "boldclk", "name": "Bold Clock", - "version": "0.06", + "version": "0.07", "description": "Simple, readable and practical clock", "icon": "bold_clock.png", "screenshots": [{"url":"screenshot_bold.png"}], diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index 8a6fe4f9a..546c83894 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -10,4 +10,14 @@ 0.10: HomeAssistant integration if HomeAssistant is installed. 0.11: Performance improvements. 0.12: Implements a 2D menu. -0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled. \ No newline at end of file +0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled. +0.14: Adds humidity to weather data. +0.15: Added option for a dynamic mode to show widgets only if unlocked. +0.16: You can now show your agenda if your calendar is synced with Gadgetbridge. +0.17: Fix - Step count was no more shown in the menu. +0.18: Set timer for an agenda entry by simply clicking in the middle of the screen. Only one timer can be set. +0.19: Fix - Compatibility with "Digital clock widget" +0.20: Better handling of async data such as getPressure. +0.21: On the default menu the week of year can be shown. +0.22: Use the new clkinfo module for the menu. +0.23: Feedback of apps after run is now optional and decided by the corresponding clkinfo. \ No newline at end of file diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md index eb5356a7e..d869fa2cf 100644 --- a/apps/bwclk/README.md +++ b/apps/bwclk/README.md @@ -1,46 +1,49 @@ # BW Clock -A very minimalistic clock with date and time in focus. +A very minimalistic clock. ![](screenshot.png) ## Features -The BW clock provides many features as well as 3rd party integrations: +The BW clock implements features that are exposed by other apps through the `clkinfo` module. +For example, if you install the HomeAssistant app, this menu item will be shown if you click right +and additionally allows you to send triggers directly from the clock (select triggers via up/down and +send via click center). Here are examples of other apps that are integrated: + - Bangle data such as steps, heart rate, battery or charging state. -- A timer can be set directly. *Requirement: Scheduler library* +- Show agenda entries. A timer for an agenda entry can also be set by simply clicking in the middle of the screen. This can be used to not forget a meeting etc. Note that only one agenda-timer can be set at a time. *Requirement: Gadgetbridge calendar sync enabled* - Weather temperature as well as the wind speed can be shown. *Requirement: Weather app* - HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant app* Note: If some apps are not installed (e.gt. weather app), then this menu item is hidden. -## Menu -2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to set a timer or send a HomeAssistant trigger. - -Simply click left / right to go through the menu entries such as Bangle, Timer etc. -and click up/down to move into this sub-menu. You can then click in the middle of the screen -to e.g. send a trigger via HomeAssistant once you selected it. - -``` - +5min - | - Bangle -- Timer[Optional] -- Weather[Optional] -- HomeAssistant [Optional] - | | | | - Bpm -5min Temperature Trigger1 - | | | - Steps ... ... - | - Battery -``` - ## Settings -- Fullscreen on/off (widgets are still loaded). -- Enable/disable lock icon in the settings. Useful if fullscreen is on. +- Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden). +- Enable/disable lock icon in the settings. Useful if fullscreen mode is on. - The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further. -- There are no design settings, as your bangle sys settings are used. +- Your bangle uses the sys color settings so you can change the color too. + +## Menu structure +2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to trigger HomeAssistant. + +Simply click left / right to go through the menu entries such as Bangle, Weather etc. +and click up/down to move into this sub-menu. You can then click in the middle of the screen +to e.g. send a trigger via HomeAssistant once you selected it. The actions really depend +on the app that provide this sub-menu through the `clkinfo` module. + +``` + Bangle -- Agenda -- Weather -- HomeAssistant + | | | | + Battery Entry 1 Temperature Trigger1 + | | | | + Steps ... ... ... + | + ... +``` ## Thanks to -Icons created by Flaticon - +- Thanks to Gordon Williams not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located. +- Icons created by Flaticon ## Creator [David Peer](https://github.com/peerdavid) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 2d629abe8..7dcca9d75 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -1,22 +1,25 @@ -/************ +/************************************************ * Includes */ const locale = require('locale'); const storage = require('Storage'); +const clock_info = require("clock_info"); -/************ - * Statics + +/************************************************ + * Globals */ const SETTINGS_FILE = "bwclk.setting.json"; -const TIMER_IDX = "bwclk"; const W = g.getWidth(); const H = g.getHeight(); +var lock_input = false; -/************ + +/************************************************ * Settings */ let settings = { - fullscreen: false, + screen: "Normal", showLock: true, hideColon: false, menuPosX: 0, @@ -28,22 +31,10 @@ for (const key in saved_settings) { settings[key] = saved_settings[key] } - -/************ +/************************************************ * Assets */ // Manrope font -Graphics.prototype.setXLargeFont = function(scale) { - // Actual height 53 (55 - 3) - this.setFontCustom( - E.toString(require('heatshrink').decompress(atob('AHM/8AIG/+AA4sD/wQGh/4EWQA/AC8YA40HNA0BRY8/RY0P/6LFgf//4iFA4IiFj4HBEQkHCAQiDHIIZGv4HCFQY5BDAo5CAAIpDDAfACA3wLYv//hsFKYxcCMgoiBOooiBQwwiBS40AHIgA/ACS/DLYjYCBAjQEBAYQDBAgHDUAbyDZQi3CegoHEVQQZFagUfW4Y0DaAgECaIJSEFYMPbIYNDv5ACGAIrBCgJ1EFYILCAAQWCj4zDGgILCegcDEQRNDHIIiCHgZ2BEQShFIqUDFYidCh5ODg4NCn40DAgd/AYR5BDILZEAAIMDAAYVCh7aHdYhKDbQg4Dv7rGBAihFCAwIDCAgA/AB3/eoa7GAAk/dgbVGDJrvCDK67DDIjaGdYpbCdYonCcQjjDEVUBEQ4A/AEMcAYV/NAUHcYUDawd/cYUPRYSmBBgaLBToP8BgYiBSgIiCj4iCg//EQSuDW4IMDVwYiCBgIiBBgrRDCATeBaIYqCv70DCgT4CEQMfIgQZBBoRnDv/3EQIvBDIffEQMHFwReBRYUfOgX/+IiDKIeHEQRRECwUHKwIuB8AiDIoJEBCwZFCv/4HIZaBIgPAEQS2CUYQiCD4SABEQcfOwIZBEQaHBO4RcEAAI/BEQQgBSIQiDTIRZBEQZuBVYQiDHoKWCEQQICFQIiDBAQeCEQQA/AANwA40BLIJ5BO4JWCBAUPAYR5En7RBUIQECN4SYCQQIiEh6CCEQk/BoQiBgYeCBoTrCAgT0CCgIfCFYQiBg4IBGgIiDj6rBg4rCBYLRDFYIiBbYIfBLgQiBIQYiD4JCCLgf/bQIWDBYV/EQV/BYXz/5FBgIiD5//IowZBD4M/NAX/BIPgDIJoC//5GgKUDn//4f/8KLE/wTBAAI8BEQPwj4HBVwYmBDgIZDN4QZCGYKJCHQP/JoSgCBATrCh5dBKITVDG4gICAAbvDAH5SCL4QADK4J5CCAiTCCAp1BCAqCDCAgiGCAIiFCAQiFeoIiFg6/FCAgiECAXnEQgQB/kfEQYQC4F/EQYQCgIiDfoIQBg4iDCAUAEQZUCcgIiDDIIQBEQhuBBoIiENoYiFDwQiECAQiFwEBPQQNCAQKDDEYMDDoMfRh4iGUwqvEESBiBaQ5oEbgr0FNAo+EEIwA+oAHGgJoFRAMHe4L0CAALNBBAT0BfwScDCAXweAL0DWgUPQYQiDwF/QYQiC/zTB+C0FBAL0CEQYIBGgMPCgIxBg4rCJIKsCh5IBBwTPCj4WBgYLBZ4V/MAIiBBQQrBEQYtCBYQiCO4QLFCwgiDIQIiGIoMHEQpFBn5FFD4JoENwRoGDgSUCAoKfBw//DgIiCT4auCFwN/T4RRET4TaCEQKoCDIQiCGgK/DAAQICdYQACHoIqCBAoQFEwIhFAH4AFQIROEj4IGXwIIGNwIACbgIhEBAiRCVwoqDTogHEW4QZFXgIZB/z9Cv49CF4MPBwI0Ca4LlB8ATCJoP4AoINDfQPAg7PBg4cBBwUfD4MfFYILCCwgOCf4QLEwEPCwILCgJaBn4WBBYQxCIQQiD+EDCYI5CBYRQBIo4fBMQIuBC4N/NAv8AoIcBSgU/FYIIBZIYrCW4hOCXIQZCgYUBv7jEh4uBZAscewZ8CgEgUYT0EEoQIBA4gICFQQIEHYQA+KQzdDAArdCAArpCEScHaIQiEvwiGe4QiFUwQiEbgIiFYIL0DEQTkBEQrJEEQc/cYYiCg4HBDIQiCfoRoEHQLaDEQQHBbQYiBCAT8Dn/BCAoXBJYP/OgZKC/6OEEARLCEQZLEEQZLEEQjKFEQI6EEQZLDEQbsGEQLjGYYYA/JIxzEg/AfgJSDAoPgfgiDC8COFAoPnaQj6CAAR+CW4TCFA4i6CDIqhCDIfwHoYHCYIN/GgKuBJ4JDBFYUf/C5CBYIZBv/Ag4ZBg4rBBYQTBAQIcBg4FBn5UBAQUfFwIfCEQeAgYfBAQUBFAKbCAQQiCGwIiE+A2BwBFNwE/AoM/EQJoIWwKCCh4cBFYKUERYV/W46uHFYIZGaJA0B/glBGYT0JIITiEMIJvCFQQAEHYQA/ABBlEOIhdGQAIRFSgQIBgQICn4IB8EAjiBCUYglCbQYeBEoQZCTwM/CYIZD/gEBUwIzBJ4UHYAU/EwIrBh4rCAoIXCn4rBCgUDAQN/FYMfBYIXBCYJnCBYXggf8HgQLCwEPEQQuBgJOECwILDCwgiLHIUHBYJFGD4IxBgYWCn4rBBwJoFDIYNBCgPADgKHBRYfDBQN/GAIrBToTLDVwYACDILiCWAb8DAAYzBYAjTCAAI9BAARNCBAoqCBAgQDFgbYCAH4AufgQACf4T8CAAT/CfgQACBwITCAAYOBCYQioh4iEAHQA=='))), - 46, - atob("FR4uHyopKyksJSssGA=="), - 70+(scale<<8)+(1<<16) - ); -}; - - Graphics.prototype.setLargeFont = function(scale) { // Actual height 47 (48 - 2) this.setFontCustom( @@ -55,14 +46,12 @@ Graphics.prototype.setLargeFont = function(scale) { return this; }; - Graphics.prototype.setMediumFont = function(scale) { // Actual height 41 (42 - 2) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAB/AAAAAAAP/AAAAAAD//AAAAAA///AAAAAP///AAAAB///8AAAAf///AAAAH///wAAAB///+AAAAH///gAAAAH//4AAAAAH/+AAAAAAH/wAAAAAAH8AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAH////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gAAH+AAD+AAAD/AAH8AAAB/AAH4AAAA/gAH4AAAAfgAH4AAAAfgAPwAAAAfgAPwAAAAfgAPwAAAAfgAHwAAAAfgAH4AAAAfgAH4AAAA/gAH8AAAA/AAD+AAAD/AAD/gAAH/AAB/////+AAB/////8AAA/////4AAAf////wAAAH////gAAAB///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAfwAAAAAAA/gAAAAAAA/AAAAAAAB/AAAAAAAD+AAAAAAAD8AAAAAAAH8AAAAAAAH//////AAH//////AAH//////AAH//////AAH//////AAH//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAA/AAAP4AAB/AAAf4AAD/AAA/4AAD/AAB/4AAH/AAD/4AAP/AAH/AAAf/AAH8AAA//AAH4AAB//AAP4AAD//AAPwAAH+/AAPwAAP8/AAPwAAf4/AAPwAA/4/AAPwAA/w/AAPwAB/g/AAPwAD/A/AAP4AH+A/AAH8AP8A/AAH/A/4A/AAD///wA/AAD///gA/AAB///AA/AAA//+AA/AAAP/8AA/AAAD/wAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAH4AAAHwAAH4AAAH4AAH4AAAH8AAH4AAAP+AAH4AAAH+AAH4A4AB/AAH4A+AA/AAH4B/AA/gAH4D/AAfgAH4H+AAfgAH4P+AAfgAH4f+AAfgAH4/+AAfgAH5/+AAfgAH5//AAfgAH7+/AA/gAH/8/gB/AAH/4f4H/AAH/wf//+AAH/gP//8AAH/AH//8AAH+AD//wAAH8AB//gAAD4AAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAD/AAAAAAAP/AAAAAAB//AAAAAAH//AAAAAAf//AAAAAB///AAAAAH///AAAAAf/8/AAAAB//w/AAAAH/+A/AAAA//4A/AAAD//gA/AAAH/+AA/AAAH/4AA/AAAH/gAA/AAAH+AAA/AAAHwAAA/AAAHAAf///AAEAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAP/AHgAAH///AP4AAH///gP8AAH///gP8AAH///gP+AAH///gD/AAH/A/AB/AAH4A/AA/gAH4A+AAfgAH4B+AAfgAH4B+AAfgAH4B8AAfgAH4B8AAfgAH4B+AAfgAH4B+AAfgAH4B+AA/gAH4B/AA/AAH4A/gD/AAH4A/4H+AAH4Af//+AAH4AP//8AAH4AP//4AAHwAD//wAAAAAB//AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAD////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gP4H+AAD/AfgD/AAH8A/AB/AAH8A/AA/gAH4B+AAfgAH4B+AAfgAPwB8AAfgAPwB8AAfgAPwB+AAfgAPwB+AAfgAH4B+AAfgAH4B/AA/gAH8B/AB/AAH+A/wD/AAD+A/8P+AAB8Af//+AAB4AP//8AAAwAH//4AAAAAD//gAAAAAA//AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAHAAPwAAAA/AAPwAAAD/AAPwAAAf/AAPwAAB//AAPwAAP//AAPwAA//8AAPwAH//wAAPwAf/+AAAPwB//4AAAPwP//AAAAPw//8AAAAP3//gAAAAP//+AAAAAP//wAAAAAP//AAAAAAP/4AAAAAAP/gAAAAAAP+AAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAH+A//gAAAf/h//4AAA//z//8AAB/////+AAD/////+AAD///+H/AAH+H/4B/AAH8B/wA/gAH4A/gAfgAH4A/gAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAH4A/gAfgAH4A/gAfgAH8B/wA/gAH/H/4B/AAD///+H/AAD/////+AAB/////+AAA//z//8AAAf/h//4AAAH+A//gAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD/8AAAAAAP/+AAAAAAf//AAcAAA///gA8AAB///wB+AAD/x/4B/AAD+AP4B/AAH8AH8A/gAH4AH8A/gAH4AD8AfgAP4AD8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAH4AD8AfgAH4AD4A/gAH8AH4B/AAD+APwD/AAD/g/wP+AAB/////+AAA/////8AAAf////4AAAP////wAAAH////AAAAA///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DxcjFyAfISAiHCAiEg=="), 54+(scale<<8)+(1<<16)); return this; }; - Graphics.prototype.setSmallFont = function(scale) { // Actual height 28 (27 - 0) this.setFontCustom( @@ -74,6 +63,16 @@ Graphics.prototype.setSmallFont = function(scale) { return this; }; +Graphics.prototype.setMiniFont = function(scale) { + // Actual height 16 (15 - 0) + this.setFontCustom( + atob('AAAAAAAAAAAAAP+w/5AAAAAA4ADgAOAA4AAAAAAAAAABgBmAGbAb8D+A+YDZ8B/wf4D5gJmAGQAQAAAAAAAeOD8cMwzxj/GPMYwc/Az4AAAAAHAA+DDIYMjA+YBzAAYADeA7MHMw4zDD4ADAAAAz4H/wzjDHMMMwwbBj4APgADAAAAAA4ADgAAAAAAAAAAfwH/54B+ABAAAAAOABeAcf/gfwAAAAACAAaAD4APgAOABgAAAAAAACAAIAAgA/wAMAAgACAAAAAAAAPAA4AAAAAAIAAgACAAIAAgAAAAAAADAAMAAAAAAAcAfwf4D4AIAAAAA/wH/gwDDAMMAwwDB/4D/AAAAAAGAAwAD/8P/wAAAAAHAw8HDA8MHww7DnMH4wGBAAAMBgyHDcMPww/DDv4MfAAAAAAAHgD+A+YPhgwGAH8AfwAEAAAAAA/GD8cMwwzDDMMM5wx+ABgAAAP8B/4MwwzDDMMMwwx+ADwAAAgADAAMBwwfDPgP4A8ADAAAAAe+D/8M4wxjDGMP5wf+ABwAAAfAB+cMYwwjDCMMYwf+A/wAAAAAAAAAxgBCAAAAAAAAAYPBA4AAAAAAAAAgAHAA+AHMAYYAAAAAAAAAAAAAAJAAkACQAJAAkACQAJAAkAAAAAAAAAAAAAABhgHMAPgAcAAgAAAAAAAABgAOAAwbDDsMYA/AA4AAAAAAAD4A/wGBgxzDPsMyQjJDPkM+wYIBxgD+AAAAAAABAA8A/gf8DwwODA/sAfwAHwADAAAP/w//DGMMYwxjDOMP9we+ABwA8AP8Bw4MAwwDDAMMAwwDDgcHDgMMAAAAAA//D/8MAwwDDAMMAw4HB/4D/AAAAAAP/w//DGMMYwxjDGMMQwgBAAAP/w//DDAMMAwwDDAMAADwA/wHDgwDDAMMAwwDDCMOJwc+ADwAAA//D/8AMAAwADAAMAAwD/8P/wAAAAAP/w//AAAABgAHAAMAAwAHD/4P+AAAAAAP/w//AOAB+AOcBw4MBwgDAAEAAA//D/8AAwADAAMAAwADAAAP/w//A8AA8AA+AA8AHwB8AeAHgA//D/8AAAAAD/8P/wcAAcAA8AA4AB4P/w//AAAA8AP8Bw4MAwwDDAMMAwwDDgcH/gP8AAAAAA//D/8MMAwwDDAMYA7gB8ABgADwA/wHDgwDDAMMAwwDDA8ODwf/A/8AAAAAD/8P/wwwDDAMMAx4Dv4HxwEBAAAHjg/HDMMMYwxjDGMONwc+ABwMAAwADAAMAA//D/8MAAwADAAIAAAAD/wP/gAHAAMAAwADAAMAHg/8AAAMAA+AA/AAfgAPAA8AfgPwD4AMAAwAD4AD+AA/AA8A/g/gDwAP4AH8AB8APwH8D8AMAAgBDAMPDgO8APAB8AOcDw8MAwgBCAAOAAeAAeAAfwH/B4AOAAwAAAAMAwwPDB8Mew3jD4MPAwwDAAAAAAAAB//3//QABAAAAAAADgAP4AH+AB8AAQAABAAEAAf/9//wAAAAAAAAAAGAAwAGAAwABgADAAGAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAQA3wHbAZMBswGzAf4A/wAAAAAP/w//AYMBgwGDAYMA/gB8AAAAEAD+Ae8BgwGDAYMBgwDGAAAAMAD+Ae8BgwGDAYMBhw//D/8AAAAYAP4B/wGTAZMBkwGTAP4AcAEAAYAP/w//CQAJAAAwAP4hz3GDMQMxAzGHcf/h/8AAAAAP/w//AYABgAGAAYAA/wB/AAAAAA3/Df8AAAAAOf/9//AAAAAP/w//ADgAfADGAYMBAQAAD/8P/wAAAAAB/wH/AYABgAGAAf8A/wGAAYABgAH/AP8AAAAAAf8B/wGAAYABgAGAAP8AfwAAADAA/gHvAYMBgwGDAYMA/gB8AAAAAAH/8f/xgwGDAYMBgwD+AHwAAAAwAP4B7wGDAYMBgwGHAf/x//AAAAAB/wH/AYABgAEAAAAA5gHzAbMBkwGbAd8AzgEAAYAP/wf/AQMBAwAAAAAB/gH/AAMAAwADAAcB/wH/AAABAAHgAPwAHwAPAH4B8AGAAQAB8AB+AA8APwHwAeAA/AAPAD8B+AHAAQEBgwHOAHwAOAD+AccBAwAAAQAB4AD4EB/wB8A/APgBwAAAAAEBgwGPAZ8B8wHjAcMBAQAAAAAABgf/9/n2AAAAAAAP/w//AAAEAAYAB/nz//AGAAAAAAAAAAAAcABgAGAAcAAwAHAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'), + 32, + atob("AwUHDwoOCwQHBwcJBAcEBgoGCQkKCQoICQoFBQoMCgkPCgoMCwkICwsECAoIDgsMCgwKCgoLCg8KCQoHBgcLCwgJCgkKCQYKCgQECAQOCgoKCgYIBwoIDAkJCAcEBwsQ"), + 16+(scale<<8)+(1<<16) + ); + return this; +}; function imgLock(){ return { @@ -83,279 +82,100 @@ function imgLock(){ } } -function imgSteps(){ - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/H///wv4CBn4CD8ACCj4IBj8f+Eeh/wjgCBngCCg/4nEH//4h/+jEP/gRBAQX+jkf/wgB//8GwP4FoICDHgICCBwIA==")) - } -} -function imgBattery(){ - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AN4EAg4TBgd///9oEAAQv8ARQRDDQQgCEwQ4OA")) - } -} - -function imgCharging() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("//+v///k///4AQPwBANgBoMxBoMb/P+h/w/kH8H4gfB+EBwfggHH4EAt4CBn4CBj4CBh4FCCIO/8EB//Agf/wEH/8Gh//x////fAQIA=")) - } -} - -function imgBpm() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AOn4CD/wCCjgCCv/8jF/wGYgOA5MB//BC4PDAQnjAQPnAQgANA")) - } -} - -function imgTemperature() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("//D///wICBjACBngCNkgCP/0kv/+s1//nDn/8wICEBAIOC/08v//IYJECA==")) - } -} - -function imgWeather(){ - return { - width : 24, height : 24, bpp : 1, - transparent : 0, - buffer : require("heatshrink").decompress(atob("AAcYAQ0MgEwAQUAngLB/8AgP/wACCgf/4Fz//OAQQICCIoaCEAQpGHA4ACA=")) - } -} - -function imgWind () { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/0f//8h///Pn//zAQXzwf/88B//mvGAh18gEevn/DIICB/PwgEBAQMHBAIADFwM/wEAGAP/54CD84CE+eP//wIQU/A==")) - } -} - -function imgTimer() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/+B/4CD84CEBAPygFP+F+h/x/+P+fz5/n+HnAQNn5/wuYCBmYCC5kAAQfOgFz80As/ngHn+fD54mC/F+j/+gF/HAQA==")) - } -} - -function imgWatch() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC")) - } -} - -function imgHomeAssistant() { - return { - width : 48, height : 48, bpp : 1, - transparent : 0, - buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA==")) - } -} - - -/************ - * 2D MENU with entries of: - * [name, icon, opt[customDownFun], opt[customUpFun], opt[customCenterFun]] - * +/************************************************ + * Menu */ -var menu = [ - [ - function(){ return [ null, null ] }, - ], - [ - function(){ return [ "Bangle", imgWatch() ] }, - function(){ return [ E.getBattery() + "%", Bangle.isCharging() ? imgCharging() : imgBattery() ] }, - function(){ return [ getSteps(), imgSteps() ] }, - function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm()] }, +// Custom bwItems menu - therefore, its added here and not in a clkinfo.js file. +var bwItems = { + name: null, + img: null, + items: [ + { name: "WeekOfYear", + get: () => ({ text: "Week " + weekOfYear(), img: null}), + show: function() { bwItems.items[0].emit("redraw"); }, + hide: function () {} + }, ] -] +}; -/* - * Timer Menu - */ -try{ - require('sched'); - menu.push([ - function(){ - var text = isAlarmEnabled() ? getAlarmMinutes() + " min." : "Timer"; - return [text, imgTimer(), () => decreaseAlarm(), () => increaseAlarm(), null ] - }, - ]); -} catch(ex) { - // If sched is not installed, we hide this menu item -} - -/* - * WEATHER MENU - */ -if(storage.readJSON('weather.json') !== undefined){ - menu.push([ - function(){ return [ "Weather", imgWeather() ] }, - function(){ return [ getWeather().temp, imgTemperature() ] }, - function(){ return [ getWeather().wind, imgWind() ] }, - ]); +function weekOfYear() { + var date = new Date(); + date.setHours(0, 0, 0, 0); + // Thursday in current week decides the year. + date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); + // January 4 is always in week 1. + var week1 = new Date(date.getFullYear(), 0, 4); + // Adjust to Thursday in week 1 and count number of weeks from date to week1. + return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 + - 3 + (week1.getDay() + 6) % 7) / 7); } -/* - * HOME ASSISTANT MENU - */ -try{ - var triggers = require("ha.lib.js").getTriggers(); - var haMenu = [ - function(){ return [ "Home", imgHomeAssistant() ] }, - ]; +// Load menu +var menu = clock_info.load(); +menu = menu.concat(bwItems); - triggers.forEach(trigger => { - haMenu.push(function(){ - return [trigger.display, trigger.getIcon(), () => {}, () => {}, function(){ - var ha = require("ha.lib.js"); - ha.sendTrigger("TRIGGER_BW"); - ha.sendTrigger(trigger.trigger); - }] - }); + +// Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it. +if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){ + settings.menuPosX = 0; + settings.menuPosY = 0; +} + +// Set draw functions for each item +menu.forEach((menuItm, x) => { + menuItm.items.forEach((item, y) => { + function drawItem() { + // For the clock, we have a special case, as we don't wanna redraw + // immediately when something changes. Instead, we update data each minute + // to save some battery etc. Therefore, we hide (and disable the listener) + // immedeately after redraw... + item.hide(); + + // After drawing the item, we enable inputs again... + lock_input = false; + + var info = item.get(); + drawMenuItem(info.text, info.img); + } + + item.on('redraw', drawItem); }) - menu.push(haMenu); -} catch(ex){ - // If HomeAssistant is not installed, we hide this item -} +}); -function getMenuEntry(){ - // In case the user removes HomeAssistant entries, showInfo - // could be larger than infoArray.length... - settings.menuPosX = settings.menuPosX % menu.length; - settings.menuPosY = settings.menuPosY % menu[settings.menuPosX].length; - return menu[settings.menuPosX][settings.menuPosY](); -} - - -/************ - * Helper - */ -function getSteps() { - var steps = 0; - try{ - if (WIDGETS.wpedom !== undefined) { - steps = WIDGETS.wpedom.getSteps(); - } else if (WIDGETS.activepedom !== undefined) { - steps = WIDGETS.activepedom.getSteps(); - } else { - steps = Bangle.getHealthStatus("day").steps; - } - } catch(ex) { - // In case we failed, we can only show 0 steps. +function canRunMenuItem(){ + if(settings.menuPosY == 0){ + return false; } - steps = Math.round(steps/100) / 10; // This ensures that we do not show e.g. 15.0k and 15k instead - return steps + "k"; + var menuEntry = menu[settings.menuPosX]; + var item = menuEntry.items[settings.menuPosY-1]; + return item.run !== undefined; } -function getWeather(){ - var weatherJson; - - try { - weatherJson = storage.readJSON('weather.json'); - var weather = weatherJson.weather; - - // Temperature - weather.temp = locale.temp(weather.temp-273.15); - - // Humidity - weather.hum = weather.hum + "%"; - - // Wind - const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/); - weather.wind = Math.round(wind[1]) + "kph"; - - return weather - - } catch(ex) { - // Return default +function runMenuItem(){ + if(settings.menuPosY == 0){ + return; } - return { - temp: " ? ", - hum: " ? ", - txt: " ? ", - wind: " ? ", - wdir: " ? ", - wrose: " ? " - }; -} - - -function isAlarmEnabled(){ + var menuEntry = menu[settings.menuPosX]; + var item = menuEntry.items[settings.menuPosY-1]; try{ - var alarm = require('sched'); - var alarmObj = alarm.getAlarm(TIMER_IDX); - if(alarmObj===undefined || !alarmObj.on){ - return false; + var ret = item.run(); + if(ret){ + Bangle.buzz(300, 0.6); } - - return true; - - } catch(ex){ } - return false; -} - - -function getAlarmMinutes(){ - if(!isAlarmEnabled()){ - return -1; + } catch (ex) { + // Simply ignore it... } - - var alarm = require('sched'); - var alarmObj = alarm.getAlarm(TIMER_IDX); - return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000)); } -function increaseAlarm(){ - try{ - var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0; - var alarm = require('sched') - alarm.setAlarm(TIMER_IDX, { - timer : (minutes+5)*60*1000, - }); - alarm.reload(); - } catch(ex){ } -} - - -function decreaseAlarm(){ - try{ - var minutes = getAlarmMinutes(); - minutes -= 5; - - var alarm = require('sched') - alarm.setAlarm(TIMER_IDX, undefined); - - if(minutes > 0){ - alarm.setAlarm(TIMER_IDX, { - timer : minutes*60*1000, - }); - } - - alarm.reload(); - } catch(ex){ } -} - - -/************ - * DRAW +/************************************************ + * Draw */ function draw() { // Queue draw again @@ -363,7 +183,7 @@ function draw() { // Draw clock drawDate(); - drawTime(); + drawMenuAndTime(); drawLock(); drawWidgets(); } @@ -371,12 +191,12 @@ function draw() { function drawDate(){ // Draw background - var y = H/5*2; - g.reset().clearRect(0,0,W,W); + var y = H/5*2 + (isFullscreen() ? 0 : 8); + g.reset().clearRect(0,0,W,y); // Draw date y = parseInt(y/2)+4; - y += settings.fullscreen ? 0 : 13; + y += isFullscreen() ? 0 : 8; var date = new Date(); var dateStr = date.getDate(); dateStr = ("0" + dateStr).substr(-2); @@ -395,15 +215,12 @@ function drawDate(){ g.setMediumFont(); g.setColor(g.theme.fg); - g.drawString(dateStr, W/2 - fullDateW / 2, y+1); + g.drawString(dateStr, W/2 - fullDateW / 2, y+2); } -function drawTime(){ +function drawTime(y, smallText){ // Draw background - var y = H/5*2 + (settings.fullscreen ? 0 : 8); - g.setColor(g.theme.fg); - g.fillRect(0,y,W,H); var date = new Date(); // Draw time @@ -419,45 +236,65 @@ function drawTime(){ // Set y coordinates correctly y += parseInt((H - y)/2) + 5; - var menuEntry = getMenuEntry(); - var menuName = menuEntry[0]; - var menuImg = menuEntry[1]; - var printImgLeft = settings.menuPosY != 0; - // Show large or small time depending on info entry - if(menuName == null){ - if(settings.hideColon){ - g.setXLargeFont(); - } else { - g.setLargeFont(); - } - } else { + if(smallText){ y -= 15; g.setMediumFont(); + } else { + g.setLargeFont(); } g.drawString(timeStr, W/2, y); +} - // Draw menu if set - if(menuName == null){ +function drawMenuItem(text, image){ + // First clear the time region + var y = H/5*2 + (isFullscreen() ? 0 : 8); + + g.setColor(g.theme.fg); + g.fillRect(0,y,W,H); + + // Draw menu text + var hasText = (text != null && text != ""); + if(hasText){ + g.setFontAlign(0,0); + + // For multiline text we show an even smaller font... + text = String(text); + if(text.split('\n').length > 1){ + g.setMiniFont(); + } else { + g.setSmallFont(); + } + + var imgWidth = image == null ? 0 : 24; + var strWidth = g.stringWidth(text); + g.setColor(g.theme.fg).fillRect(0, 149-14, W, H); + g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 149+3); + + if(image != null){ + var scale = imgWidth / image.width; + g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 149 - parseInt(imgWidth/2), {scale: scale}); + } + } + + // Draw time + drawTime(y, hasText); +} + + +function drawMenuAndTime(){ + var menuEntry = menu[settings.menuPosX]; + + // The first entry is the overview... + if(settings.menuPosY == 0){ + drawMenuItem(menuEntry.name, menuEntry.img); return; } - y += 35; - g.setFontAlign(0,0); - g.setSmallFont(); - var imgWidth = 0; - if(menuImg !== undefined){ - imgWidth = 24.0; - var strWidth = g.stringWidth(menuName); - var scale = imgWidth / menuImg.width; - g.drawImage( - menuImg, - W/2 + (printImgLeft ? -strWidth/2-2 : strWidth/2+2) - parseInt(imgWidth/2), - y - parseInt(imgWidth/2), - { scale: scale } - ); - } - g.drawString(menuName, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3); + // Draw item if needed + lock_input = true; + var item = menuEntry.items[settings.menuPosY-1]; + item.show(); } @@ -470,7 +307,7 @@ function drawLock(){ function drawWidgets(){ - if(settings.fullscreen){ + if(isFullscreen()){ for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} } else { Bangle.drawWidgets(); @@ -478,9 +315,19 @@ function drawWidgets(){ } +function isFullscreen(){ + var s = settings.screen.toLowerCase(); + if(s == "dynamic"){ + return Bangle.isLocked() + } else { + return s == "full" + } +} -/* - * Draw timeout + + +/************************************************ + * Listener */ // timeout used to update every minute var drawTimeout; @@ -508,6 +355,13 @@ Bangle.on('lcdPower',on=>{ Bangle.on('lock', function(isLocked) { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; + + if(!isLocked && settings.screen.toLowerCase() == "dynamic"){ + // If we have to show the widgets again, we load it from our + // cache and not through Bangle.loadWidgets as its much faster! + for (let wd of WIDGETS) {wd.draw=wd._draw;wd.area=wd._area;} + } + draw(); }); @@ -516,13 +370,13 @@ Bangle.on('charging',function(charging) { drawTimeout = undefined; // Jump to battery - settings.menuPosX = 1; + settings.menuPosX = 0; settings.menuPosY = 1; draw(); }); Bangle.on('touch', function(btn, e){ - var widget_size = settings.fullscreen ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better... + var widget_size = isFullscreen() ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better... var left = parseInt(g.getWidth() * 0.22); var right = g.getWidth() - left; var upper = parseInt(g.getHeight() * 0.22) + widget_size; @@ -534,17 +388,15 @@ Bangle.on('touch', function(btn, e){ var is_right = e.x > right && !is_upper && !is_lower; var is_center = !is_upper && !is_lower && !is_left && !is_right; + if(lock_input){ + return; + } + if(is_lower){ Bangle.buzz(40, 0.6); - settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].length; + settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1); - // Handle custom menu entry function - var menuEntry = getMenuEntry(); - if(menuEntry.length > 2){ - menuEntry[2](); - } - - drawTime(); + drawMenuAndTime(); } if(is_upper){ @@ -554,22 +406,16 @@ Bangle.on('touch', function(btn, e){ Bangle.buzz(40, 0.6); settings.menuPosY = settings.menuPosY-1; - settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].length-1 : settings.menuPosY; + settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY; - // Handle custom menu entry function - var menuEntry = getMenuEntry(); - if(menuEntry.length > 3){ - menuEntry[3](); - } - - drawTime(); + drawMenuAndTime(); } if(is_right){ Bangle.buzz(40, 0.6); settings.menuPosX = (settings.menuPosX+1) % menu.length; settings.menuPosY = 0; - drawTime(); + drawMenuAndTime(); } if(is_left){ @@ -577,23 +423,12 @@ Bangle.on('touch', function(btn, e){ settings.menuPosY = 0; settings.menuPosX = settings.menuPosX-1; settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX; - drawTime(); + drawMenuAndTime(); } if(is_center){ - var menuEntry = getMenuEntry(); - if(menuEntry.length > 4){ - Bangle.buzz(80, 0.6).then(()=>{ - try{ - menuEntry[4](); - setTimeout(()=>{ - Bangle.buzz(80, 0.6); - }, 250); - } catch(ex){ - // In case it fails, we simply ignore it. - } - } - ); + if(canRunMenuItem()){ + runMenuItem(); } } }); @@ -608,17 +443,24 @@ E.on("kill", function(){ }); -/* - * Draw clock the first time +/************************************************ + * Startup Clock */ + // The upper part is inverse i.e. light if dark and dark if light theme // is enabled. In order to draw the widgets correctly, we invert the // dark/light theme as well as the colors. g.setTheme({bg:g.theme.fg,fg:g.theme.bg, dark:!g.theme.dark}).clear(); -// Load widgets and draw clock the first time -Bangle.loadWidgets(); -draw(); - // Show launcher when middle button pressed Bangle.setUI("clock"); + +// Load widgets and draw clock the first time +Bangle.loadWidgets(); + +// Cache draw function for dynamic screen to hide / show widgets +// Bangle.loadWidgets() could also be called later on but its much slower! +for (let wd of WIDGETS) {wd._draw=wd.draw; wd._area=wd.area;} + +// Draw first time +draw(); diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index 45d337ebf..fbae0e1e7 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -1,8 +1,8 @@ { "id": "bwclk", "name": "BW Clock", - "version": "0.13", - "description": "A very minimalistic clock with date and time in focus.", + "version": "0.23", + "description": "A very minimalistic clock to mainly show date and time.", "readme": "README.md", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}], diff --git a/apps/bwclk/screenshot_3.png b/apps/bwclk/screenshot_3.png index f9a9a7d3f..8d982cac4 100644 Binary files a/apps/bwclk/screenshot_3.png and b/apps/bwclk/screenshot_3.png differ diff --git a/apps/bwclk/settings.js b/apps/bwclk/settings.js index a421e81a9..116253fda 100644 --- a/apps/bwclk/settings.js +++ b/apps/bwclk/settings.js @@ -4,7 +4,7 @@ // initialize with default settings... const storage = require('Storage') let settings = { - fullscreen: false, + screen: "Normal", showLock: true, hideColon: false, }; @@ -17,15 +17,16 @@ storage.write(SETTINGS_FILE, settings) } - + var screenOptions = ["Normal", "Dynamic", "Full"]; E.showMenu({ '': { 'title': 'BW Clock' }, '< Back': back, - 'Fullscreen': { - value: settings.fullscreen, - format: () => (settings.fullscreen ? 'Yes' : 'No'), - onchange: () => { - settings.fullscreen = !settings.fullscreen; + 'Screen': { + value: 0 | screenOptions.indexOf(settings.screen), + min: 0, max: 2, + format: v => screenOptions[v], + onchange: v => { + settings.screen = screenOptions[v]; save(); }, }, diff --git a/apps/calclock/ChangeLog b/apps/calclock/ChangeLog new file mode 100644 index 000000000..b67f29e94 --- /dev/null +++ b/apps/calclock/ChangeLog @@ -0,0 +1,3 @@ +0.01: Initial version +0.02: More compact rendering & app icon +0.03: Tell clock widgets to hide. diff --git a/apps/calclock/README.md b/apps/calclock/README.md new file mode 100644 index 000000000..2b4e93a0c --- /dev/null +++ b/apps/calclock/README.md @@ -0,0 +1,9 @@ +# Calendar Clock - Your day at a glance + +This clock shows a chronological view of your current and future events. +It uses events synced from Gadgetbridge to achieve this. + +The current time and date is highlighted in cyan. + +## Screenshot +![](screenshot.png) diff --git a/apps/calclock/calclock-icon.js b/apps/calclock/calclock-icon.js new file mode 100644 index 000000000..9d5514d80 --- /dev/null +++ b/apps/calclock/calclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwgpm5gAB4AVRhgWCAAQWWDCARC/4ACJR4uB54WDAAP8DBotFGIgXLFwv4GAouQC4gwMLooXF/gXJOowXGJBIXBCIgXQxgXLMAIXXMAmIC5OIx4XJhH/wAXIxnIC78IxGIHoIABI44MBC4wQBEQIDB5gXGPAJgEC6IxBC5oABC4wwDa4YTCxAWD5nPDAzvGFYgAB5AXWJBK+GcAq5CGBIuBC5X4GBIJBdoQXB/GIx4CDPJAuEC5JoCDAgWBFwYXJxCBIFwYXKYwoACCwZ3IPQoWIC5YABGYIABCwpHKAQYMBCwwX/C5QAMC8R3/R/4XNhAXNwAXHgGIABgWIAFwA==")) diff --git a/apps/calclock/calclock.js b/apps/calclock/calclock.js new file mode 100644 index 000000000..343d95c04 --- /dev/null +++ b/apps/calclock/calclock.js @@ -0,0 +1,119 @@ +var calendar = []; +var current = []; +var next = []; + +function updateCalendar() { + calendar = require("Storage").readJSON("android.calendar.json",true)||[]; + calendar = calendar.filter(e => isActive(e) || getTime() <= e.timestamp); + calendar.sort((a,b) => a.timestamp - b.timestamp); + + current = calendar.filter(isActive); + next = calendar.filter(e=>!isActive(e)); +} + +function isActive(event) { + var timeActive = getTime() - event.timestamp; + return timeActive >= 0 && timeActive <= event.durationInSeconds; +} +function zp(str) { + return ("0"+str).substr(-2); +} + +function drawEventHeader(event, y) { + g.setFont("Vector", 24); + + var time = isActive(event) ? new Date() : new Date(event.timestamp * 1000); + var timeStr = zp(time.getHours()) + ":" + zp(time.getMinutes()); + g.drawString(timeStr, 5, y); + y += 24; + + g.setFont("12x20", 1); + if (isActive(event)) { + g.drawString(zp(time.getDate())+". " + require("locale").month(time,1),15*timeStr.length,y-21); + } else { + var offset = 0-time.getTimezoneOffset()/1440; + var days = Math.floor((time.getTime()/1000)/86400+offset)-Math.floor(getTime()/86400+offset); + if(days > 0) { + var daysStr = days===1?/*LANG*/"tomorrow":/*LANG*/"in "+days+/*LANG*/" days"; + g.drawString(daysStr,15*timeStr.length,y-21); + } + } + return y; +} + +function drawEventBody(event, y) { + g.setFont("12x20", 1); + var lines = g.wrapString(event.title, g.getWidth()-10); + if (lines.length > 2) { + lines = lines.slice(0,2); + lines[1] = lines[1].slice(0,-3)+"..."; + } + g.drawString(lines.join('\n'), 5, y); + y+=20 * lines.length; + if(event.location) { + g.drawImage(atob("DBSBAA8D/H/nDuB+B+B+B3Dn/j/B+A8A8AYAYAYAAAAAAA=="),5,y); + g.drawString(event.location, 20, y); + y+=20; + } + y+=5; + return y; +} + +function drawEvent(event, y) { + y = drawEventHeader(event, y); + y = drawEventBody(event, y); + return y; +} + +var curEventHeight = 0; + +function drawCurrentEvents(y) { + g.setColor("#0ff"); + g.clearRect(5, y, g.getWidth() - 5, y + curEventHeight); + curEventHeight = y; + + if(current.length === 0) { + y = drawEvent({timestamp: getTime(), durationInSeconds: 100}, y); + } else { + y = drawEventHeader(current[0], y); + for (var e of current) { + y = drawEventBody(e, y); + } + } + curEventHeight = y - curEventHeight; + return y; +} + +function drawFutureEvents(y) { + g.setColor(g.theme.fg); + for (var e of next) { + y = drawEvent(e, y); + if(y>g.getHeight())break; + } + return y; +} + +function fullRedraw() { + g.clearRect(5,24,g.getWidth()-5,g.getHeight()); + updateCalendar(); + var y = 30; + y = drawCurrentEvents(y); + drawFutureEvents(y); +} + +function redraw() { + g.reset(); + if (current.find(e=>!isActive(e)) || next.find(isActive)) { + fullRedraw(); + } else { + drawCurrentEvents(30); + } +} + +g.clear(); +fullRedraw(); +var minuteInterval = setInterval(redraw, 60 * 1000); + +Bangle.setUI("clock"); +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/calclock/calclock.png b/apps/calclock/calclock.png new file mode 100644 index 000000000..5f953c1ee Binary files /dev/null and b/apps/calclock/calclock.png differ diff --git a/apps/calclock/location.png b/apps/calclock/location.png new file mode 100644 index 000000000..619e55775 Binary files /dev/null and b/apps/calclock/location.png differ diff --git a/apps/calclock/metadata.json b/apps/calclock/metadata.json new file mode 100644 index 000000000..7bac5c721 --- /dev/null +++ b/apps/calclock/metadata.json @@ -0,0 +1,17 @@ +{ + "id": "calclock", + "name": "Calendar Clock", + "shortName": "CalClock", + "version": "0.03", + "description": "Show the current and upcoming events synchronized from Gadgetbridge", + "icon": "calclock.png", + "type": "clock", + "tags": "clock agenda", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"calclock.app.js","url":"calclock.js"}, + {"name":"calclock.img","url":"calclock-icon.js","evaluate":true} + ], + "screenshots": [{"url":"screenshot.png"}] +} diff --git a/apps/calclock/screenshot.png b/apps/calclock/screenshot.png new file mode 100644 index 000000000..4ab503f2b Binary files /dev/null and b/apps/calclock/screenshot.png differ diff --git a/apps/cassioWatch/ChangeLog b/apps/cassioWatch/ChangeLog index 419810021..883bd2585 100644 --- a/apps/cassioWatch/ChangeLog +++ b/apps/cassioWatch/ChangeLog @@ -8,4 +8,5 @@ 0.7: Update Rocket Sequences Scope to not use memory all time 0.8: Update Some Variable Scopes to not use memory until need 0.9: Remove ESLint spaces -0.10: Show daily steps, heartrate and the temperature if weather information is available. \ No newline at end of file +0.10: Show daily steps, heartrate and the temperature if weather information is available. +0.11: Tell clock widgets to hide. diff --git a/apps/cassioWatch/app.js b/apps/cassioWatch/app.js index 6bbb9e823..91f6737ad 100644 --- a/apps/cassioWatch/app.js +++ b/apps/cassioWatch/app.js @@ -165,11 +165,11 @@ Bangle.on("lock", (locked) => { } }); +Bangle.setUI("clock"); // Load widgets, but don't show them Bangle.loadWidgets(); -Bangle.setUI("clock"); g.reset(); g.clear(); -draw(); \ No newline at end of file +draw(); diff --git a/apps/cassioWatch/metadata.json b/apps/cassioWatch/metadata.json index dabdc2c93..abfee9b93 100644 --- a/apps/cassioWatch/metadata.json +++ b/apps/cassioWatch/metadata.json @@ -4,7 +4,7 @@ "description": "Animated Clock with Space Cassio Watch Style", "screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }], "icon": "app.png", - "version": "0.10", + "version": "0.11", "type": "clock", "tags": "clock, weather, cassio, retro", "supports": ["BANGLEJS2"], diff --git a/apps/chimer/ChangeLog b/apps/chimer/ChangeLog new file mode 100644 index 000000000..01bd00a0a --- /dev/null +++ b/apps/chimer/ChangeLog @@ -0,0 +1,2 @@ +0.01: Initial Creation +0.02: Fixed some sleep bugs. Added a sleep mode toggle \ No newline at end of file diff --git a/apps/chimer/README.MD b/apps/chimer/README.MD new file mode 100644 index 000000000..a78c677f2 --- /dev/null +++ b/apps/chimer/README.MD @@ -0,0 +1,11 @@ +# Chimer - For the BangleJS + +A fork of [Hour Chime](https://github.com/espruino/BangleApps/tree/master/apps/widchime) that adds extra features such as: + +- Buzz or beep on every 60, 30 or 15 minutes. +- Repeat Chime up to 3 times +- Set hours to disable chime + +Setting the hours you don't want your watch to chime for is done by setting the hour you want it to stop, and the hour you want it to start. + +Hours range from 0 - 23. diff --git a/apps/chimer/icon.txt b/apps/chimer/icon.txt new file mode 100644 index 000000000..cc969bc81 --- /dev/null +++ b/apps/chimer/icon.txt @@ -0,0 +1,2 @@ + +widget.png: "https://icons8.com/icon/114436/alarm" \ No newline at end of file diff --git a/apps/chimer/metadata.json b/apps/chimer/metadata.json new file mode 100644 index 000000000..d5bc04950 --- /dev/null +++ b/apps/chimer/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "chimer", + "name": "Chimer", + "version": "0.02", + "description": "A fork of Hour Chime that adds extra features such as: \n - Buzz or beep on every 60, 30 or 15 minutes. \n - Reapeat Chime up to 3 times \n - Set hours to disable chime", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.MD", + "storage": [ + { "name": "chimer.wid.js", "url": "widget.js" }, + { "name": "chimer.settings.js", "url": "settings.js" } + ], + "data": [{ "name": "chimer.json" }] +} diff --git a/apps/chimer/settings.js b/apps/chimer/settings.js new file mode 100644 index 000000000..55160c9be --- /dev/null +++ b/apps/chimer/settings.js @@ -0,0 +1,94 @@ +/** + * @param {function} back Use back() to return to settings menu + */ + +(function (back) { + // default to buzzing + var FILE = "chimer.json"; + var settings = {}; + const chimes = ["Off", "Buzz", "Beep", "Both"]; + const frequency = ["60 min", "30 min", "15 min", "1 min"]; + + var showMainMenu = () => { + E.showMenu({ + "": { title: "Chimer" }, + "< Back": () => back(), + "Chime Type": { + value: settings.type, + min: 0, + max: 2, // both is just silly + format: (v) => chimes[v], + onchange: (v) => { + settings.type = v; + writeSettings(settings); + }, + }, + Frequency: { + value: settings.freq, + min: 0, + max: 2, + format: (v) => frequency[v], + onchange: (v) => { + settings.freq = v; + writeSettings(settings); + }, + }, + Repetition: { + value: settings.repeat, + min: 1, + max: 5, + format: (v) => v, + onchange: (v) => { + settings.repeat = v; + writeSettings(settings); + }, + }, + "Sleep Mode": { + value: !!settings.sleep, + onchange: (v) => { + settings.sleep = v; + writeSettings(settings); + }, + }, + "Sleep Start": { + value: settings.start, + min: 0, + max: 23, + format: (v) => v, + onchange: (v) => { + settings.start = v; + writeSettings(settings); + }, + }, + "Sleep End": { + value: settings.end, + min: 0, + max: 23, + format: (v) => v, + onchange: (v) => { + settings.end = v; + writeSettings(settings); + }, + }, + }); + }; + + var readSettings = () => { + var settings = require("Storage").readJSON(FILE, 1) || { + type: 1, + freq: 0, + repeat: 1, + sleep: true, + start: 6, + end: 22, + }; + return settings; + }; + + var writeSettings = (settings) => { + require("Storage").writeJSON(FILE, settings); + }; + + settings = readSettings(); + showMainMenu(); +}); diff --git a/apps/chimer/widget.js b/apps/chimer/widget.js new file mode 100644 index 000000000..18358df9e --- /dev/null +++ b/apps/chimer/widget.js @@ -0,0 +1,134 @@ +(function () { + // 0: off, 1: buzz, 2: beep, 3: both + var FILE = "chimer.json"; + + var readSettings = () => { + var settings = require("Storage").readJSON(FILE, 1) || { + type: 1, + freq: 0, + repeat: 1, + sleep: true, + start: 6, + end: 22, + }; + return settings; + }; + + var settings = readSettings(); + + function sleep(milliseconds) { + const date = Date.now(); + let currentDate = null; + do { + currentDate = Date.now(); + } while (currentDate - date < milliseconds); + } + + function chime() { + for (var i = 0; i < settings.repeat; i++) { + if (settings.type === 1) { + Bangle.buzz(100); + } else if (settings.type === 2) { + Bangle.beep(); + } else { + return; + } + sleep(150); + } + } + + let lastHour = new Date().getHours(); + let lastMinute = new Date().getMinutes(); // don't chime when (re)loaded at a whole hour + function check() { + const now = new Date(), + h = now.getHours(), + m = now.getMinutes(), + s = now.getSeconds(), + ms = now.getMilliseconds(); + if ( + (settings.sleep && h > settings.end) || + (settings.sleep && h >= settings.end && m !== 0) || + (settings.sleep && h < settings.start) + ) { + var mLeft = 60 - m, + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + setTimeout(check, msLeft); + return; + } + if (settings.freq === 1) { + if ((m !== lastMinute && m === 0) || (m !== lastMinute && m === 30)) + chime(); + lastHour = h; + lastMinute = m; + // check again in 30 minutes + switch (true) { + case m / 30 >= 1: + var mLeft = 30 - (m - 30), + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + break; + case m / 30 < 1: + var mLeft = 30 - m, + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + break; + } + setTimeout(check, msLeft); + } else if (settings.freq === 2) { + if ( + (m !== lastMinute && m === 0) || + (m !== lastMinute && m === 15) || + (m !== lastMinute && m === 30) || + (m !== lastMinute && m === 45) + ) + chime(); + lastHour = h; + lastMinute = m; + // check again in 15 minutes + switch (true) { + case m / 15 >= 3: + var mLeft = 15 - (m - 45), + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + break; + case m / 15 >= 2: + var mLeft = 15 - (m - 30), + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + break; + case m / 15 >= 1: + var mLeft = 15 - (m - 15), + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + break; + case m / 15 < 1: + var mLeft = 15 - m, + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + break; + } + setTimeout(check, msLeft); + } else if (settings.freq === 3) { + if (m !== lastMinute) chime(); + lastHour = h; + lastMinute = m; + // check again in 1 minute + + var mLeft = 1, + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + setTimeout(check, msLeft); + } else { + if (h !== lastHour && m === 0) chime(); + lastHour = h; + // check again in 60 minutes + var mLeft = 60 - m, + sLeft = mLeft * 60 - s, + msLeft = sLeft * 1000 - ms; + setTimeout(check, msLeft); + } + } + + check(); +})(); diff --git a/apps/chimer/widget.png b/apps/chimer/widget.png new file mode 100644 index 000000000..14edf4150 Binary files /dev/null and b/apps/chimer/widget.png differ diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index 20a46b5b7..27d4fc7f4 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -2,3 +2,5 @@ 0.02: Added scrollable calendar and swipe gestures 0.03: Configurable drag gestures 0.04: Use default Bangle formatter for booleans +0.05: Improved colors (connected vs disconnected) +0.06: Tell clock widgets to hide. diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js index 5e8c7f796..58ddd7ef5 100644 --- a/apps/clockcal/app.js +++ b/apps/clockcal/app.js @@ -1,3 +1,4 @@ +Bangle.setUI("clock"); Bangle.loadWidgets(); var s = Object.assign({ @@ -123,7 +124,7 @@ function drawMinutes() { var d = new Date(); var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' '); var minutes = d.getMinutes().toString().padStart(2, '0'); - var textColor = NRF.getSecurityStatus().connected ? '#fff' : '#f00'; + var textColor = NRF.getSecurityStatus().connected ? '#99f' : '#fff'; var size = 50; var clock_x = (w - 20) / 2; if (dimSeconds) { @@ -307,4 +308,4 @@ NRF.on('disconnect', BTevent); dimSeconds = Bangle.isLocked(); drawWatch(); -Bangle.setUI("clock"); + diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index 6d547a7a3..872211495 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,7 +1,7 @@ { "id": "clockcal", "name": "Clock & Calendar", - "version": "0.04", + "version": "0.06", "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", diff --git a/apps/colorful_clock/ChangeLog b/apps/colorful_clock/ChangeLog index c72634017..54ee389e3 100644 --- a/apps/colorful_clock/ChangeLog +++ b/apps/colorful_clock/ChangeLog @@ -1,2 +1,3 @@ ... 0.03: First update with ChangeLog Added +0.04: Tell clock widgets to hide. diff --git a/apps/colorful_clock/app.js b/apps/colorful_clock/app.js index afc6b321f..ba6272e9b 100644 --- a/apps/colorful_clock/app.js +++ b/apps/colorful_clock/app.js @@ -3,6 +3,8 @@ let outerRadius = Math.min(CenterX,CenterY) * 0.9; + Bangle.setUI('clock'); + Bangle.loadWidgets(); /**** updateClockFaceSize ****/ @@ -241,7 +243,3 @@ refreshDisplay(); } }); - - Bangle.loadWidgets(); - - Bangle.setUI('clock'); diff --git a/apps/colorful_clock/metadata.json b/apps/colorful_clock/metadata.json index 5b6dbe87e..237acf81c 100644 --- a/apps/colorful_clock/metadata.json +++ b/apps/colorful_clock/metadata.json @@ -1,7 +1,7 @@ { "id": "colorful_clock", "name": "Colorful Analog Clock", "shortName":"Colorful Clock", - "version":"0.03", + "version":"0.04", "description": "a colorful analog clock", "icon": "app-icon.png", "type": "clock", diff --git a/apps/configurable_clock/ChangeLog b/apps/configurable_clock/ChangeLog index 84e7affed..9d55c1a91 100644 --- a/apps/configurable_clock/ChangeLog +++ b/apps/configurable_clock/ChangeLog @@ -1,2 +1,3 @@ ... 0.02: First update with ChangeLog Added +0.03: Tell clock widgets to hide. diff --git a/apps/configurable_clock/app.js b/apps/configurable_clock/app.js index 157d57741..45c86c7e9 100644 --- a/apps/configurable_clock/app.js +++ b/apps/configurable_clock/app.js @@ -5,6 +5,7 @@ let ScreenWidth = g.getWidth(), CenterX; let ScreenHeight = g.getHeight(), CenterY, outerRadius; + Bangle.setUI('clock'); Bangle.loadWidgets(); /**** updateClockFaceSize ****/ @@ -1377,4 +1378,3 @@ } }); - Bangle.setUI('clock'); diff --git a/apps/configurable_clock/metadata.json b/apps/configurable_clock/metadata.json index 28feae7e4..687a5b212 100644 --- a/apps/configurable_clock/metadata.json +++ b/apps/configurable_clock/metadata.json @@ -1,7 +1,7 @@ { "id": "configurable_clock", "name": "Configurable Analog Clock", "shortName":"Configurable Clock", - "version":"0.02", + "version":"0.03", "description": "an analog clock with several kinds of faces, hands and colors to choose from", "icon": "app-icon.png", "type": "clock", diff --git a/apps/crowclk/ChangeLog b/apps/crowclk/ChangeLog index 4f48bdd14..1c4f6f43b 100644 --- a/apps/crowclk/ChangeLog +++ b/apps/crowclk/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". 0.03: Fix the clock for dark mode. +0.04: Tell clock widgets to hide. diff --git a/apps/crowclk/crow_clock.js b/apps/crowclk/crow_clock.js index eee1653cb..7e608ef19 100644 --- a/apps/crowclk/crow_clock.js +++ b/apps/crowclk/crow_clock.js @@ -136,9 +136,9 @@ Bangle.on('lcdPower', (on) => { g.clear(); +// Show launcher when button pressed +Bangle.setUI("clock"); Bangle.loadWidgets(); Bangle.drawWidgets(); startTimers(); -// Show launcher when button pressed -Bangle.setUI("clock"); diff --git a/apps/crowclk/metadata.json b/apps/crowclk/metadata.json index 6985cf11a..265a0398b 100644 --- a/apps/crowclk/metadata.json +++ b/apps/crowclk/metadata.json @@ -1,7 +1,7 @@ { "id": "crowclk", "name": "Crow Clock", - "version": "0.03", + "version": "0.04", "description": "A simple clock based on Bold Clock that has MST3K's Crow T. Robot for a face", "icon": "crow_clock.png", "screenshots": [{"url":"screenshot_crow.png"}], diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index 829ff3d13..b13ce261b 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -5,3 +5,4 @@ 0.05: changed text to uppercase, just looks better, removed colons on text 0.06: better contrast for light theme, use fg color instead of dithered for ring 0.07: Use default Bangle formatter for booleans +0.08: fix idle timer always getting set to true diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 7c513726f..848cd1801 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -83,7 +83,7 @@ function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; settings.gy = settings.gy||'#020'; settings.fg = settings.fg||'#0f0'; - settings.idle_check = settings.idle_check||true; + settings.idle_check = (settings.idle_check === undefined ? true : settings.idle_check); assignPalettes(); } diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index 802ba6834..c6cc93620 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.07", + "version":"0.08", "dependencies": {"mylocation":"app"}, "description": "A beautiful digital clock with large ring guage, idle timer and a cyclic information line that includes, day, date, steps, battery, sunrise and sunset times", "icon": "app.png", diff --git a/apps/deko/Building_Typeface.ttf b/apps/deko/Building_Typeface.ttf new file mode 100644 index 000000000..d5a3933ab Binary files /dev/null and b/apps/deko/Building_Typeface.ttf differ diff --git a/apps/deko/ChangeLog b/apps/deko/ChangeLog new file mode 100644 index 000000000..9db0e26c5 --- /dev/null +++ b/apps/deko/ChangeLog @@ -0,0 +1 @@ +0.01: first release diff --git a/apps/deko/README.md b/apps/deko/README.md new file mode 100644 index 000000000..91e83bd23 --- /dev/null +++ b/apps/deko/README.md @@ -0,0 +1,10 @@ +# Deko Clock + +A simple clock with an Art Deko font + +The font was obtained from https://dafonttop.com/building.font and is free for personal use + + +![](screenshot.png) + +Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/deko/app-icon.js b/apps/deko/app-icon.js new file mode 100644 index 000000000..06f93e2ef --- /dev/null +++ b/apps/deko/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIdah/wAof//4ECgYFB4AFBg4FB8AFBj/wh/4AoM/wEB/gFBvwCEBAU/AQP4gfAj8AgPwAoMPwED8AFBg/AAYIBDA4ngg4TB4EBApkPKgJSBJQIFTMgIFCJIIFDKoIFEvgFBGoMAnw7DP4IFEh+BAoItBg+DNIQwBMIaeCKoKxCPoIzCEgKVHUIqtFXIrFFaIrdFdIwAV")) diff --git a/apps/deko/app.js b/apps/deko/app.js new file mode 100644 index 000000000..8ae2c1d31 --- /dev/null +++ b/apps/deko/app.js @@ -0,0 +1,64 @@ +Graphics.prototype.setFontBuildingTypeface = function(scale) { + // Actual height 100 (102 - 3) + this.setFontCustom( + atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAAAAAAAAAAAAH/gAAAAAAAAAAAAAAAAAH//gAAAAAAAAAAAAAAAAD///gAAAAAAAAAAAAAAAD////gAAAAAAAAAAAAAAD/////gAAAAAAAAAAAAAB//////gAAAAAAAAAAAAB///////gAAAAAAAAAAAB////////gAAAAAAAAAAA////////4AAAAAAAAAAA////////4AAAAAAAAAAAf///////8AAAAAAAAAAAf///////8AAAAAAAAAAAf///////8AAAAAAAAAAAP///////+AAAAAAAAAAAP///////+AAAAAAAAAAAP///////+AAAAAAAAAAAH////////AAAAAAAAAAAAH///////AAAAAAAAAAAAAH//////AAAAAAAAAAAAAAH/////gAAAAAAAAAAAAAAH////gAAAAAAAAAAAAAAAH///wAAAAAAAAAAAAAAAAH//wAAAAAAAAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////AAAAAAAD/////////////wAAAAAAP/////////////4AAAAAAP/////////////8AAAAAAf/////////////+AAAAAAf/////////////+AAAAAA///////////////AAAAAA///////////////AAAAAA///////////////AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA/4AAAAAAAAAAAH/AAAAAA///////////////AAAAAA///////////////AAAAAA///////////////AAAAAA///////////////AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAP/////////////8AAAAAAH/////////////4AAAAAAD/////////////wAAAAAAA/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAf4AAAAAAAAAAAAAAAAAAA/4AAAAAAAAAAAAAAAAAAB/4AAAAAAAAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAH/4AAAAAAAAAAAAAAAAAAf/4AAAAAAAAAAAAAAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/wAAf///////+AAAAAAB//wAB////////+AAAAAAH//wAD////////+AAAAAAH//wAH////////+AAAAAAP//wAP////////+AAAAAAf//wAP////////+AAAAAAf//wAP////////+AAAAAAf//wAf////////+AAAAAAf//wAf////////+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf8AAAf8AAAAAAP+AAAAAAf/////8AAAA///+AAAAAAf/////8AAAA///+AAAAAAf/////8AAAA///+AAAAAAf/////8AAAA///+AAAAAAP/////8AAAA///+AAAAAAH/////8AAAA///+AAAAAAH/////8AAAA///+AAAAAAB/////8AAAA///+AAAAAAAf////8AAAA///+AAAAAAAAAAAAAAAAA///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//gAAAAAAAf//+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf//wAAAAAAA///+AAAAAAf8AAAAAAAAAAAP+AAAAAAf8AAAAAAAAAAAP+AAAAAAf8AAAAAAAAAAAP+AAAAAAf8AAAAEAAAAAAP+AAAAAAf8AAAB8AAAAAAP+AAAAAAf8AAAP8AAAAAAP+AAAAAAf8AAD/8AAAAAAP+AAAAAAf8AA//8AAAAAAP+AAAAAAf8AP//8AAAAAAP+AAAAAAf8B///8AAAAAAP+AAAAAAf8f///8AAAAAAP+AAAAAAf/////8AAAAAAP+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf///8P////////+AAAAAAf///gH////////+AAAAAAf//4AD////////+AAAAAAf/+AAB////////+AAAAAAf/gAAA////////+AAAAAAfwAAAAD///////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAAAAAAAAB//gAAAAAAAAAAAAAAAAAH//gAAAAAAAAAAAAAAAAA///gAAAAAAAAAAAAAAAAH///gAAAAAAAAAAAAAAAAf///gAAAAAAAAAAAAAAAD////gAAAAAAAAAAAAAAAf////gAAAAAAAAAAAAAAB/////gAAAAAAAAAAAAAAP///z/gAAAAAAAAAAAAAB///+D/gAAAAAAAAAAAAAH///wD/gAAAAAAAAAAAAA///+AD/gAAAAAAAAAAAAH///wAD/gAAAAAAAAAAAAf//+AAD/gAAAAAAAAAAAD///wAAD/gAAAAAAAAAAAf///AAAD/gAAAAAAAAAAB///4AAAD/gAAAAAAAAAAP///AAAAD/gAAAAAAAAAB///4AAAAD/gAAAAAAAAAH///AAAAAD/gAAAAAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//+AAAAAAAf/////8AAAA///wAAAAAAf/////8AAAA///4AAAAAAf/////8AAAA///8AAAAAAf/////8AAAA///+AAAAAAf/////8AAAA///+AAAAAAf/////8AAAA///+AAAAAAf/////8AAAA////AAAAAAf/////8AAAA////AAAAAAf/////8AAAA////AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf8AAAf8AAAAAAH/AAAAAAf//wAf8AAAAAAH/AAAAAAf//wAf/////////AAAAAAf//wAf/////////AAAAAAf//wAf/////////AAAAAAf//wAf////////+AAAAAAf//wAP////////+AAAAAAf//wAP////////8AAAAAAf//wAH////////8AAAAAAf//wAD////////wAAAAAAf//wAA////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////AAAAAAAD/////////////wAAAAAAP/////////////4AAAAAAP/////////////8AAAAAAf/////////////+AAAAAAf/////////////+AAAAAA///////////////AAAAAA///////////////AAAAAA///////////////AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA/4AAAf8AAAAAAH/AAAAAA///wAf8AAAAAAH/AAAAAA///wAf/////////AAAAAA///wAf/////////AAAAAA///wAf/////////AAAAAAf//wAf/////////AAAAAAf//wAP////////+AAAAAAP//wAP////////+AAAAAAH//wAH////////8AAAAAAB//wAD////////4AAAAAAAf/wAB////////wAAAAAAAAAAAAf///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//wAAAAAAAAAAAAAAAAAf//wAAAAAAAAAAAAAAAAAf//wAAAAAAAAAAeAAAAAAf//wAAAAAAAAAP+AAAAAAf//wAAAAAAAAD/+AAAAAAf//wAAAAAAAA//+AAAAAAf//wAAAAAAAf//+AAAAAAf//wAAAAAAH///+AAAAAAf//wAAAAAD////+AAAAAAf8AAAAAAA/////+AAAAAAf8AAAAAAP/////+AAAAAAf8AAAAAH//////8AAAAAAf8AAAAB///////AAAAAAAf8AAAAf//////wAAAAAAAf8AAAP//////4AAAAAAAAf8AAD//////+AAAAAAAAAf8AB///////gAAAAAAAAAf8Af//////4AAAAAAAAAAf8H//////+AAAAAAAAAAAf////////gAAAAAAAAAAAf///////wAAAAAAAAAAAAf//////8AAAAAAAAAAAAAf//////AAAAAAAAAAAAAAf/////wAAAAAAAAAAAAAAf////8AAAAAAAAAAAAAAAf////AAAAAAAAAAAAAAAAf///wAAAAAAAAAAAAAAAAf//4AAAAAAAAAAAAAAAAAf/+AAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///gf//////+AAAAAAAB////4////////wAAAAAAH////9////////4AAAAAAP/////////////8AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAf/////////////+AAAAAA///////////////AAAAAA///////////////AAAAAA//////4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA/4AAA/4AAAAAAH/AAAAAA///////////////AAAAAA///////////////AAAAAA///////////////AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAP/////////////+AAAAAAP/////////////8AAAAAAH////9////////4AAAAAAB////4////////gAAAAAAAH///gP//////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////+AAAAAAAAAAAAD////////gAD//AAAAAAAP////////wAD//wAAAAAAP////////4AD//4AAAAAAf////////8AD//8AAAAAAf////////8AD//+AAAAAA/////////+AD//+AAAAAA/////////+AD///AAAAAA/////////+AD///AAAAAA/4AAAAAAP+AD///AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA/4AAAAAAP+AAAH/AAAAAA///////////////AAAAAA///////////////AAAAAA///////////////AAAAAAf/////////////+AAAAAAf/////////////+AAAAAAP/////////////8AAAAAAP/////////////4AAAAAAD/////////////wAAAAAAA/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAD/wAAAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='), + 46, + atob("FCYpGigoKigoJykoFA=="), + 126+(scale<<8)+(1<<16) + ); + return this; +}; + + + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + + +function draw() { + var x = g.getWidth()/2; + var y = g.getHeight()/2; + g.reset(); + var date = new Date(); + var timeStr = require("locale").time(date,1); + var dateStr = require("locale").date(date).toUpperCase(); + // draw time + g.setFontAlign(0,0).setFont("BuildingTypeface"); + g.clearRect(0, 24, g.getWidth(), y+35); // clear the background + g.drawString(timeStr,x,y); + // draw date + y += 60; + g.setFontAlign(0,0).setFont("6x8",2); + g.clearRect(0,y-8,g.getWidth(),y+8); // clear the background + g.drawString(dateStr,x,y); + // queue draw in one minute + queueDraw(); +} + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first, queue update +draw(); +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/deko/app.png b/apps/deko/app.png new file mode 100644 index 000000000..6f11e7019 Binary files /dev/null and b/apps/deko/app.png differ diff --git a/apps/deko/metadata.json b/apps/deko/metadata.json new file mode 100644 index 000000000..9bdd15429 --- /dev/null +++ b/apps/deko/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "deko", + "name": "Deko Clock", + "version": "0.01", + "description": "Clock with Art Deko font", + "readme": "README.md", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"deko.app.js","url":"app.js"}, + {"name":"deko.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/deko/screenshot.png b/apps/deko/screenshot.png new file mode 100644 index 000000000..91ce2ea38 Binary files /dev/null and b/apps/deko/screenshot.png differ diff --git a/apps/distortclk/ChangeLog b/apps/distortclk/ChangeLog new file mode 100644 index 000000000..4c7291526 --- /dev/null +++ b/apps/distortclk/ChangeLog @@ -0,0 +1,2 @@ +0.01: New face! +0.02: Improved clock diff --git a/apps/distortclk/README.md b/apps/distortclk/README.md new file mode 100644 index 000000000..8c7c433c1 --- /dev/null +++ b/apps/distortclk/README.md @@ -0,0 +1,17 @@ +# Distort Watchface +Was playing around with custom fonts and made something with it +Made for Bangle.js 2 + +![screenshot (3)](https://user-images.githubusercontent.com/44651387/157507228-100452bf-94a6-476f-aec6-d13d5dad86d5.png) + +## Features + +Has a dark mode + +## Requests + +If you have any issues or would like to suggest a feature, click here to send a message -> [here](https://github.com/elykittytee/BangleApps/issues/new?title=Poketch%20Clock%20Bug). + +## Creator + +Eleanor Tayam diff --git a/apps/distortclk/app-icon.js b/apps/distortclk/app-icon.js new file mode 100644 index 000000000..c375de96e --- /dev/null +++ b/apps/distortclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("j0ewkBiIAxHIQMJiBJEIxAaCAIQfHDgIUFDwwNCHYgVFiAVBHYgIDEghKCCIQGCFYoaDAYgORGIJ2DBwYIBHgQOPgAOIPIYOGAgQOFFgh7DHZQeDBwhoFQgh3JEAgOFFoqkHYRzgOfx4bCJ4gNGSIaJEABA7EAGA")) diff --git a/apps/distortclk/app.js b/apps/distortclk/app.js new file mode 100644 index 000000000..a9fdd1ef2 --- /dev/null +++ b/apps/distortclk/app.js @@ -0,0 +1,65 @@ +Graphics.prototype.setFontSixCaps = function(scale) { + // Actual height 60 (59 - 0) + this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0VniarM3u4AAAAAAAAAAAAAAAAAAAAAAAAAAABEZoiqzN3u////////8AAAAAAAAAAAAAAAAAAAJFZ4iqzN3u////////////////8AAAAAAAAAAARGZ4mrzd7v////////////////////////8AAAAAAAqszd7v////////////////////////////7u3MoAAAAAAA//////////////////////////7t3MqohmRCAAAAAAAAAA//////////////////7t3MqohmRAAAAAAAAAAAAAAAAAAA/////////+7dzKqYdlQwAAAAAAAAAAAAAAAAAAAAAAAAAA/+7dzKqIZkQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWazMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMqVAAAAAAAAAa7//////////////////////////////////+oQAAAAAAC/////////////////////////////////////+wAAAAAAf//////////////////////////////////////3AAAAAA3///7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u///9AAAAAA///GREREREREREREREREREREREREREREREREbP//AAAAAA//8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///AAAAAA///GREREREREREREREREREREREREREREREREbP//AAAAAA3///7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u///9AAAAAAf//////////////////////////////////////3AAAAAAC/////////////////////////////////////+wAAAAAAAa7//////////////////////////////////+oQAAAAAAAAWazMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMqVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqoAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAA//3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3/8AAAAAAA//////////////////////////////////////8AAAAAAA//////////////////////////////////////8AAAAAAA//////////////////////////////////////8AAAAAAA3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAes3d3d3d0AAAAAAAAAAAAAAAAAAAAAAAADVorAAAAAAAA8////////8AAAAAAAAAAAAAAAAAAAAlaKze///wAAAAAAHf////////8AAAAAAAAAAAAAAAFGis3v///////wAAAAAAn/////////8AAAAAAAAAAARom83v///////////wAAAAAA7//+3d3d3d0AAAAAAEV5rN7//////////////v/wAAAAAA//xTAAAAAAAAA1eKze//////////////7cqXVP/wAAAAAA//UAAAAAFGis3v/////////////+3Kl2QAAAAP/wAAAAAA//6XZoq83v/////////////+26hkEAAAAAAAAP/wAAAAAA3//////////////////tyoZSAAAAAAAAAAAAAP/wAAAAAAb//////////////tuoZAAAAAAAAAAAAAAAAAAP/wAAAAAACv/////////tuXUwAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAI3////9yoZAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAJ4qodRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqgAAAAAAAAWazMzMzMzMzAAAAAAAAAAAAAzMzMzMzMzMqVAAAAAAAAAa7//////////wAAAAAAAAAAAA///////////+oQAAAAAADP///////////wAAAAAAAAAAAA/////////////AAAAAAAf////////////wAAAAiIgAAAAA/////////////3AAAAAA3///7u7u7u7u7gAAAA//8AAAAA7u7u7u7u7u///9AAAAAA//11RERERERERAAAAA//8AAAAAREREREREREV9//AAAAAA//QAAAAAAAAAAAAAAB//8QAAAAAAAAAAAAAAAE//AAAAAA//11RERERERERERERa//+lREREREREREREREV9//AAAAAA3///7u7u7u7u7u7u7/////7u7u7u7u7u7u7u///9AAAAAAf//////////////////////////////////////3AAAAAAC/////////////////+q//////////////////+wAAAAAAAa7///////////////0i3////////////////+oQAAAAAAAAWazMzMzMzMzMzMyoIAKKzMzMzMzMzMzMzMqVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkRGZniIqqoAAAAAAAAAAAAAAAAAAAAAAkRGZniIqqrMzd3u7v//////8AAAAAAAAAAAAAAAqqrMzd3u7v////////////////////8AAAAAAAAAAAAAAA//////////////////////////////8AAAAAAAAAAAAAAA//////////////////////////////8AAAAAAAAAAAAAAA///////////////+7t3czKqpiHZm//8AAAAAAAAAAAAAAA//7u3dzMuqqIhmZUQwAAAAAAAAAA//8AAAAAAAAAAAAAAAZmREAAAAAAAAAARERERERERERERE//9EREREREQAAAAAAAAAAAAAAAAAAAAA7u7u7u7u7u7u7u///u7u7u7u4AAAAAAAAAAAAAAAAAAAAA////////////////////////8AAAAAAAAAAAAAAAAAAAAA////////////////////////8AAAAAAAAAAAAAAAAAAAAA////////////////////////8AAAAAAAAAAAAAAAAAAAAAzMzMzMzMzMzMzMzMzMzMzMzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARERERERERERERERERERAAABEREREREREREREAAAAAAAAAA7u7u7u7u7u7u7u7u7u7gAADu7u7u7u7u7u7u2TAAAAAAAA///////////////////wAAD//////////////+YAAAAAAA///////////////////wAAD///////////////4wAAAAAA///////////////////wAAD///////////////+gAAAAAA//zMzMzMzMzMzMzM3//AAADMzMzMzMzMzMzM7//wAAAAAA//AAAAAAAAAAAAAG//cAAAAAAAAAAAAAAAAAKf/wAAAAAA//AAAAAAAAAAAAAN//UAAAAAAAAAAAAAAAAAB//wAAAAAA//AAAAAAAAAAAAAP//6qqqqqqqqqqqqqqqqqv//wAAAAAA//AAAAAAAAAAAAAP///////////////////////AAAAAAA//AAAAAAAAAAAAAN//////////////////////9AAAAAAA//AAAAAAAAAAAAAF7/////////////////////gAAAAAAA//AAAAAAAAAAAAAAWu//////////////////7GAAAAAAAAZmAAAAAAAAAAAAAAADZmZmZmZmZmZmZmZmZmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADREREREREREREREREREREREREREREREREMAAAAAAAAAADne7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7ZMAAAAAAABd////////////////////////////////////1QAAAAAALv/////////////////////////////////////iAAAAAAr//////////////////////////////////////6AAAAAA///szMzMzMzMzMzMzP//zMzMzMzMzMzMzMzM3///AAAAAA//ogAAAAAAAAAAAAC//5AAAAAAAAAAAAAAAACf//AAAAAA//cAAAAAAAAAAAAAD//zAAAAAAAAAAAAAAAABf//AAAAAA//+6qqqqqqqqAAAAD//8qqqqqqqqqqqqqqqqrv//AAAAAAz///////////AAAAD//////////////////////8AAAAAAT///////////AAAADv/////////////////////0AAAAAACP//////////AAAAB/////////////////////+AAAAAAAAGzv////////AAAAAGzv/////////////////sYAAAAAAAAABGZmZmZmZmAAAAAABGZmZmZmZmZmZmZmZmZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAACRGZ4iqrM3e4AAAAAAA//AAAAAAAAAAAAAAACRGZ4iqrM3e7v////////8AAAAAAA//AAAAACRGZ4iqrM3e7v//////////////////8AAAAAAA//iqrM3e7v////////////////////////////8AAAAAAA//////////////////////////////////7u3cwAAAAAAA///////////////////////+7t3MyqmIZmRCAAAAAAAAAA/////////////u3dzLqoiGZUQgAAAAAAAAAAAAAAAAAAAA//7t3cyqqIhmVEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZlRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWazMzMzMqphjAAAAAAAAAARniqrMzMzMzMqVAAAAAAAAAa7//////////+yWEAAAAVi97////////////+oQAAAAAAC///////////////2VAGrf////////////////+wAAAAAAf////////////////+vP///////////////////3AAAAAA3///7u7u7u7/////////////////7u7u7u7u///9AAAAAA///GRERERERmis3////////typhmREREREREbP//AAAAAA//8wAAAAAAAAAAJ8/////8hgAAAAAAAAAAAAA///AAAAAA///GRERERERWis3////////typhmREREREREbP//AAAAAA3///7u7u7u7/////////////////7u7u7u7u///9AAAAAAf////////////////+vP///////////////////3AAAAAAC///////////////2VAGrf////////////////+wAAAAAAAa7//////////+yWIAAAAVi97////////////+oQAAAAAAAAWazMzMzMqphjAAAAAAAAAARniqrMzMzMzMqVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1ZmZmZmZmZmZmZmZmQgAAAAAAZmZmZmZmYwAAAAAAAAAFvv////////////////7rUAAAAA/////////rUAAAAAAAB+////////////////////9gAAAA//////////9wAAAAAAP//////////////////////gAAAA///////////zAAAAAAv//////////////////////wAAAA///////////7AAAAAA///7qqqqqqqqqqqqqqqq3//wAAAAqqqqqqqqrP//AAAAAA//9wAAAAAAAAAAAAAAAAT//wAAAAAAAAAAAAAH//AAAAAA//9wAAAAAAAAAAAAAAAAn//AAAAAAAAAAAAAAZ//AAAAAA///8zMzMzMzMzMzMzMzM///MzMzMzMzMzMzMzf//AAAAAAv//////////////////////////////////////7AAAAAAP//////////////////////////////////////zAAAAAABu////////////////////////////////////5gAAAAAAAEre7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7aQAAAAAAAAAAUREREREREREREREREREREREREREREREREQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMwAAAAAAAAAAAzMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//8AAAAAAAAAAA///wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//8AAAAAAAAAAA///wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//8AAAAAAAAAAA///wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//8AAAAAAAAAAA///wAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMwAAAAAAAAAAAzMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("CAwODQ4PDw8QDA8QCA=="), 69+(scale<<8)+(4<<16)); + return this; +}; + +const offset = 25; +const width = g.getWidth(); +const height = g.getHeight(); + +var drawTimeout; +var fgTime = 0xf800; +var bgTime = 0x3333ff; +var dayDate = 0x000; + +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + +function time() { + require("Font4x5").add(Graphics); + var d = new Date(); + var day = d.getDate(); + var time = require("locale").time(d,1); + var date = require("locale").date(d); + var mo = require("date_utils").month(d.getMonth()+1,0); + + g.setFontAlign(0,0); + g.setFontSixCaps(2).setColor(fgTime).drawString(time, width/2, height/2+10); + + g.setFont("4x5",2); + g.setFontAlign(0,0); + g.setColor(dayDate).drawString(mo,width-55, height-16); + g.drawString(day,width-10, height-16); +} + +function draw() { + g.setColor(bgTime).fillRect(0,40,width,height-offset); + time(); + queueDraw(); +} + +//program start +g.clear(); // Clear the screen once, at startup + +if (g.theme.dark==true){ + dayDate = 0xffff; +} +else { + dayDate=0x000; +} + +draw(); // draw immediately at first + + + +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/distortclk/app.png b/apps/distortclk/app.png new file mode 100644 index 000000000..b82a0913e Binary files /dev/null and b/apps/distortclk/app.png differ diff --git a/apps/distortclk/metadata.json b/apps/distortclk/metadata.json new file mode 100644 index 000000000..125dac590 --- /dev/null +++ b/apps/distortclk/metadata.json @@ -0,0 +1,17 @@ +{ + "id": "distortclk", + "name": "Distort Clock", + "shortName":"Distort Clock", + "version": "0.02", + "description": "A clockface", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "allow_emulator": true, + "readme":"README.md", + "storage": [ + {"name":"distortclk.app.js","url":"app.js"}, + {"name":"distortclk.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/distortclk/screenshot.png b/apps/distortclk/screenshot.png new file mode 100644 index 000000000..3207b4e1e Binary files /dev/null and b/apps/distortclk/screenshot.png differ diff --git a/apps/espruinoprog/ChangeLog b/apps/espruinoprog/ChangeLog index 5560f00bc..6fdcad1d6 100644 --- a/apps/espruinoprog/ChangeLog +++ b/apps/espruinoprog/ChangeLog @@ -1 +1,4 @@ 0.01: New App! +0.02: Add 'pre' code that can erase the device + Wait more between sending code snippets + Now force use of 'Storage' (assume 2v00 or later) diff --git a/apps/espruinoprog/README.md b/apps/espruinoprog/README.md index a8f15d3e9..aef4cccad 100644 --- a/apps/espruinoprog/README.md +++ b/apps/espruinoprog/README.md @@ -13,6 +13,9 @@ Click on the Customise button in the app loader to set up the programmer. * First you need to choose the kind of devices you want to upload to. This is the text that should match the Bluetooth advertising name. So `Puck.js` for Puck.js devices, or `Bangle.js` for Bangles. +* In the next box, you have code to run before the upload of the main code. By default +the code `require("Storage").list().forEach(f=>require("Storage").erase(f));reset();` will +erase all files on the device and reset it. * Now paste in the code you want to write to the device. This is automatically written to flash (`.bootcde`). See https://www.espruino.com/Saving#save-on-send-to-flash- for more information. @@ -35,8 +38,6 @@ To stop scanning, long-press the button to return to the clock. ## Notes -* Right now the Espruino Tools used here are unaware of the device they're writing to, -and as a result they don't use Storage and so the size of the files you can -write to the device are quite limited. You should be find with up to 4k of code. +* This assumes the device being written to is at least version 2v00 of Espruino * Currently, code is not minified before upload (so you need to supply pre-minified code if you want that) diff --git a/apps/espruinoprog/app.js b/apps/espruinoprog/app.js index b939d4007..58fac4a0b 100644 --- a/apps/espruinoprog/app.js +++ b/apps/espruinoprog/app.js @@ -58,21 +58,31 @@ function scanAndConnect() { term.print("Connected...\r\n"); uart.removeAllListeners(); uart.on('data', function(d) { term.print(d); }); - uart.write(json.code+"\n").then(() => { - term.print("\r\nUpload Complete...\r\n"); - // main upload completed - wait a bit + term.print("Upload initial...\r\n"); + uart.write((json.pre||"")+"\n").then(() => { + term.print("\r\Done.\r\n"); uploadTimeout = setTimeout(function() { - term.print("\r\nFinal Upload...\r\n"); - // now upload the code to run after... - uart.write(json.post+"\n").then(() => { - term.print("\r\nDone.\r\n"); - // now wait and disconnect (if not already done!) + uploadTimeout = undefined; + term.print("\r\nUpload Code...\r\n"); + uart.write((json.code||"")+"\n").then(() => { + term.print("\r\Done.\r\n"); + // main upload completed - wait a bit uploadTimeout = setTimeout(function() { - term.print("\r\nDisconnecting...\r\n"); - if (uart) uart.disconnect(); - }, 500); + uploadTimeout = undefined; + term.print("\r\Upload final...\r\n"); + // now upload the code to run after... + uart.write((json.post||"")+"\n").then(() => { + term.print("\r\nDone.\r\n"); + // now wait and disconnect (if not already done!) + uploadTimeout = setTimeout(function() { + uploadTimeout = undefined; + term.print("\r\nDisconnecting...\r\n"); + if (uart) uart.disconnect(); + }, 500); + }); + }, 2000); }); - }, 1000); + }, 2000); }); }); }).catch(err => { diff --git a/apps/espruinoprog/custom.html b/apps/espruinoprog/custom.html index c994aaea7..a12189707 100644 --- a/apps/espruinoprog/custom.html +++ b/apps/espruinoprog/custom.html @@ -17,6 +17,8 @@

Upload code to devices with names starting with:

+

Enter the code to send before upload here:

+

Enter your program to upload here:

Enter the code to send after upload here:

@@ -24,12 +26,17 @@

Then click  

Click here to reset to defaults.

diff --git a/apps/imgclock/metadata.json b/apps/imgclock/metadata.json index 799d11acc..94dff5f17 100644 --- a/apps/imgclock/metadata.json +++ b/apps/imgclock/metadata.json @@ -2,18 +2,19 @@ "id": "imgclock", "name": "Image background clock", "shortName": "Image Clock", - "version": "0.08", + "version": "0.10", "description": "A clock with an image as a background", "icon": "app.png", "type": "clock", "tags": "clock", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "custom": "custom.html", + "customConnect": true, "storage": [ {"name":"imgclock.app.js","url":"app.js"}, {"name":"imgclock.img","url":"app-icon.js","evaluate":true}, {"name":"imgclock.face.img"}, {"name":"imgclock.face.json"}, - {"name":"imgclock.face.bg","content":""} + {"name":"imgclock.face.bg","content":"X"} ] } diff --git a/apps/impwclock/ChangeLog b/apps/impwclock/ChangeLog index 6555fcc8f..0af7c99d6 100644 --- a/apps/impwclock/ChangeLog +++ b/apps/impwclock/ChangeLog @@ -3,3 +3,4 @@ 0.03: Move to Bangle.setUI to launcher support 0.04: Tweaks for compatibility with BangleJS2 0.05: Time-word now readable on Bangle.js 2 +0.06: Tell clock widgets to hide. diff --git a/apps/impwclock/clock-impword.js b/apps/impwclock/clock-impword.js index c42dbda44..04421017b 100644 --- a/apps/impwclock/clock-impword.js +++ b/apps/impwclock/clock-impword.js @@ -154,6 +154,9 @@ Bangle.on('lcdPower', function(on) { if (on) drawWordClock(); }); +// Show launcher when button pressed +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -172,5 +175,4 @@ Bangle.on('touch',e=>{ } }); -// Show launcher when button pressed -Bangle.setUI("clock"); + diff --git a/apps/impwclock/metadata.json b/apps/impwclock/metadata.json index 733dbb957..1b92ea3ae 100644 --- a/apps/impwclock/metadata.json +++ b/apps/impwclock/metadata.json @@ -1,7 +1,7 @@ { "id": "impwclock", "name": "Imprecise Word Clock", - "version": "0.05", + "version": "0.06", "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", "icon": "clock-impword.png", "type": "clock", diff --git a/apps/isoclock/ChangeLog b/apps/isoclock/ChangeLog index 809091ce4..7b57ecfa9 100644 --- a/apps/isoclock/ChangeLog +++ b/apps/isoclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: Created app based on digiclock with some small tweaks. 0.02: Swap to Bangle.setUI for launcher/buttons +0.03: Tell clock widgets to hide. diff --git a/apps/isoclock/checkout b/apps/isoclock/checkout new file mode 100644 index 000000000..e69de29bb diff --git a/apps/isoclock/isoclock.js b/apps/isoclock/isoclock.js index 59f28e66e..7526660b9 100644 --- a/apps/isoclock/isoclock.js +++ b/apps/isoclock/isoclock.js @@ -89,8 +89,8 @@ Bangle.on('lcdPower',on=>{ } }); -Bangle.loadWidgets(); -Bangle.drawWidgets(); - // Show launcher when button pressed Bangle.setUI("clock"); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/isoclock/metadata.json b/apps/isoclock/metadata.json index 313153dde..488afcb41 100644 --- a/apps/isoclock/metadata.json +++ b/apps/isoclock/metadata.json @@ -2,7 +2,7 @@ "id": "isoclock", "name": "ISO Compliant Clock Face", "shortName": "ISO Clock", - "version": "0.02", + "version": "0.03", "description": "Tweaked fork of digiclock for ISO date and time", "icon": "isoclock.png", "type": "clock", diff --git a/apps/kanawatch/ChangeLog b/apps/kanawatch/ChangeLog index 86a98398e..f2c991fd0 100644 --- a/apps/kanawatch/ChangeLog +++ b/apps/kanawatch/ChangeLog @@ -2,3 +2,4 @@ 0.02: Improve battery life, sprite resolution, fix launcher issue and unaligned text bug 0.03: Reduce code size, refresh once a minute and faster refresh 0.04: Show a random kana every minute to improve learning +0.05: Tell clock widgets to hide. diff --git a/apps/kanawatch/app.js b/apps/kanawatch/app.js index 1e9c0f922..088dab785 100644 --- a/apps/kanawatch/app.js +++ b/apps/kanawatch/app.js @@ -264,10 +264,10 @@ Bangle.on('touch', function (tap, top) { }); g.clear(true); +// show launcher when button pressed +Bangle.setUI('clock'); Bangle.loadWidgets(); tickWatch(); setInterval(tickWatch, 1000 * 60); -// show launcher when button pressed -Bangle.setUI('clock'); diff --git a/apps/kanawatch/metadata.json b/apps/kanawatch/metadata.json index 7183d6cad..b14703979 100644 --- a/apps/kanawatch/metadata.json +++ b/apps/kanawatch/metadata.json @@ -2,7 +2,7 @@ "id": "kanawatch", "name": "Kanawatch", "shortName": "Kanawatch", - "version": "0.04", + "version": "0.05", "type": "clock", "description": "Learn Hiragana and Katakana", "icon": "app.png", diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 44866b9f3..36852e0b7 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -14,3 +14,4 @@ Add /*LANG*/ tags for internationalisation 0.13: Add fullscreen mode 0.14: Use default Bangle formatter for booleans +0.15: Support for unload and quick return to the clock on 2v16 diff --git a/apps/launch/app.js b/apps/launch/app.js index 556e61bfd..d53f0dcdf 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -1,7 +1,8 @@ -var s = require("Storage"); -var scaleval = 1; -var vectorval = 20; -var font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2"; +{ // must be inside our own scope here so that when we are unloaded everything disappears +let s = require("Storage"); +let scaleval = 1; +let vectorval = 20; +let font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2"; let settings = Object.assign({ showClocks: true, fullscreen: false @@ -20,7 +21,7 @@ if ("font" in settings){ scaleval = (font.split("x")[1])/20; } } -var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || !app.type)); +let apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || !app.type)); apps.sort((a,b)=>{ var n=(0|a.sortorder)-(0|b.sortorder); if (n) return n; // do sortorder first @@ -69,18 +70,30 @@ E.showScroller({ } }); +function returnToClock() { + // unload everything manually + // ... or we could just call `load();` but it will be slower + Bangle.setUI(); // remove scroller's handling + if (lockTimeout) clearTimeout(lockTimeout); + Bangle.removeListener("lock", lockHandler); + // now load the default clock - just call .bootcde as this has the code already + setTimeout(eval,0,s.read(".bootcde")); +} + // on bangle.js 2, the screen is used for navigating, so the single button goes back // on bangle.js 1, the buttons are used for navigating if (process.env.HWVERSION==2) { - setWatch(_=>load(), BTN1, {edge:"falling"}); + setWatch(returnToClock, BTN1, {edge:"falling"}); } // 10s of inactivity goes back to clock Bangle.setLocked(false); // unlock initially -var lockTimeout; -Bangle.on("lock", locked => { +let lockTimeout; +function lockHandler(locked) { if (lockTimeout) clearTimeout(lockTimeout); lockTimeout = undefined; if (locked) - lockTimeout = setTimeout(_=>load(), 10000); -}); + lockTimeout = setTimeout(returnToClock, 10000); +} +Bangle.on("lock", lockHandler); +} diff --git a/apps/launch/metadata.json b/apps/launch/metadata.json index 19ca74e73..ec070e44e 100644 --- a/apps/launch/metadata.json +++ b/apps/launch/metadata.json @@ -2,7 +2,7 @@ "id": "launch", "name": "Launcher", "shortName": "Launcher", - "version": "0.14", + "version": "0.15", "description": "This is needed to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "readme": "README.md", "icon": "app.png", diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index 9a8ac4008..f97ddf540 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -21,3 +21,4 @@ 0.21: Add custom theming. 0.22: Fix alarm and add build in function for step counting. 0.23: Add warning for low flash memory +0.24: Add ability to disable alarm functionality \ No newline at end of file diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index e81c0d6f3..06a89a957 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -12,6 +12,7 @@ let settings = { themeColor1BG: "#FF9900", themeColor2BG: "#FF00DC", themeColor3BG: "#0094FF", + disableAlarms: false, }; let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings; for (const key in saved_settings) { @@ -722,12 +723,12 @@ Bangle.on('touch', function(btn, e){ } if(lcarsViewPos == 0){ - if(is_upper){ + if(is_upper && !settings.disableAlarms){ feedback(); increaseAlarm(); drawState(); return; - } if(is_lower){ + } if(is_lower && !settings.disableAlarms){ feedback(); decreaseAlarm(); drawState(); diff --git a/apps/lcars/lcars.settings.js b/apps/lcars/lcars.settings.js index b64feb30e..e4b9b0a78 100644 --- a/apps/lcars/lcars.settings.js +++ b/apps/lcars/lcars.settings.js @@ -13,6 +13,7 @@ themeColor1BG: "#FF9900", themeColor2BG: "#FF00DC", themeColor3BG: "#0094FF", + disableAlarms: false, }; let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings; for (const key in saved_settings) { @@ -102,6 +103,14 @@ settings.themeColor3BG = bg_code[v]; save(); }, - } + }, + 'Disable alarm functionality': { + value: settings.disableAlarms, + format: () => (settings.disableAlarms ? 'Yes' : 'No'), + onchange: () => { + settings.disableAlarms = !settings.disableAlarms; + save(); + }, + }, }); }) diff --git a/apps/lcars/metadata.json b/apps/lcars/metadata.json index 62a1c67db..6533ddd52 100644 --- a/apps/lcars/metadata.json +++ b/apps/lcars/metadata.json @@ -3,7 +3,7 @@ "name": "LCARS Clock", "shortName":"LCARS", "icon": "lcars.png", - "version":"0.23", + "version":"0.24", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "Library Computer Access Retrieval System (LCARS) clock.", diff --git a/apps/limelight/ChangeLog b/apps/limelight/ChangeLog index 9db0e26c5..8fe3a0b2c 100644 --- a/apps/limelight/ChangeLog +++ b/apps/limelight/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: Tell clock widgets to hide. diff --git a/apps/limelight/limelight.app.js b/apps/limelight/limelight.app.js index 20d79deeb..84ded1039 100644 --- a/apps/limelight/limelight.app.js +++ b/apps/limelight/limelight.app.js @@ -10,6 +10,8 @@ * */ +Bangle.setUI('clock'); + g.clear(); const SETTINGS_FILE = "limelight.json"; @@ -259,5 +261,4 @@ Bangle.on('lcdPower',on=>{ } }); -Bangle.setUI('clock'); draw(); diff --git a/apps/limelight/metadata.json b/apps/limelight/metadata.json index 7c3736e1a..e484a2825 100644 --- a/apps/limelight/metadata.json +++ b/apps/limelight/metadata.json @@ -1,7 +1,7 @@ { "id": "limelight", "name": "Limelight", - "version": "0.01", + "version": "0.02", "description": "Simple analogue clock (with configurable fonts) based on the work of @Andreas_Rozek (Simple_Clock)", "icon": "limelight.png", "readme":"README.md", diff --git a/apps/macwatch2/ChangeLog b/apps/macwatch2/ChangeLog index a60193ba7..5eafe64d2 100644 --- a/apps/macwatch2/ChangeLog +++ b/apps/macwatch2/ChangeLog @@ -1,3 +1,5 @@ 0.01: Created first version of the app with numeric date, only works in light mode 0.02: New icon, shimmied date right a bit 0.03: Incorporated improvements from Peer David for accuracy, fix dark mode, widgets run in background +0.04: Changed clock to use 12/24 hour format based on locale +0.05: Tell clock widgets to hide. diff --git a/apps/macwatch2/app.js b/apps/macwatch2/app.js index 3b78d5baf..4556e06ac 100644 --- a/apps/macwatch2/app.js +++ b/apps/macwatch2/app.js @@ -30,15 +30,15 @@ function draw() { g.setFontAlign(0, -1, 0); g.setColor(0,0,0); var d = new Date(); - var da = d.toString().split(" "); - hh = da[4].substr(0,2); - mi = da[4].substr(3,2); + var dt = require("locale").time(d, 1); + var hh = dt.split(":")[0]; + var mm = dt.split(":")[1]; + g.drawString(hh, 52, 65, true); + g.drawString(mm, 132, 65, true); + g.drawString(':', 93,65); dd = ("0"+(new Date()).getDate()).substr(-2); mo = ("0"+((new Date()).getMonth()+1)).substr(-2); yy = ("0"+((new Date()).getFullYear())).substr(-2); - g.drawString(hh, 52, 65, true); - g.drawString(mi, 132, 65, true); - g.drawString(':', 93,65); g.setFontCustom(font, 48, 8, 521); g.drawString(dd + ':' + mo + ':' + yy, 88, 120, true); @@ -57,8 +57,8 @@ Bangle.on('lcdPower',on=>{ } }); +Bangle.setUI("clock"); // Load widgets but hide them Bangle.loadWidgets(); draw(); -Bangle.setUI("clock"); diff --git a/apps/macwatch2/metadata.json b/apps/macwatch2/metadata.json index 09ec01e06..14c48c749 100644 --- a/apps/macwatch2/metadata.json +++ b/apps/macwatch2/metadata.json @@ -2,7 +2,7 @@ "name": "MacWatch2", "shortName":"MacWatch2", "icon": "app.png", - "version":"0.03", + "version":"0.05", "description": "Classic Mac Finder clock", "type": "clock", "tags": "clock", diff --git a/apps/matrixclock/ChangeLog b/apps/matrixclock/ChangeLog index ed59e37b0..02f7d109b 100644 --- a/apps/matrixclock/ChangeLog +++ b/apps/matrixclock/ChangeLog @@ -4,3 +4,4 @@ 0.04: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". 0.05: Added support to other color themes (other then black) 0.06: Added support for 24 hour clock enabled from settings +0.07: Tell clock widgets to hide. diff --git a/apps/matrixclock/matrixclock.js b/apps/matrixclock/matrixclock.js index c7f63dfdc..9618c3a47 100644 --- a/apps/matrixclock/matrixclock.js +++ b/apps/matrixclock/matrixclock.js @@ -328,11 +328,9 @@ Bangle.on('lcdPower', (on) => { } }); +Bangle.setUI("clock"); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); startTimers(); -Bangle.setUI("clock"); - - diff --git a/apps/matrixclock/metadata.json b/apps/matrixclock/metadata.json index eeefb6de4..718b878e5 100644 --- a/apps/matrixclock/metadata.json +++ b/apps/matrixclock/metadata.json @@ -1,7 +1,7 @@ { "id": "matrixclock", "name": "Matrix Clock", - "version": "0.06", + "version": "0.07", "description": "inspired by The Matrix, a clock of the same style", "icon": "matrixclock.png", "screenshots": [{"url":"matrix_green_on_black.jpg"}], diff --git a/apps/mclock/ChangeLog b/apps/mclock/ChangeLog index 05b422406..e3b164942 100644 --- a/apps/mclock/ChangeLog +++ b/apps/mclock/ChangeLog @@ -5,3 +5,4 @@ Fix issue where first digit could get stuck going from "2x:xx" to " x:xx" (fix #365) 0.06: Support 12 hour time 0.07: Use Bangle.setUI for button/launcher handling +0.08: Tell clock widgets to hide. diff --git a/apps/mclock/clock-morphing.js b/apps/mclock/clock-morphing.js index f1254860b..bd133206e 100644 --- a/apps/mclock/clock-morphing.js +++ b/apps/mclock/clock-morphing.js @@ -209,6 +209,9 @@ Bangle.on('lcdPower',function(on) { } }); +// Show launcher when button pressed +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -216,5 +219,3 @@ Bangle.drawWidgets(); timeInterval = setInterval(showTime, 1000); showTime(); -// Show launcher when button pressed -Bangle.setUI("clock"); diff --git a/apps/mclock/metadata.json b/apps/mclock/metadata.json index 513f823a1..a7d56f752 100644 --- a/apps/mclock/metadata.json +++ b/apps/mclock/metadata.json @@ -1,7 +1,7 @@ { "id": "mclock", "name": "Morphing Clock", - "version": "0.07", + "version": "0.08", "description": "7 segment clock that morphs between minutes and hours", "icon": "clock-morphing.png", "type": "clock", diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 7f7f8d3d3..da3b3ab5c 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -63,3 +63,11 @@ 0.47: Add new Icons (Nextbike, Mattermost, etc.) 0.48: When getting new message from the clock, only buzz once the messages app is loaded 0.49: Change messages icon (to fit within 24px) and ensure widget renders icons centrally +0.50: Add `getMessages` and `status` functions to library + Option to disable auto-open of messages + Option to make message icons monochrome (not colored) + messages widget buzz now returns a promise +0.51: Emit "message events" + Setting to hide widget + Add custom event handlers to prevent default app form loading + Move WIDGETS.messages.buzz() to require("messages").buzz() \ No newline at end of file diff --git a/apps/messages/README.md b/apps/messages/README.md index 2e583d1c2..72a989146 100644 --- a/apps/messages/README.md +++ b/apps/messages/README.md @@ -25,7 +25,7 @@ it starts getting clipped. * `Auto-Open Music` - Should the app automatically open when the phone starts playing music? * `Unlock Watch` - Should the app unlock the watch when a new message arrives, so you can touch the buttons at the bottom of the app? * `Flash Icon` - Toggle flashing of the widget icon. -* `Widget messages` - The maximum amount of message icons to show on the widget. +* `Widget messages` - The maximum amount of message icons to show on the widget, or `Hide` the widget completely. ## New Messages @@ -56,6 +56,24 @@ _2. What the notify icon looks like (it's touchable on Bangle.js2!)_ ![](screenshot-notify.gif) +## Events (for app/widget developers) + +When a new message arrives, a `"message"` event is emitted, you can listen for +it like this: + +```js +myMessageListener = Bangle.on("message", (type, message)=>{ + if (message.handled) return; // another app already handled this message + // is one of "text", "call", "alarm", "map", "music", or "clearAll" + if (type === "clearAll") return; // not a message + // see `messages/lib.js` for possible formats + // message.t could be "add", "modify" or "remove" + E.showMessage(`${message.title}\n${message.body}`, `${message.t} ${type} message`); + // You can prevent the default `message` app from loading by setting `message.handled = true`: + message.handled = true; +}); +``` + ## Requests diff --git a/apps/messages/app.js b/apps/messages/app.js index 6d5478b69..20fa8aaa3 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -48,14 +48,13 @@ we should start a timeout for settings.unreadTimeout to return to the clock. */ var unreadTimeout; /// List of all our messages -var MESSAGES = require("Storage").readJSON("messages.json",1)||[]; +var MESSAGES = require("messages").getMessages(); if (!Array.isArray(MESSAGES)) MESSAGES=[]; var onMessagesModified = function(msg) { // TODO: if new, show this new one if (msg && msg.id!=="music" && msg.new && active!="map" && !((require('Storage').readJSON('setting.json', 1) || {}).quiet)) { - if (WIDGETS["messages"]) WIDGETS["messages"].buzz(msg.src); - else Bangle.buzz(); + require("messages").buzz(msg.src); } if (msg && msg.id=="music") { if (msg.state && msg.state!="play") openMusic = false; // no longer playing music to go back to @@ -286,6 +285,7 @@ function showMessage(msgid) { } } function goBack() { + layout = undefined; msg.new = false; saveMessages(); // read mail cancelReloadTimeout(); // don't auto-reload to clock now checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0,openMusic:openMusic}); @@ -355,13 +355,13 @@ function checkMessages(options) { // If we have a new message, show it if (options.showMsgIfUnread && newMessages.length) { showMessage(newMessages[0].id); - // buzz after showMessage, so beingbusy during layout doesn't affect the buzz pattern + // buzz after showMessage, so being busy during layout doesn't affect the buzz pattern if (global.BUZZ_ON_NEW_MESSAGE) { // this is set if we entered the messages app by loading `messages.new.js` // ... but only buzz the first time we view a new message global.BUZZ_ON_NEW_MESSAGE = false; // messages.buzz respects quiet mode - no need to check here - WIDGETS.messages.buzz(newMessages[0].src); + require("messages").buzz(newMessages[0].src); } return; } diff --git a/apps/messages/lib.js b/apps/messages/lib.js index b51180d81..ed71ec04b 100644 --- a/apps/messages/lib.js +++ b/apps/messages/lib.js @@ -8,15 +8,11 @@ function openMusic() { /* Push a new message onto messages queue, event is: {t:"add",id:int, src,title,subject,body,sender,tel, important:bool, new:bool} {t:"add",id:int, id:"music", state, artist, track, etc} // add new - {t:"remove-",id:int} // remove + {t:"remove",id:int} // remove {t:"modify",id:int, title:string} // modified */ exports.pushMessage = function(event) { - var messages, inApp = "undefined"!=typeof MESSAGES; - if (inApp) - messages = MESSAGES; // we're in an app that has already loaded messages - else // no app - load messages - messages = require("Storage").readJSON("messages.json",1)||[]; + var messages = exports.getMessages(); // now modify/delete as appropriate var mIdx = messages.findIndex(m=>m.id==event.id); if (event.t=="remove") { @@ -35,73 +31,148 @@ exports.pushMessage = function(event) { else Object.assign(messages[mIdx], event); if (event.id=="music" && messages[mIdx].state=="play") { messages[mIdx].new = true; // new track, or playback (re)started + type = 'music'; } } require("Storage").writeJSON("messages.json",messages); + var message = mIdx<0 ? {id:event.id, t:'remove'} : messages[mIdx]; // if in app, process immediately - if (inApp) return onMessagesModified(mIdx<0 ? {id:event.id} : messages[mIdx]); + if ("undefined"!=typeof MESSAGES) return onMessagesModified(message); + // emit message event + var type = 'text'; + if (["call", "music", "map"].includes(message.id)) type = message.id; + if (message.src && message.src.toLowerCase().startsWith("alarm")) type = "alarm"; + Bangle.emit("message", type, message); // update the widget icons shown if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.update(messages,true); + var handleMessage = () => { // if no new messages now, make sure we don't load the messages app - if (event.t=="remove" && exports.messageTimeout && !messages.some(m=>m.new)) { - clearTimeout(exports.messageTimeout); - delete exports.messageTimeout; - } - // ok, saved now - if (event.id=="music" && Bangle.CLOCK && messages[mIdx].new && openMusic()) { - // just load the app to display music: no buzzing - load("messages.app.js"); - } else if (event.t!="add") { - // we only care if it's new - return; - } else if(event.new == false) { - return; - } - // otherwise load messages/show widget - var loadMessages = Bangle.CLOCK || event.important; - var quiet = (require('Storage').readJSON('setting.json',1)||{}).quiet; - var appSettings = require('Storage').readJSON('messages.settings.json',1)||{}; - var unlockWatch = appSettings.unlockWatch; - var quietNoAutOpn = appSettings.quietNoAutOpn; - delete appSettings; - // don't auto-open messages in quiet mode if quietNoAutOpn is true - if(quiet && quietNoAutOpn) { - loadMessages = false; - } - // after a delay load the app, to ensure we have all the messages - if (exports.messageTimeout) clearTimeout(exports.messageTimeout); - exports.messageTimeout = setTimeout(function() { - exports.messageTimeout = undefined; - // if we're in a clock or it's important, go straight to messages app - if (loadMessages){ - if(!quiet && unlockWatch){ - Bangle.setLocked(false); - Bangle.setLCDPower(1); // turn screen on - } - // we will buzz when we enter the messages app - return load("messages.new.js"); + if (event.t=="remove" && exports.messageTimeout && !messages.some(m => m.new)) { + clearTimeout(exports.messageTimeout); + delete exports.messageTimeout; } - if (!quiet && (!global.WIDGETS || !WIDGETS.messages)) return Bangle.buzz(); // no widgets - just buzz once to let someone know - if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.update(messages); - }, 500); + // ok, saved now + if (event.id=="music" && Bangle.CLOCK && messages[mIdx].new && openMusic()) { + // just load the app to display music: no buzzing + load("messages.app.js"); + } else if (event.t!="add") { + // we only care if it's new + return; + } else if (event.new==false) { + return; + } + // otherwise load messages/show widget + var loadMessages = Bangle.CLOCK || event.important; + var quiet = (require('Storage').readJSON('setting.json', 1) || {}).quiet; + var appSettings = require('Storage').readJSON('messages.settings.json', 1) || {}; + var unlockWatch = appSettings.unlockWatch; + // don't auto-open messages in quiet mode if quietNoAutOpn is true + if ((quiet && appSettings.quietNoAutOpn) || appSettings.noAutOpn) + loadMessages = false; + delete appSettings; + // after a delay load the app, to ensure we have all the messages + if (exports.messageTimeout) clearTimeout(exports.messageTimeout); + exports.messageTimeout = setTimeout(function() { + exports.messageTimeout = undefined; + // if we're in a clock or it's important, go straight to messages app + if (loadMessages) { + if (!quiet && unlockWatch) { + Bangle.setLocked(false); + Bangle.setLCDPower(1); // turn screen on + } + // we will buzz when we enter the messages app + return load("messages.new.js"); + } + if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.update(messages); + exports.buzz(message.src); + }, 500); + }; + setTimeout(()=>{ + if (!message.handled) handleMessage(); + },0); } /// Remove all messages -exports.clearAll = function(event) { - var messages, inApp = "undefined"!=typeof MESSAGES; - if (inApp) { +exports.clearAll = function() { + if ("undefined"!= typeof MESSAGES) { // we're in a messages app, clear that as well MESSAGES = []; - messages = MESSAGES; // we're in an app that has already loaded messages - } else // no app - empty messages - messages = []; - // Save all messages - require("Storage").writeJSON("messages.json",messages); - // update app if in app - if (inApp) return onMessagesModified(); + } + // Clear all messages + require("Storage").writeJSON("messages.json", []); // if we have a widget, update it if (global.WIDGETS && WIDGETS.messages) - WIDGETS.messages.update(messages); + WIDGETS.messages.update([]); + // let message listeners know + Bangle.emit("message", "clearAll", {}); // guarantee listeners an object as `message` + // clearAll cannot be marked as "handled" + // update app if in app + if ("function"== typeof onMessagesModified) onMessagesModified(); } +/** + * @returns {array} All messages + */ +exports.getMessages = function() { + if ("undefined"!=typeof MESSAGES) return MESSAGES; // loaded/managed by app + return require("Storage").readJSON("messages.json",1)||[]; +} + +/** + * Check if there are any messages + * @returns {string} "new"/"old"/"none" + */ + exports.status = function() { + try { + let status= "none"; + for(const m of exports.getMessages()) { + if (["music", "map"].includes(m.id)) continue; + if (m.new) return "new"; + status = "old"; + } + return status; + } catch(e) { + return "none"; // don't bother e.g. the widget with errors + } +}; + +/** + * Start buzzing for new message + * @param {string} msgSrc Message src to buzz for + * @return {Promise} Resolves when initial buzz finishes (there might be repeat buzzes later) + */ +exports.buzz = function(msgSrc) { + exports.stopBuzz(); // cancel any previous buzz timeouts + if ((require('Storage').readJSON('setting.json',1)||{}).quiet) return Promise.resolve(); // never buzz during Quiet Mode + + var pattern; + if (msgSrc && msgSrc.toLowerCase() === "phone") { + // special vibration pattern for incoming calls + pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrateCalls; + } else { + pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrate; + } + if (pattern === undefined) { pattern = ":"; } // pattern may be "", so we can't use || ":" here + if (!pattern) return Promise.resolve(); + + var repeat = (require('Storage').readJSON("messages.settings.json", true) || {}).repeat; + if (repeat===undefined) repeat=4; // repeat may be zero + if (repeat) { + exports.buzzTimeout = setTimeout(()=>require("buzz").pattern(pattern), repeat*1000); + var vibrateTimeout = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrateTimeout; + if (vibrateTimeout===undefined) vibrateTimeout=60; + if (vibrateTimeout && !exports.stopTimeout) exports.stopTimeout = setTimeout(exports.stopTimeout, vibrateTimeout*1000); + } + return require("buzz").pattern(pattern); +}; +/** + * Stop buzzing + */ +exports.stopBuzz = function() { + if (exports.buzzTimeout) clearTimeout(exports.buzzTimeout); + delete exports.buzzTimeout; + if (exports.stopTimeout) clearTimeout(exports.stopTimeout); + delete exports.stopTimeout; +}; + exports.getMessageImage = function(msg) { /* * icons should be 24x24px or less with 1bpp colors and 'Transparency to Color' @@ -120,7 +191,6 @@ exports.getMessageImage = function(msg) { if (s=="gmx") return atob("GBgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEJmfmd8Zuc85v847/88Z9s8fttmHIHiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); if (s=="google") return atob("GBiBAAAAAAD/AAP/wAf/4A/D4B8AwDwAADwAAHgAAHgAAHAAAHAH/nAH/nAH/ngH/ngAHjwAPDwAfB8A+A/D8Af/4AP/wAD/AAAAAA=="); if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA=="); // 2 bit unpaletted - if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA="); if (s=="home assistant") return atob("FhaBAAAAAADAAAeAAD8AAf4AD/3AfP8D7fwft/D/P8ec572zbzbNsOEhw+AfD8D8P4fw/z/D/P8P8/w/z/AAAAA="); if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA=="); if (s=="kalender") return atob("GBgBBgBgBQCgff++RQCiRgBiQAACf//+QAACQAACR//iRJkiRIEiR//iRNsiRIEiRJkiR//iRIEiRIEiR//iQAACQAACf//+AAAA"); @@ -154,11 +224,14 @@ exports.getMessageImage = function(msg) { }; exports.getMessageImageCol = function(msg,def) { + let iconColorMode = (require('Storage').readJSON("messages.settings.json", 1) || {}).iconColorMode; + if (iconColorMode == 'mono') + return g.theme.fg; const s = (("string"=== typeof msg) ? msg : (msg.src || "")).toLowerCase(); return { // generic colors, using B2-safe colors + // DO NOT USE BLACK OR WHITE HERE, just leave the declaration out and then the theme's fg color will be used "airbnb": "#f00", - "alarm": "#fff", "mail": "#ff0", "music": "#f0f", "phone": "#0f0", @@ -174,8 +247,7 @@ exports.getMessageImageCol = function(msg,def) { "gmx": "#1c449b", "google": "#4285F4", "google home": "#fbbc05", - "hangouts": "#1ba261", - "home assistant": "#fff", // ha-blue is #41bdf5, but that's the background +// "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background "instagram": "#dd2a7b", "lieferando": "#ee5c00", "messenger": "#0078ff", @@ -196,7 +268,6 @@ exports.getMessageImageCol = function(msg,def) { "teams": "#464eb8", "telegram": "#0088cc", "telegram foss": "#0088cc", - "threema": "#000", "to do": "#3999e5", "twitch": "#6441A4", "twitter": "#1da1f2", diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 408901bfc..057a95026 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.49", + "version": "0.51", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/settings.js b/apps/messages/settings.js index ac91464f7..09c9db455 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -1,4 +1,6 @@ (function(back) { + const iconColorModes = ['color', 'mono']; + function settings() { let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.vibrate===undefined) settings.vibrate=":"; @@ -7,6 +9,7 @@ if (settings.vibrateTimeout===undefined) settings.vibrateTimeout=60; if (settings.unreadTimeout===undefined) settings.unreadTimeout=60; if (settings.maxMessages===undefined) settings.maxMessages=3; + if (settings.iconColorMode === undefined) settings.iconColorMode = iconColorModes[0]; settings.unlockWatch=!!settings.unlockWatch; settings.openMusic=!!settings.openMusic; settings.maxUnreadTimeout=240; @@ -64,10 +67,21 @@ value: !!settings().quietNoAutOpn, onchange: v => updateSetting("quietNoAutOpn", v) }, + /*LANG*/'Disable auto-open': { + value: !!settings().noAutOpn, + onchange: v => updateSetting("noAutOpn", v) + }, /*LANG*/'Widget messages': { value:0|settings().maxMessages, - min: 1, max: 5, + min: 0, max: 5, + format: v => v ? v :/*LANG*/"Hide", onchange: v => updateSetting("maxMessages", v) + }, + /*LANG*/'Icon color mode': { + value: Math.max(0,iconColorModes.indexOf(settings().iconColorMode)), + min: 0, max: iconColorModes.length - 1, + format: v => iconColorModes[v], + onchange: v => updateSetting("iconColorMode", iconColorModes[v]) } }; E.showMenu(mainmenu); diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 835626f5d..c8d132f82 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -1,9 +1,5 @@ (() => { - -function getMessages() { - if ("undefined"!=typeof MESSAGES) return MESSAGES; - return require("Storage").readJSON("messages.json",1)||[]; -} +if ((require('Storage').readJSON("messages.settings.json", true) || {}).maxMessages===0) return; function filterMessages(msgs) { return msgs.filter(msg => msg.new && msg.id != "music") @@ -19,15 +15,14 @@ WIDGETS["messages"]={area:"tl", width:0, draw:function(recall) { } Bangle.removeListener('touch', this.touch); if (!this.width) return; - var c = (Date.now()-this.t)/1000; - let settings = Object.assign({flash:true, maxMessages:3, repeat:4, vibrateTimeout:60},require('Storage').readJSON("messages.settings.json", true) || {}); + let settings = Object.assign({flash:true, maxMessages:3},require('Storage').readJSON("messages.settings.json", true) || {}); if (recall !== true || settings.flash) { var msgsShown = E.clip(this.msgs.length, 0, settings.maxMessages); g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+23); for(let i = 0;i < msgsShown;i++) { const msg = this.msgs[i]; const colors = [g.theme.bg, g.setColor(require("messages").getMessageImageCol(msg)).getColor()]; - if (settings.flash && (c&1)) { + if (settings.flash && ((Date.now()/1000)&1)) { if (colors[1] == g.theme.fg) { colors.reverse(); } else { @@ -40,38 +35,13 @@ WIDGETS["messages"]={area:"tl", width:0, draw:function(recall) { this.x + 12 + i * 24, this.y + 12, {rotate:0/*force centering*/}); } } - if (csettings.repeat*1000) { // the period between vibrations - this.l = Date.now(); - WIDGETS["messages"].buzz(); // buzz every 4 seconds - } WIDGETS["messages"].i=setTimeout(()=>WIDGETS["messages"].draw(true), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); -},update:function(rawMsgs, quiet) { +},update:function(rawMsgs) { const settings = Object.assign({maxMessages:3},require('Storage').readJSON("messages.settings.json", true) || {}); this.msgs = filterMessages(rawMsgs); - if (this.msgs.length === 0) { - delete this.t; - delete this.l; - } else { - this.t=Date.now(); // first time - this.l=Date.now()-10000; // last buzz - if (quiet) this.t -= 500000; // if quiet, set last time in the past so there is no buzzing - } this.width = 24 * E.clip(this.msgs.length, 0, settings.maxMessages); Bangle.drawWidgets(); -},buzz:function(msgSrc) { - if ((require('Storage').readJSON('setting.json',1)||{}).quiet) return; // never buzz during Quiet Mode - var pattern; - if (msgSrc != undefined && msgSrc.toLowerCase() == "phone") { - // special vibration pattern for incoming calls - pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrateCalls; - } else { - pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrate; - } - if (pattern === undefined) { pattern = ":"; } // pattern may be "", so we can't use || ":" here - require("buzz").pattern(pattern); },touch:function(b,c) { var w=WIDGETS["messages"]; if (!w||!w.width||c.xw.x+w.width||c.yw.y+24) return; @@ -79,9 +49,7 @@ WIDGETS["messages"]={area:"tl", width:0, draw:function(recall) { }}; /* We might have returned here if we were in the Messages app for a -message but then the watch was never viewed. In that case we don't -want to buzz but should still show that there are unread messages. */ +message but then the watch was never viewed. */ if (global.MESSAGES===undefined) - WIDGETS["messages"].update(getMessages(), true); - + WIDGETS["messages"].update(require("messages").getMessages()); })(); diff --git a/apps/miclock/ChangeLog b/apps/miclock/ChangeLog index e92bad2e3..d1ac3e388 100644 --- a/apps/miclock/ChangeLog +++ b/apps/miclock/ChangeLog @@ -2,3 +2,4 @@ 0.03: Localization 0.04: move jshint to the top 0.05: Use Bangle.setUI for button/launcher handling +0.06: Tell clock widgets to hide. diff --git a/apps/miclock/clock-mixed.js b/apps/miclock/clock-mixed.js index b3d6bea8d..cb3235406 100644 --- a/apps/miclock/clock-mixed.js +++ b/apps/miclock/clock-mixed.js @@ -77,11 +77,13 @@ Bangle.on('lcdPower', function(on) { drawMixedClock(); }); +// Show launcher when button pressed +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); setInterval(drawMixedClock, 5E3); drawMixedClock(); -// Show launcher when button pressed -Bangle.setUI("clock"); + diff --git a/apps/miclock/metadata.json b/apps/miclock/metadata.json index 6eece46b0..2c216dc33 100644 --- a/apps/miclock/metadata.json +++ b/apps/miclock/metadata.json @@ -1,7 +1,7 @@ { "id": "miclock", "name": "Mixed Clock", - "version": "0.05", + "version": "0.06", "description": "A mix of analog and digital Clock", "icon": "clock-mixed.png", "type": "clock", diff --git a/apps/minimal_clock/ChangeLog b/apps/minimal_clock/ChangeLog index c72634017..54ee389e3 100644 --- a/apps/minimal_clock/ChangeLog +++ b/apps/minimal_clock/ChangeLog @@ -1,2 +1,3 @@ ... 0.03: First update with ChangeLog Added +0.04: Tell clock widgets to hide. diff --git a/apps/minimal_clock/app.js b/apps/minimal_clock/app.js index d78790347..47eca3c66 100644 --- a/apps/minimal_clock/app.js +++ b/apps/minimal_clock/app.js @@ -3,6 +3,7 @@ let outerRadius = Math.min(CenterX,CenterY) * 0.9; + Bangle.setUI('clock'); Bangle.loadWidgets(); /**** updateClockFaceSize ****/ @@ -225,6 +226,5 @@ } }); - Bangle.loadWidgets(); - Bangle.setUI('clock'); + Bangle.loadWidgets(); diff --git a/apps/minimal_clock/metadata.json b/apps/minimal_clock/metadata.json index 1702d97a9..3089780ce 100644 --- a/apps/minimal_clock/metadata.json +++ b/apps/minimal_clock/metadata.json @@ -1,7 +1,7 @@ { "id": "minimal_clock", "name": "Minimal Analog Clock", "shortName":"Minimal Clock", - "version":"0.03", + "version":"0.04", "description": "a minimal analog clock - just with some hands and no clock face", "icon": "app-icon.png", "type": "clock", diff --git a/apps/minionclk/ChangeLog b/apps/minionclk/ChangeLog index a8b6efc81..5949a786d 100644 --- a/apps/minionclk/ChangeLog +++ b/apps/minionclk/ChangeLog @@ -3,3 +3,4 @@ 0.03: Fixed rendering for Espruino v2.06 0.04: Fixed overlapped rendering of dates 0.05: Use Bangle.setUI for button/launcher handling +0.06: Tell clock widgets to hide. diff --git a/apps/minionclk/app b/apps/minionclk/app new file mode 100644 index 000000000..e69de29bb diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 9648e3d89..c61f8d3bf 100644 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -78,8 +78,10 @@ Bangle.on('lcdPower', (on) => { } }); +// Show launcher when button pressed +Bangle.setUI("clock"); + Bangle.loadWidgets(); startDrawing(); -// Show launcher when button pressed -Bangle.setUI("clock"); + diff --git a/apps/minionclk/metadata.json b/apps/minionclk/metadata.json index 44fc2a82d..4df2ddc6b 100644 --- a/apps/minionclk/metadata.json +++ b/apps/minionclk/metadata.json @@ -1,7 +1,7 @@ { "id": "minionclk", "name": "Minion clock", - "version": "0.05", + "version": "0.06", "description": "Minion themed clock.", "icon": "minionclk.png", "type": "clock", diff --git a/apps/mysticclock/ChangeLog b/apps/mysticclock/ChangeLog index b486a29a1..cd91abe00 100644 --- a/apps/mysticclock/ChangeLog +++ b/apps/mysticclock/ChangeLog @@ -1,2 +1,3 @@ 1.00: First published version. 1.01: Use Bangle.setUI for Launcher/buttons +1.02: Tell clock widgets to hide. diff --git a/apps/mysticclock/metadata.json b/apps/mysticclock/metadata.json index 571a55ecd..bd2df2f8d 100644 --- a/apps/mysticclock/metadata.json +++ b/apps/mysticclock/metadata.json @@ -1,7 +1,7 @@ { "id": "mysticclock", "name": "Mystic Clock", - "version": "1.01", + "version": "1.02", "description": "A retro-inspired watchface featuring time, date, and an interactive data display line.", "icon": "mystic-clock.png", "type": "clock", diff --git a/apps/mysticclock/mystic-clock-app.js b/apps/mysticclock/mystic-clock-app.js index 2d95633fe..d7f4ab1c3 100644 --- a/apps/mysticclock/mystic-clock-app.js +++ b/apps/mysticclock/mystic-clock-app.js @@ -189,6 +189,13 @@ Bangle.on('touch', (button) => { if (button === 3 && Bangle.isLCDOn()) Bangle.setLCDPower(false); }); +// Show launcher when button pressed +Bangle.setUI("clockupdown", btn=>{ + if (btn<0) prevInfo(); + if (btn>0) nextInfo(); + drawAll(); +}); + // clean app screen g.clear(); Bangle.loadWidgets(); @@ -200,9 +207,3 @@ if (Bangle.isLCDOn()) { drawAll(); // draw immediately } -// Show launcher when button pressed -Bangle.setUI("clockupdown", btn=>{ - if (btn<0) prevInfo(); - if (btn>0) nextInfo(); - drawAll(); -}); diff --git a/apps/ncrclk/ChangeLog b/apps/ncrclk/ChangeLog index 31e5d42c8..0c326161a 100644 --- a/apps/ncrclk/ChangeLog +++ b/apps/ncrclk/ChangeLog @@ -1,2 +1,3 @@ 0.01: A copy of the analogimgclk to work for NodeConf Remote 0.02: Use Bangle.setUI for button/launcher handling +0.03: Tell clock widgets to hide. diff --git a/apps/ncrclk/app.js b/apps/ncrclk/app.js index 16724fa5e..805ac1b95 100644 --- a/apps/ncrclk/app.js +++ b/apps/ncrclk/app.js @@ -120,10 +120,10 @@ Bangle.on('lcdPower', (on) => { } }); +// Show launcher when button pressed +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); drawHands(true); - -// Show launcher when button pressed -Bangle.setUI("clock"); diff --git a/apps/ncrclk/metadata.json b/apps/ncrclk/metadata.json index b50b554e1..fdab77450 100644 --- a/apps/ncrclk/metadata.json +++ b/apps/ncrclk/metadata.json @@ -2,7 +2,7 @@ "id": "ncrclk", "name": "NCR Clock", "shortName": "NCR Clock", - "version": "0.02", + "version": "0.03", "description": "NodeConf Remote clock", "icon": "app.png", "type": "clock", diff --git a/apps/novaclock/ChangeLog b/apps/novaclock/ChangeLog index b9a5425d1..8b05ff9ec 100644 --- a/apps/novaclock/ChangeLog +++ b/apps/novaclock/ChangeLog @@ -1,2 +1,3 @@ ... 0.10: First update with ChangeLog Added +0.11: Tell clock widgets to hide. diff --git a/apps/novaclock/app.js b/apps/novaclock/app.js index e5bd37b06..52bee0dbd 100644 --- a/apps/novaclock/app.js +++ b/apps/novaclock/app.js @@ -249,13 +249,13 @@ var open = false; var timemode = true; var clockmode; var novaYPos = -7; +Bangle.setUI("clock"); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); g.drawImage(nova(), -10, -10, { scale: 2.2 }); -Bangle.setUI("clock"); g.drawImage(star(), 5, -5, {scale:0.8}); g.drawImage(star(), -10, 120, {scale:0.8}); diff --git a/apps/novaclock/metadata.json b/apps/novaclock/metadata.json index a8a2c0af1..69b7627f8 100644 --- a/apps/novaclock/metadata.json +++ b/apps/novaclock/metadata.json @@ -3,7 +3,7 @@ "shortName":"Nova Clock", "icon": "app.png", "type": "clock", - "version":"0.10", + "version":"0.11", "description": "A clock inspired by the Kirby series", "tags": "clock", "supports": ["BANGLEJS2"], diff --git a/apps/numberchaser/app-icon.js b/apps/numberchaser/app-icon.js new file mode 100644 index 000000000..a4bb5054d --- /dev/null +++ b/apps/numberchaser/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkA/4AC+c/AoYAR+QTTj4DBkYXS+YUB+cSl4YS+P/mUiL4RLQ+chiUziPyAAIXPmJEC+Ui+UhO6QABj8iVKocEACUTC60j+YXWPoZHTkcyC6sibYaPpC63ziXzkYXUkXyO6nykMykIXUl8xmcykQ2BSZ4XBkTXB+LdBMgPyDRnzj8vmf/AIMyDgMjAoIALiQSCVYI0CD4QAL+MTIILFCI4TJOmMRkUzn40CGQRLBMRipBiIABkR2DTAIAQmURF4KcBZScxn5qBACgWWbwUhMCT7CmU/WQQAR+awBF6jdBVggXSPCwXXVAPyJCkimUieKinBI6sxAQIvUeAMyMQIXT+MjI6iNC+RIT+bAB+cSYiZdBMQMzSCkf+ZIUGAMiYKsjkTbVkMSl4A==")) diff --git a/apps/numberchaser/app.js b/apps/numberchaser/app.js new file mode 100644 index 000000000..f68119fb2 --- /dev/null +++ b/apps/numberchaser/app.js @@ -0,0 +1,104 @@ +var randomNumber; +var guessNumber = 1; + +function mathRandomInt(a, b) { + if (a > b) { + // Swap a and b to ensure a is smaller. + var c = a; + a = b; + b = c; + } + return Math.floor(Math.random() * (b - a + 1) + a); +} + +/** + * Describe this function... + */ +function game() { + + g.drawString('',0,20,true); + E.showMenu(numMenu); + console.log(randomNumber); +} + +var numMenu = { + "" : { + "title" : "Number Chaser", + }, + "Guess Number" : { + value : guessNumber, + min:1,max:100,step:1, + onchange : v => { guessNumber=v; } + }, + "OK" : function () { + g.clear(); + if (guessNumber == randomNumber) { + //if guess is correct + g.setFont("Vector",13);g.setFontAlign(-1,-1); + status = "You won! "; + gameOver(); + } else { + //if guess is incorrect + g.setFont("Vector",13);g.setFontAlign(-1,-1); + if (guessNumber > randomNumber) { + //Decreases number if guess is greater + randomNumber = randomNumber - 1; + status = "Too high!"; + } else if (guessNumber < randomNumber) { + //Increases number if guess is lower + status = "Too low!"; + randomNumber = randomNumber + 1; + } + if (randomNumber < 0 || randomNumber > 100) { + //You lose when the number is out of the 1 to 100 range + g.setFont("Vector",13);g.setFontAlign(-1,-1); + g.drawString('You have lost\nNumber is out\nof range.',10,10,true); + status = "You lost!"; + } else { + g.drawString(status+"\nTry again!",10,10); + Bangle.on('tap', function() { + delay(3000).then(() => game()); + } + ); + } + } + } +}; + +function gameOver() +{ + E.showPrompt(status+'Play again?',{title:""+'Number Chaser'}).then(function(a) { + if (a) { + randomNumber = mathRandomInt(1, 100); + game(); + } else { + load(); + } + } + ); +} + +function delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); +} + +function instructions() +{ + g.setFont("Vector",13);g.setFontAlign(-1,-1); + g.drawString('Guess the number\nbetween 1 and 100.\nGuess too high, it\ndecreases by 1.\nToo low, it increases\nby 1.\nIf the number\ngoes below 0 or\nabove 100, it\nis out of range\nand you have\nlost.',10,10,true); + randomNumber = mathRandomInt(1, 100); + delay(10000).then(() => game()); +} + + +g.clear(); +E.showPrompt('Do you need instructions?',{title:""+'Number Chaser'}).then(function(a) + { if (a) { + instructions(); + } else + { + randomNumber = mathRandomInt(1, 100); + game(); + } + } +); diff --git a/apps/numberchaser/metadata.json b/apps/numberchaser/metadata.json new file mode 100644 index 000000000..f9b6ff4b2 --- /dev/null +++ b/apps/numberchaser/metadata.json @@ -0,0 +1,13 @@ +{ "id": "numberchaser", + "name": "Number Chaser", + "shortName":"Number Chaser", + "version":"0.01", + "description": "A number guessing game, but the number goes up or down based on if you're guessing too high or too low.", + "icon": "numberchaser.png", + "tags": "game,fun", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"numberchaser.app.js","url":"app.js"}, + {"name":"numberchaser.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/numberchaser/numberchaser.png b/apps/numberchaser/numberchaser.png new file mode 100644 index 000000000..2042cc22b Binary files /dev/null and b/apps/numberchaser/numberchaser.png differ diff --git a/apps/openstmap/custom.html b/apps/openstmap/custom.html index 6f611dd86..3bba997e7 100644 --- a/apps/openstmap/custom.html +++ b/apps/openstmap/custom.html @@ -66,20 +66,20 @@ TODO: However some don't allow cross-origin use */ //var TILELAYER = 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png'; // simple, high contrast, TOO SLOW //var TILELAYER = 'http://a.tile.stamen.com/toner/{z}/{x}/{y}.png'; // black and white - var TILELAYER = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; - var PREVIEWTILELAYER = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + var TILELAYER = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + var PREVIEWTILELAYER = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; // Create map and try and set the location to where the browser thinks we are var map = L.map('map').locate({setView: true, maxZoom: 16, enableHighAccuracy:true}); // Tiles used for Bangle.js itself var bangleTileLayer = L.tileLayer(TILELAYER, { maxZoom: 18, - attribution: 'Map data © OpenStreetMap contributors' + attribution: 'Map data © OpenStreetMap contributors' }); // Tiles used for the may the user sees (faster) var previewTileLayer = L.tileLayer(PREVIEWTILELAYER, { maxZoom: 18, - attribution: 'Map data © OpenStreetMap contributors' + attribution: 'Map data © OpenStreetMap contributors' }); // Could optionally overlay trails: https://wiki.openstreetmap.org/wiki/Tiles diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog index f4640426b..28dcc0c28 100644 --- a/apps/pastel/ChangeLog +++ b/apps/pastel/ChangeLog @@ -18,3 +18,4 @@ added setting to enable/disable idle timer warning 0.16: make check_idle boolean setting work properly with new B2 menu 0.17: Use default Bangle formatter for booleans +0.18: fix idle option always getting defaulted to true diff --git a/apps/pastel/metadata.json b/apps/pastel/metadata.json index 1fe176d5f..860ed833b 100644 --- a/apps/pastel/metadata.json +++ b/apps/pastel/metadata.json @@ -2,7 +2,7 @@ "id": "pastel", "name": "Pastel Clock", "shortName": "Pastel", - "version": "0.17", + "version": "0.18", "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", "icon": "pastel.png", "dependencies": {"mylocation":"app","weather":"app"}, diff --git a/apps/pastel/pastel.app.js b/apps/pastel/pastel.app.js index 605b78ad0..05c0e2367 100644 --- a/apps/pastel/pastel.app.js +++ b/apps/pastel/pastel.app.js @@ -34,7 +34,7 @@ function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; settings.grid = settings.grid||false; settings.font = settings.font||"Lato"; - settings.idle_check = settings.idle_check||true; + settings.idle_check = (settings.idle_check === undefined ? true : settings.idle_check); } // requires the myLocation app diff --git a/apps/pebble/ChangeLog b/apps/pebble/ChangeLog index 274c34a34..ac894fc00 100644 --- a/apps/pebble/ChangeLog +++ b/apps/pebble/ChangeLog @@ -8,3 +8,4 @@ 0.08: Add theme options and optional lock symbol 0.09: Add support for internationalization (LANG placeholders + "locale" module) Get steps from built-in step counter (widpedom no more needed, fix #1697) +0.10: Tell clock widgets to hide. diff --git a/apps/pebble/metadata.json b/apps/pebble/metadata.json index f3c1fcc12..c5faa8857 100644 --- a/apps/pebble/metadata.json +++ b/apps/pebble/metadata.json @@ -2,7 +2,7 @@ "id": "pebble", "name": "Pebble Clock", "shortName": "Pebble", - "version": "0.09", + "version": "0.10", "description": "A pebble style clock to keep the rebellion going", "readme": "README.md", "icon": "pebble.png", diff --git a/apps/pebble/pebble.app.js b/apps/pebble/pebble.app.js index 774b24c3f..729d0a896 100644 --- a/apps/pebble/pebble.app.js +++ b/apps/pebble/pebble.app.js @@ -133,6 +133,8 @@ Bangle.on('lock', function(on) { drawLock(); }); +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); @@ -149,4 +151,3 @@ loadThemeColors(); setInterval(draw, 15000); // refresh every 15s draw(); -Bangle.setUI("clock"); diff --git a/apps/pebbled/ChangeLog b/apps/pebbled/ChangeLog index 9db0e26c5..8fe3a0b2c 100644 --- a/apps/pebbled/ChangeLog +++ b/apps/pebbled/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: Tell clock widgets to hide. diff --git a/apps/pebbled/metadata.json b/apps/pebbled/metadata.json index c16025f6f..70820f2c8 100644 --- a/apps/pebbled/metadata.json +++ b/apps/pebbled/metadata.json @@ -2,7 +2,7 @@ "id": "pebbled", "name": "Pebble Clock with distance", "shortName": "Pebble + distance", - "version": "0.01", + "version": "0.02", "description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).", "readme": "README.md", "icon": "pebbled.png", diff --git a/apps/pebbled/pebbled.app.js b/apps/pebbled/pebbled.app.js index bbe98823f..472ac8fff 100644 --- a/apps/pebbled/pebbled.app.js +++ b/apps/pebbled/pebbled.app.js @@ -115,6 +115,7 @@ function getSteps() { return '0'; } +Bangle.setUI("clock"); g.clear(); Bangle.loadWidgets(); /* @@ -126,4 +127,3 @@ for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} loadSettings(); setInterval(draw, 15000); // refresh every 15s draw(); -Bangle.setUI("clock"); diff --git a/apps/pokeclk/ChangeLog b/apps/pokeclk/ChangeLog index 8e506ce50..5838e596d 100644 --- a/apps/pokeclk/ChangeLog +++ b/apps/pokeclk/ChangeLog @@ -1,2 +1,3 @@ 0.01: New face :) 0.02: Color image compressed +0.03: Improved clock diff --git a/apps/pokeclk/app.js b/apps/pokeclk/app.js index 17a487bc0..7e495f7d2 100644 --- a/apps/pokeclk/app.js +++ b/apps/pokeclk/app.js @@ -5,7 +5,7 @@ const width = g.getWidth(); const height = g.getHeight(); const font = "Vector:12"; -const locale = require("locale"); +var drawTimeout; var img = { width : 176, height : 149, bpp : 4, @@ -20,34 +20,12 @@ var night= { buffer : (atob("ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERABEREREREREAEREREREREREREREREREREREREREREREREREREREREREREREQABERERERHwABEREREREREREREREREREREREREREREREREREREREREREREREQ/xERERER/wERERERERERERERERERERERERERERERERERERERERERERERERH//xERERH//xERERERERERERERERERERERERERERERERERERERERERERERERH//xEREf/xERERERERERERERERERERERERERERERERERERERERERERERERERH///////ERERERERERERERERERERERERERERERERERERERERERERERERERER////////8RERERERERERERERERERERERERERERERERERERERERERERERERH/////////ERERERERERERERERERERERERERERERERERERERERERERERERER////D///DxERERERERERERERERERERERERERERERERERERERERERERERERH////w///w8RERERERERERERERERERERERERERERERERERERERER//ERERER//AA///w/w8REREREREREREREREREREREREREREREREREREREREf////EREf/wAP/wAA8PERERERERERERERERERERERERERERERERERERERERH////xERH/8AD/////DxERERERERERERERERERERERERERERERERERERERER////8REf//////////ERERERERERERERERERERERERERERERERERERERERERERH/8R/////////xERERERERERERERERERERERERERERERERERERERER////////Ef////////////////////////////////////////////////////////////////////////////////////////////////////////////8RERERH////////////xERERERERERERERERERERERERERERERERERERERERERERERH///////////EREREREREREREREREREREREREREREREREREREREREf/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w==")) }; -var time= "10:20"; - -function time() { //numbers - // work out how to display the current time - const d = new Date(); - const h = d.getHours(), - m = d.getMinutes(); - const time = h + ":" + ("0" + m).substr(-2); - const day = Date.now(); - const mo = d.getMonth()+1; - const damo = d.getDate(); - - var dayMonth = mo+"-"+damo; - - // time - require("Font4x5").add(Graphics); - isDark(); - g.setFontAlign(0,0); - //g.setFont("6x8:4x5"); - g.setFont("4x5",7); - g.drawString(time, width/2, height/2); - // date - require("Font4x5").add(Graphics); - g.setFontAlign(1,1); - //g.setFont("4x6",2); - g.setFont("4x5",3); - g.drawString(dayMonth, width/2+60, height/2+40); - +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); } function isDark(){ @@ -59,6 +37,22 @@ function isDark(){ } } +function time() { + var d = new Date(); + var day = d.getDate(); + var time = require("locale").time(d,1); + var date = require("locale").date(d); + var mo = require("date_utils").month(d.getMonth()+1,1); + + require("Font4x5").add(Graphics); // time + isDark(); + g.setFontAlign(0,0); + g.setFont("4x5",7.5).drawString(time, width/2, height/2); + + g.setFontAlign(1,1); + g.setFont("4x5",3).drawString(mo+" "+day, width-15, height-35); +} + function draw() { //poketch background if (g.theme.dark==true){ g.drawImage(night, 0, 25, {scale:2}); //poketch is life @@ -67,20 +61,13 @@ function draw() { //poketch background g.drawImage(img, 0, 25); //poketch is life } time(); + queueDraw(); } //program start g.clear(); 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) { - secondInterval = setInterval(draw, 1000); - draw(); // draw immediately - } -}); + // Show launcher when middle button pressed Bangle.setUI("clock"); // Load widgets diff --git a/apps/pokeclk/metadata.json b/apps/pokeclk/metadata.json index 433077efe..c022868ec 100644 --- a/apps/pokeclk/metadata.json +++ b/apps/pokeclk/metadata.json @@ -2,7 +2,7 @@ "id": "pokeclk", "name": "Poketch Clock", "shortName":"Poketch Clock", - "version": "0.02", + "version": "0.03", "description": "A clock based on the Poketch electronic device found in Sinnoh", "icon": "app.png", "type": "clock", diff --git a/apps/powersave/README.md b/apps/powersave/README.md new file mode 100644 index 000000000..5be5e32b5 --- /dev/null +++ b/apps/powersave/README.md @@ -0,0 +1,27 @@ +# Power Saver + +Save your watch's battery power by halting foreground app execution while the screen is off. + +## Features +- Stops foreground app processes +- Background processes still run +- Clears screen +- Decreases accelerometer polls +- Foreground app is returned to when screen is turned back on (app state is not preserved) + +## Controls +- Automatically activates when screen times out, timing can be adjusted using normal timeout settings +- Deactivates when screen is turned back on + +## Warnings +- Due to an Espruino bug, this does not take affect immediately when installed. Switch apps for these features to take affect. +- This is not compatible with apps that need to run in the foreground even while the screen is off, such as most stopwatch apps and some health trackers. +- If you check your watch super often (like multiple times per minute), this may end of costing you more power than it saves since the app you are using will have to restart everytime you check it. + +## Requests + +[Contact information is on my website](https://kyleplo.com/#contact) + +## Creator + +[kyleplo](https://kyleplo.com) \ No newline at end of file diff --git a/apps/powersave/boot.js b/apps/powersave/boot.js new file mode 100644 index 000000000..d170e9d59 --- /dev/null +++ b/apps/powersave/boot.js @@ -0,0 +1,15 @@ +var Storage = Storage || require("Storage"); +Bangle.on("lock", locked => { + if(locked){ + g.clear().reset(); + Bangle.setLCDBrightness(0); + Bangle.setPollInterval(1000); + load("powersave.screen.js"); + }else{ + load(Storage.read("resumeaftersleep") || JSON.parse(Storage.read("setting.json")).clock); + } +}); +E.on("init", () => { + if(__FILE__ && __FILE__ !== "powersave.screen.js") + Storage.write("resumeaftersleep", __FILE__); +}); \ No newline at end of file diff --git a/apps/powersave/metadata.json b/apps/powersave/metadata.json new file mode 100644 index 000000000..50603b2c2 --- /dev/null +++ b/apps/powersave/metadata.json @@ -0,0 +1,15 @@ +{ + "id": "powersave", + "name": "Power Save", + "version": "0.01", + "description": "Halts foreground app execution while screen is off while still allowing background processes.", + "readme": "README.md", + "icon": "powersave.png", + "type": "bootloader", + "tags": "tool", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"powersave.boot.js","url":"boot.js"}, + {"name":"powersave.screen.js","url":"boot.js"} + ] +} \ No newline at end of file diff --git a/apps/powersave/powersave.png b/apps/powersave/powersave.png new file mode 100644 index 000000000..fa0399b73 Binary files /dev/null and b/apps/powersave/powersave.png differ diff --git a/apps/powersave/screen.js b/apps/powersave/screen.js new file mode 100644 index 000000000..f987f0bbb --- /dev/null +++ b/apps/powersave/screen.js @@ -0,0 +1,7 @@ +var Storage = Storage || require("Storage"); +g.clear(); +Bangle.setLCDBrightness(0); +Bangle.setPollInterval(1000); +if(!Bangle.isLocked()){ + load(Storage.read("resumeaftersleep") || JSON.parse(Storage.read("setting.json")).clock); +} \ No newline at end of file diff --git a/apps/presentation_timer/ChangeLog b/apps/presentation_timer/ChangeLog index 9db0e26c5..2ed460931 100644 --- a/apps/presentation_timer/ChangeLog +++ b/apps/presentation_timer/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: added interface for configuration from app loader diff --git a/apps/presentation_timer/README.md b/apps/presentation_timer/README.md index b24426672..4539fc2f9 100644 --- a/apps/presentation_timer/README.md +++ b/apps/presentation_timer/README.md @@ -12,11 +12,10 @@ when the time for the last slide is approaching, the button becomes red, when it passed, the time will go on for another half a minute and stop automatically. -The only way to upload personalized timings is -by uploading a CSV to the bangle (i.e. from the IDE), -in the future I'll possibly figure out a better way. +You can set personalized timings from the web interface +by uploading a CSV to the bangle (floppy disk button in the app loader). -Each line in the file (which must be called `presentation_timer.csv`) +Each line in the file (`presentation_timer.csv`) contains the time in minutes at which the slide is supposed to finish and the slide number, separated by a semicolon. @@ -25,8 +24,7 @@ is lasting until 1 minutes 30 seconds (yes it's decimal), after another slide will start. The only requirement is that timings are increasing, so slides number don't have to be consecutive, -some can be skipped and they can even be short texts -(be careful with that, I didn't test it). +some can be skipped and they can even be short texts. At the moment the app is just quick and dirty but it should do its job. diff --git a/apps/presentation_timer/interface.html b/apps/presentation_timer/interface.html new file mode 100644 index 000000000..137ea8475 --- /dev/null +++ b/apps/presentation_timer/interface.html @@ -0,0 +1,136 @@ + + + + + + + +
+ + + + + +

+
+    
+    
+  
+
diff --git a/apps/presentation_timer/metadata.json b/apps/presentation_timer/metadata.json
index 7a61ffbf0..8790d6208 100644
--- a/apps/presentation_timer/metadata.json
+++ b/apps/presentation_timer/metadata.json
@@ -1,15 +1,17 @@
 {
   "id": "presentation_timer",
   "name": "Presentation Timer",
-  "version": "0.01",
+  "version": "0.02",
   "description": "A touch based presentation timer for Bangle JS 2",
   "icon": "presentation_timer.png",
   "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot4.png"}],
   "tags": "tools,app",
   "supports": ["BANGLEJS2"],
   "readme": "README.md",
+  "interface": "interface.html",
   "storage": [
     {"name":"presentation_timer.app.js","url":"presentation_timer.app.js"},
     {"name":"presentation_timer.img","url":"presentation_timer.icon.js","evaluate":true}
-  ]
+  ],
+  "data": [{ "name": "presentation_timer.csv" }]
 }
diff --git a/apps/presentation_timer/presentation_timer.app.js b/apps/presentation_timer/presentation_timer.app.js
index af2b35dd5..1d0e5945d 100644
--- a/apps/presentation_timer/presentation_timer.app.js
+++ b/apps/presentation_timer/presentation_timer.app.js
@@ -19,10 +19,10 @@ const margin = 0.5; //half a minute tolerance
 
 //dummy default values
 var slides = [
-  [0.3, 1],
-  [0.5, 2],
-  [0.7, 3],
-  [1,4]
+  [1.5, 1],
+  [2, 2],
+  [2.5, 3],
+  [3,4]
 ];
 
 function log_debug(o) {
@@ -267,6 +267,6 @@ g.fillRect(0,0,w,h);
 
 Bangle.loadWidgets();
 Bangle.drawWidgets();
+readSlides();
 draw();
 setWatch(() => load(), BTN, { repeat: false, edge: "falling" });
-readSlides();
diff --git a/apps/ptlaunch/ChangeLog b/apps/ptlaunch/ChangeLog
index eec3610ed..5871b1fdc 100644
--- a/apps/ptlaunch/ChangeLog
+++ b/apps/ptlaunch/ChangeLog
@@ -6,3 +6,4 @@
 0.12: Improve pattern detection code readability by PaddeK http://forum.espruino.com/profiles/117930/
 0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/
 0.14: Update setUI to work with new Bangle.js 2v13 menu style
+0.15: Update to support clocks in custom setUI mode
diff --git a/apps/ptlaunch/boot.js b/apps/ptlaunch/boot.js
index 748d564f3..885962761 100644
--- a/apps/ptlaunch/boot.js
+++ b/apps/ptlaunch/boot.js
@@ -76,13 +76,8 @@
   var sui = Bangle.setUI;
   Bangle.setUI = function (mode, cb) {
     sui(mode, cb);
-    if ("object"==typeof mode) mode = mode.mode;
-    if (!mode) {
-      Bangle.removeListener("drag", dragHandler);
-      storedPatterns = {};
-      return;
-    }
-    if (!mode.startsWith("clock")) {
+    if (typeof mode === "object") mode = (mode.clock ? "clock" : "") + mode.mode;
+    if (!mode || !mode.startsWith("clock")) {
       storedPatterns = {};
       Bangle.removeListener("drag", dragHandler);
       return;
diff --git a/apps/ptlaunch/metadata.json b/apps/ptlaunch/metadata.json
index 0b6dce3d1..6f8a9e16f 100644
--- a/apps/ptlaunch/metadata.json
+++ b/apps/ptlaunch/metadata.json
@@ -2,7 +2,7 @@
   "id": "ptlaunch",
   "name": "Pattern Launcher",
   "shortName": "Pattern Launcher",
-  "version": "0.14",
+  "version": "0.15",
   "description": "Directly launch apps from the clock screen with custom patterns.",
   "icon": "app.png",
   "screenshots": [{"url":"manage_patterns_light.png"}],
diff --git a/apps/rclock/ChangeLog b/apps/rclock/ChangeLog
index 915fbc5d7..0a86ee3e3 100644
--- a/apps/rclock/ChangeLog
+++ b/apps/rclock/ChangeLog
@@ -5,3 +5,4 @@
 0.05: Changes which circle show minutes and seconds
 0.06: Avoid function wrapper, use setUI for launcher
       Clock face smaller so no longer breaks widgets
+0.07: Tell clock widgets to hide.
diff --git a/apps/rclock/metadata.json b/apps/rclock/metadata.json
index 77a036481..e5478aa6a 100644
--- a/apps/rclock/metadata.json
+++ b/apps/rclock/metadata.json
@@ -2,7 +2,7 @@
   "id": "rclock",
   "name": "Round clock with seconds,  minutes and date",
   "shortName": "Round Clock",
-  "version": "0.06",
+  "version": "0.07",
   "description": "Designed round clock with ticks for minutes and seconds and heart rate indication",
   "icon": "app.png",
   "type": "clock",
diff --git a/apps/rclock/rclock.app.js b/apps/rclock/rclock.app.js
index 9c219ab3d..2d6f84dc4 100644
--- a/apps/rclock/rclock.app.js
+++ b/apps/rclock/rclock.app.js
@@ -196,6 +196,9 @@ const drawHR = function () {
   }
 };
 
+// Show launcher when button pressed
+Bangle.setUI("clock");
+
 // clean app screen
 g.clear();
 Bangle.loadWidgets();
@@ -222,5 +225,3 @@ Bangle.on('HRM', function (d) {
 // draw now
 drawClock();
 
-// Show launcher when button pressed
-Bangle.setUI("clock");
diff --git a/apps/rebble/ChangeLog b/apps/rebble/ChangeLog
index 4e2e76484..c392cc74b 100644
--- a/apps/rebble/ChangeLog
+++ b/apps/rebble/ChangeLog
@@ -6,4 +6,6 @@
 0.06: Add 12h support and autocycle control
 0.07: added localization, removed deprecated code
 0.08: removed unused font, fix autocycle,  imported suncalc and trimmed, removed pedometer dependency, "tap to cycle" setting
-0.09: fix battery icon size
\ No newline at end of file
+0.09: fix battery icon size
+0.10: Tell clock widgets to hide.
+0.11: fix issue https://github.com/espruino/BangleApps/issues/2128 (#2128) ( settings undefined )
\ No newline at end of file
diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json
index ec7650f53..9134ccd23 100644
--- a/apps/rebble/metadata.json
+++ b/apps/rebble/metadata.json
@@ -2,7 +2,7 @@
   "id": "rebble",
   "name": "Rebble Clock",
   "shortName": "Rebble",
-  "version": "0.09",
+  "version": "0.11",
   "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion",
   "readme": "README.md",
   "icon": "rebble.png",
diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js
index fc91fe0ac..2ddd3a9b9 100644
--- a/apps/rebble/rebble.app.js
+++ b/apps/rebble/rebble.app.js
@@ -292,19 +292,10 @@ function queueDraw() {
 
 
 log_debug("starting..");
-g.clear();
-Bangle.loadWidgets();
-/*
- * we are not drawing the widgets as we are taking over the whole screen
- * so we will blank out the draw() functions of each widget and change the
- * area to the top bar doesn't get cleared.
- */
-for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
 loadSettings();
 loadLocation();
 
 
-
 if(settings.autoCycle || settings.sideTap==0)
 {
   Bangle.setUI("clockupdown", btn=> {
@@ -318,6 +309,17 @@ else{
 }
 
 
+g.clear();
+Bangle.loadWidgets();
+/*
+ * we are not drawing the widgets as we are taking over the whole screen
+ * so we will blank out the draw() functions of each widget and change the
+ * area to the top bar doesn't get cleared.
+ */
+for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
+
+
+
 
 
 draw();  // queues the next draw for a minutes time
@@ -331,4 +333,4 @@ Bangle.on('charging', function(charging) {
       drawSideBar2();
       break;
   }
-});
\ No newline at end of file
+});
diff --git a/apps/rolex/ChangeLog b/apps/rolex/ChangeLog
index a1e2cee0a..447b084f6 100644
--- a/apps/rolex/ChangeLog
+++ b/apps/rolex/ChangeLog
@@ -2,3 +2,4 @@
 0.02: Minor tweaks for light theme
 0.03: Made images 2 bit and fixed theme honoring
 0.04: Fixed date font alignment and changed date font to match a real Rolex
+0.05: Tell clock widget to hide.
diff --git a/apps/rolex/app.js b/apps/rolex/app.js
index 124cb6fee..fe9e534d6 100644
--- a/apps/rolex/app.js
+++ b/apps/rolex/app.js
@@ -44,7 +44,9 @@ let cx = W/2;
 let cy = H/2;
 let Timeout;
 
-Bangle.loadWidgets();
+Bangle.setUI("clock");
+// load widgets after 'setUI' so they're aware there is a clock active
+Bangle.loadWidgets(); 
 
 /* Custom version of Bangle.drawWidgets (does not clear the widget areas) Thanks to rozek */
 
@@ -142,8 +144,4 @@ Bangle.on('lcdPower', (on) => {
     displayRefresh();
   }
 });
-
-Bangle.setUI("clock");
-// load widgets after 'setUI' so they're aware there is a clock active
-Bangle.loadWidgets(); 
-displayRefresh();
\ No newline at end of file
+displayRefresh();
diff --git a/apps/rolex/metadata.json b/apps/rolex/metadata.json
index f307e60c4..e8627246c 100644
--- a/apps/rolex/metadata.json
+++ b/apps/rolex/metadata.json
@@ -3,7 +3,7 @@
     "shortName":"rolex",
     "icon": "rolex.png",
     "screenshots": [{"url":"screenshot1.png"}],
-    "version":"0.04",
+    "version":"0.05",
     "description": "A rolex like watch face",
     "tags": "clock",
     "type": "clock",
diff --git a/apps/saclock/app-icon.js b/apps/saclock/app-icon.js
new file mode 100644
index 000000000..0a8a06644
--- /dev/null
+++ b/apps/saclock/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwIFCn/8AgUB///wAFBh4FB8AFBj4FB/AFBv4FBDAX/4ED/wcB/0DwH/gED/EH4E/wEH+AFBj/Ah/gAoMH8EPAYIeB+EfCYPAgPwn8AAoX4nwFCgAFFvl8ApN+Aok+KoIFOjwFEj4FCOwIFD+AFEOwIFCgZwBAoR/BwAjCRYPAF4QPBAogwBnxNBSQOAAoYABvl+AohxBAAX8QYIAC/CPBDwQFETYKhBGASrBagSxBX4JCDgLUCv4bBK4LxBBAS8BboMAn7vEfYR+BOwTxBIgX/CwRqDAYIA=="))
\ No newline at end of file
diff --git a/apps/saclock/app-icon.png b/apps/saclock/app-icon.png
new file mode 100644
index 000000000..d55dcf598
Binary files /dev/null and b/apps/saclock/app-icon.png differ
diff --git a/apps/saclock/app.js b/apps/saclock/app.js
new file mode 100644
index 000000000..3bac66211
--- /dev/null
+++ b/apps/saclock/app.js
@@ -0,0 +1,88 @@
+Math.TAU = Math.PI*2; // the real circle constant
+
+/**
+ * Rotate points around origin
+ *
+ * @param points List of coordinates: [x1,y1, x2,y2, ...]
+ * @param radians Angle by which to rotate
+ */
+function rotate(points, radians) {
+  for(let i = 0; i hours,
+    getMinutes: () => minutes,
+  });
+};
diff --git a/apps/saclock/icon.png b/apps/saclock/icon.png
new file mode 100644
index 000000000..664a40bfb
Binary files /dev/null and b/apps/saclock/icon.png differ
diff --git a/apps/saclock/metadata.json b/apps/saclock/metadata.json
new file mode 100644
index 000000000..558e28066
--- /dev/null
+++ b/apps/saclock/metadata.json
@@ -0,0 +1,20 @@
+{ "id": "saclock",
+  "name": "Simple analog clock",
+  "shortName":"Analog clock",
+  "version":"0.01",
+  "description": "A very basic analog clock",
+  "screenshots": [{"url":"screenshot.png"}],
+  "icon": "icon.png",
+  "type": "clock",
+  "tags": "clock,analog",
+  "supports" : ["BANGLEJS","BANGLEJS2"],
+  "allow_emulator":true,
+  "storage": [
+    {"name":"saclock.app.js","url":"app.js"},
+    {"name":"saclock.settings.js","url":"settings.js"},
+    {"name":"saclock.img","url":"app-icon.js","evaluate":true}
+  ],
+  "data": [
+    {"name": "saclock.settings.json"}
+  ]
+}
diff --git a/apps/saclock/screenshot.png b/apps/saclock/screenshot.png
new file mode 100644
index 000000000..595b032dd
Binary files /dev/null and b/apps/saclock/screenshot.png differ
diff --git a/apps/saclock/settings.js b/apps/saclock/settings.js
new file mode 100644
index 000000000..3b98f6a13
--- /dev/null
+++ b/apps/saclock/settings.js
@@ -0,0 +1,10 @@
+(function(back) {
+  let menu = {
+    "": {"title": /*LANG*/"Analog Clock"},
+    /*LANG*/"< Back": back,
+  };
+  require("ClockFace_menu").addSettingsFile(menu, "saclock.settings.json", [
+    "loadWidgets"
+  ]);
+  E.showMenu(menu);
+});
diff --git a/apps/sched/README.md b/apps/sched/README.md
index 8a7d1fc21..c874b5577 100644
--- a/apps/sched/README.md
+++ b/apps/sched/README.md
@@ -70,11 +70,21 @@ let alarm = require("sched").newDefaultAlarm();
 // Get a new timer with default values
 let timer = require("sched").newDefaultTimer();
 
-// Add/update an existing alarm
-require("sched").setAlarm("mytimer", {
+// Add/update an existing alarm (using fields from the object shown above)
+require("sched").setAlarm("mytimer", { // as a timer
   msg : "Wake up",
   timer : 10 * 60 * 1000 // 10 minutes
 });
+require("sched").setAlarm("myalarm", { // as an alarm
+  msg : "Wake up",
+  t : 9 * 3600000 // 9 o'clock (in ms)
+});
+require("sched").setAlarm("mydayalarm", { // as an alarm on a date
+  msg : "Wake up",
+  date : "2022-04-04",
+  t : 9 * 3600000 // 9 o'clock (in ms)
+});
+
 // Ensure the widget and alarm timer updates to schedule the new alarm properly
 require("sched").reload();
 
diff --git a/apps/seiko-5actus/ChangeLog b/apps/seiko-5actus/ChangeLog
index 978e5d6ea..7d8a35194 100644
--- a/apps/seiko-5actus/ChangeLog
+++ b/apps/seiko-5actus/ChangeLog
@@ -1,2 +1,3 @@
 0.01: Initial Release
 0.02: Shrink hand images to save memory
+0.03: Tell clock widgets to hide.
diff --git a/apps/seiko-5actus/app.js b/apps/seiko-5actus/app.js
index 078b6e5c2..7d5e34f7c 100644
--- a/apps/seiko-5actus/app.js
+++ b/apps/seiko-5actus/app.js
@@ -52,7 +52,9 @@ let cx = W/2;
 let cy = H/2;
 let Timeout;
 
-Bangle.loadWidgets();
+Bangle.setUI("clock");
+// load widgets after 'setUI' so they're aware there is a clock active
+Bangle.loadWidgets(); 
 
 /* Custom version of Bangle.drawWidgets (does not clear the widget areas) Thanks to rozek */
 
@@ -175,7 +177,4 @@ Bangle.on('lcdPower', (on) => {
   }
 });
 
-Bangle.setUI("clock");
-// load widgets after 'setUI' so they're aware there is a clock active
-Bangle.loadWidgets(); 
 displayRefresh();
diff --git a/apps/seiko-5actus/metadata.json b/apps/seiko-5actus/metadata.json
index 33de8213b..addd8cb70 100644
--- a/apps/seiko-5actus/metadata.json
+++ b/apps/seiko-5actus/metadata.json
@@ -3,7 +3,7 @@
     "shortName":"5actus",
     "icon": "seiko-5actus.png",
     "screenshots": [{"url":"screenshot.png"}],
-    "version":"0.02",
+    "version":"0.03",
     "description": "A watch designed after then Seiko 5actus from the 1970's",
     "tags": "clock",
     "type": "clock",
diff --git a/apps/shownearby/ChangeLog b/apps/shownearby/ChangeLog
index 5560f00bc..b98baa1c0 100644
--- a/apps/shownearby/ChangeLog
+++ b/apps/shownearby/ChangeLog
@@ -1 +1,2 @@
 0.01: New App!
+0.02: Ensure we reset advertising after exiting so the watch can be connected to!
diff --git a/apps/shownearby/app.js b/apps/shownearby/app.js
index 10b123b5c..56ae27cb6 100644
--- a/apps/shownearby/app.js
+++ b/apps/shownearby/app.js
@@ -86,3 +86,8 @@ NRF.setScan(function(d) {
 },{phy:"coded",filters: [{ manufacturerData:{0x0590:{}} }]});
 // Set transmit power to max
 NRF.setTxPower(8);
+
+// when leaving the app, reset the advertising to default so we can reconnect!
+Bangle.on('kill', function() {
+  NRF.setAdvertising({},{});
+});
diff --git a/apps/shownearby/metadata.json b/apps/shownearby/metadata.json
index 143cc3a3f..ef0c4f5e9 100644
--- a/apps/shownearby/metadata.json
+++ b/apps/shownearby/metadata.json
@@ -1,8 +1,8 @@
 {
   "id": "shownearby",
   "name": "Show Nearby",
-  "version": "0.01",
-  "description": "Uses BLE long range advertising, advertises current location and shows the position of other watches running the app (Needs firmware 2v14.63 or later and Open Street Map installed)",
+  "version": "0.02",
+  "description": "Uses BLE long range advertising, advertises current location and shows the position of other watches running the app (Needs firmware 2v14.63 or later and Open Street Map installed). Make sure you disconnect from your phone first!",
   "icon": "app.png",
   "tags": "outdoors,gps",
   "supports": ["BANGLEJS2"],
diff --git a/apps/simple_clock/ChangeLog b/apps/simple_clock/ChangeLog
index 84e7affed..9d55c1a91 100644
--- a/apps/simple_clock/ChangeLog
+++ b/apps/simple_clock/ChangeLog
@@ -1,2 +1,3 @@
 ...
 0.02: First update with ChangeLog Added
+0.03: Tell clock widgets to hide.
diff --git a/apps/simple_clock/app.js b/apps/simple_clock/app.js
index 3c1843cb0..8ac51ed40 100644
--- a/apps/simple_clock/app.js
+++ b/apps/simple_clock/app.js
@@ -3,6 +3,8 @@
 
   let outerRadius = Math.min(CenterX,CenterY) * 0.9;
 
+  Bangle.setUI('clock');
+
   Bangle.loadWidgets();
 
 /**** updateClockFaceSize ****/
@@ -225,6 +227,3 @@
     }
   });
 
-  Bangle.loadWidgets();
-
-  Bangle.setUI('clock');
diff --git a/apps/simple_clock/metadata.json b/apps/simple_clock/metadata.json
index ccec0bfbc..512bcd674 100644
--- a/apps/simple_clock/metadata.json
+++ b/apps/simple_clock/metadata.json
@@ -1,7 +1,7 @@
 { "id": "simple_clock",
   "name": "Simple Analog Clock",
   "shortName":"Simple Clock",
-  "version":"0.02",
+  "version":"0.03",
   "description": "a simple, yet stylish, analog clock",
   "icon": "app-icon.png",
   "type": "clock",
diff --git a/apps/slash/ChangeLog b/apps/slash/ChangeLog
index f3fae1785..734df26dd 100644
--- a/apps/slash/ChangeLog
+++ b/apps/slash/ChangeLog
@@ -1 +1,2 @@
 0.01: First version for upload
+0.02: Fix for leftover date artifacts on display.
diff --git a/apps/slash/app.js b/apps/slash/app.js
index f548bcaf7..c594e5916 100644
--- a/apps/slash/app.js
+++ b/apps/slash/app.js
@@ -57,6 +57,10 @@ function draw() {
   var minutes = ("0"+m).substr(-2);
   g.reset();
   
+  // If midnight clear display to remove day / date artifacts
+  if (h == 0 && m == 0)
+    g.clear();
+  
   // Convert to 12hr time mode
   if (is12Hour && h > 12) {
     h = h - 12;
diff --git a/apps/slash/metadata.json b/apps/slash/metadata.json
index 6bdb4cd53..b08aa7c44 100644
--- a/apps/slash/metadata.json
+++ b/apps/slash/metadata.json
@@ -4,7 +4,7 @@
   "shortName":"Slash",
   "icon": "slash.png",
   "screenshots": [{"url":"screenshot.png"}],
-  "version":"0.01",
+  "version":"0.02",
   "description": "Slash Watch based on Pebble watch face by Nikki.",
   "tags": "clock",
   "type": "clock",
diff --git a/apps/sleeplog/ChangeLog b/apps/sleeplog/ChangeLog
index 8a3da6362..a0698d471 100644
--- a/apps/sleeplog/ChangeLog
+++ b/apps/sleeplog/ChangeLog
@@ -4,3 +4,6 @@
 0.04: Fix #1445, display loading info, add icons to display service states
 0.05: Fix LOW_MEMORY,MEMORY error on to big log size
 0.06: Reduced log size further to 750 entries
+0.10: Complete rework off this app!
+0.10beta: Add interface.html to view saved log data, add "View log" function for debugging log, send data for gadgetbridge, change caching for global getStats
+0.11: Prevent module not found error
diff --git a/apps/sleeplog/README.md b/apps/sleeplog/README.md
index ebbcdde54..45aeb316b 100644
--- a/apps/sleeplog/README.md
+++ b/apps/sleeplog/README.md
@@ -1,176 +1,175 @@
 # Sleep Log
 
-This app logs and displays the four following states:  
-_unknown, not worn, awake, sleeping_  
-It derived from the [SleepPhaseAlarm](https://banglejs.com/apps/#sleepphasealarm) and uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments ([ESS](https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en)) and
-also provides a power saving mode using the built in movement calculation. The internal temperature is used to decide if the status is _sleeping_ or _not worn_.
+This app logs and displays the following states:  
+- sleepling status: _unknown, not worn, awake, light sleep, deep sleep_
+- consecutive sleep status: _unknown, not consecutive, consecutive_
+
+It is using the built in movement calculation to decide your sleeping state. While charging it is assumed that you are not wearing the watch and if the status changes to _deep sleep_ the internal heartrate sensor is used to detect if you are wearing the watch.
+
+Logfiles are not removed on un-/reinstall to prevent data loss.
+
+| Filename (* _example_)       | Content         | Removeable in     |
+|------------------------------|-----------------|-------------------|
+| `sleeplog.log (StorageFile)` | recent logfile  | App Web Interface |
+| `sleeplog_1234.log`*         | old logfiles    | App Web Interface |
+| `sleeplog_123456.csv`*       | debugging files | Web IDE           |
 
-#### Operating Principle
-* __ESS calculation__  
-  The accelerometer polls values with 12.5Hz. On each poll the magnitude value is saved. When 13 values are collected, every 1.04 seconds, the standard deviation over this values is calculated.  
-  Is the calculated standard deviation lower than the "no movement" threshold (__NoMo Thresh__) a "no movement" counter is incremented. Each time the "no movement" threshold is reached the "no movement" counter will be reset. The first time no movement is detected the actual timestamp is cached (in _sleeplog.firstnomodate_) for logging.  
-  When the "no movement" counter reaches the sleep threshold the watch is considered as resting. (The sleep threshold is calculated from the __Min Duration__ setting, Example: _sleep threshold = Min Duration * 60 / calculation interval => 10min * 60s/min / 1.04s ~= 576,9 rounded up to 577_)
-* __Power Saving Mode__  
-  On power saving mode the movement value of bangle's build in health event is checked against the maximal movement threshold (__Max Move__). The event is only triggered every 10 minutes which decreases the battery impact but also reduces accurracy.
-* ___Sleeping___ __or__ ___Not Worn___  
-  To check if a resting watch indicates a sleeping status, the internal temperature must be greater than the temperature threshold (__Temp Thresh__). Otherwise the watch is considered as not worn.
-* __True Sleep__  
-  The true sleep value is a simple addition of all registert sleeping periods.
-* __Consecutive Sleep__  
-  In addition the consecutive sleep value tries to predict the complete time you were asleep, even the light sleeping phases with registered movements. All periods after a sleeping period will be summarized til the first following non sleeping period that is longer then the maximal awake duration (__Max Awake__). If this sum is lower than the minimal consecutive sleep duration (__Min Consec__) it is not considered, otherwise it will be added to the consecutive sleep value.
-* __Logging__  
-  To minimize the log size only a changed state is logged. The logged timestamp is matching the beginning of its measurement period.  
-  When not on power saving mode a movement is detected nearly instantaneous and the detection of a no movement period is delayed by the minimal no movement duration. To match the beginning of the measurement period a cached timestamp (_sleeplog.firstnomodate_) is logged.  
-  On power saving mode the measurement period is fixed to 10 minutes and all logged timestamps are also set back 10 minutes.  
-  To prevent a LOW_MEMORY,MEMORY error the log size is limited to 750 entries, older entries will be overwritten.
 
 ---
-### Control
+### App Usage
 ---
-* __Swipe__  
-  Swipe left/right to display the previous/following day.
-* __Touch__ / __BTN__  
-  Touch the screen to open the settings menu to exit or change settings.
+
+#### On the main app screen:
+  - __swipe left & right__  
+    to change the displayed day
+  - __touch the "title"__ (e.g. `Night to Fri 20/05/2022`)  
+    to enter day selection prompt
+  - __touch the info area__  
+    to change the displayed information  
+    (by default: consecutive & true sleeping)
+  - __touch the wrench__ (upper right corner)  
+    to enter the settings
+  - __use back button widget__ (upper left corner)  
+    exit the app
+
+#### Inside the settings:
+  - __Thresholds__ submenu  
+    Changes take effect from now on, not retrospective!
+    - __Max Awake__ | maximal awake duration  
+      _10min_ / _20min_ / ... / __60min__ / ... / _120min_
+    - __Min Consecutive__ | minimal consecutive sleep duration  
+      _10min_ / _20min_ / ... / __30min__ / ... / _120min_
+    - __Deep Sleep__ | deep sleep threshold  
+      _30_ / _31_ / ... / __100__ / ... / _200_
+    - __Light Sleep__ | light sleep threshold  
+      _100_ / _110_ / ... / __200__ / ... / _400_  
+    - __Reset to Default__ | reset to bold values above
+  - __BreakToD__ | time of day to break view  
+    _0:00_ / _1:00_ / ... / __12:00__ / ... / _23:00_
+  - __App Timeout__ | app specific lock timeout  
+    __0s__ / _10s_ / ... / _120s_
+  - __Enabled__ | completely en-/disables the background service  
+    __on__ / _off_
+  - __Debugging__ submenu  
+    - __View log__ | display logfile data  
+      Select the logfile by its starting time.  
+      Thresholds are shown as line with its value.  
+      - __swipe left & right__  
+        to change displayed duration
+      - __swipe up & down__  
+        to change displayed value range
+      - __touch the graph__  
+        to change between light & dark colors
+      - __use back button widget__ (upper left corner)  
+        to go back to the logfile selection
+    - __Enabled__ | en-/disables debugging  
+      _on_ / __off__
+    - __write File__ | toggles if a logfile is written  
+      _on_ / __off__
+    - __Duration__ | duration for writing into logfile  
+      _1h_ / _2h_ / ... / __12h__ / _96_  
+    - The following data is logged to a csv-file:    
+      _timestamp_ (in days since 1900-01-01 00:00 UTC used by office software) _, movement, status, consecutive, asleepSince, awakeSince, bpm, bpmConfidence_
+
 
 ---
-### Settings
+### Web Interface Usage
 ---
-* __Break Tod__ | break at time of day  
-  _0_ / _1_ / _..._ / __10__ / _..._ / _12_  
-  Change time of day on wich the lower graph starts and the upper graph ends. 
-* __Max Awake__ | maximal awake duration  
-  _15min_ / _20min_ / _..._ / __60min__ / _..._ / _120min_  
-  Adjust the maximal awake duration upon the exceeding of which aborts the consecutive sleep period.
-* __Min Consec__ | minimal consecutive sleep duration  
-  _15min_ / _20min_ / _..._ / __30min__ / _..._ / _120min_  
-  Adjust the minimal consecutive sleep duration that will be considered for the consecutive sleep value.
-* __Temp Thresh__ | temperature threshold  
-  _20°C_ / _20.5°C_ / _..._ / __25°C__ / _..._ / _40°C_  
-  The internal temperature must be greater than this threshold to log _sleeping_, otherwise it is _not worn_.
-* __Power Saving__  
-  _on_ / __off__  
-  En-/Disable power saving mode. _Saves battery, but might decrease accurracy._  
-  In app icon showing that power saving mode is enabled: ![](powersaving.png)
-* __Max Move__ | maximal movement threshold  
-  (only available when on power saving mode)  
-  _50_ / _51_ / _..._ / __100__ / _..._ / _200_  
-  On power saving mode the watch is considered resting if this threshold is lower or equal to the movement value of bangle's health event.
-* __NoMo Thresh__ | no movement threshold  
-  (only available when not on power saving mode)  
-  _0.006_ / _0.007_ / _..._ / __0.012__ / _..._ / _0.020_  
-  The standard deviation over the measured values needs to be lower then this threshold to count as not moving.  
-  The defaut threshold value worked best for my watch. A threshold value below 0.008 may get triggert by noise.
-* __Min Duration__ | minimal no movement duration  
-  (only available when not on power saving mode)  
-  _5min_ / _6min_ / _..._ / __10min__ / _..._ / _15min_  
-  If no movement is detected for this duration, the watch is considered as resting.
-* __Enabled__  
-  __on__ / _off_  
-  En-/Disable the service (all background activities). _Saves the most battery, but might make this app useless._  
-  In app icon showing that the service is disabled: ![](disabled.png)
-* __Logfile__  
-  __default__ / _off_  
-  En-/Disable logging by setting the logfile to _sleeplog.log_ / _undefined_.  
-  If the logfile has been customized it is displayed with _custom_.  
-  In app icon showing that logging is disabled: ![](nolog.png)
+
+Available through the App Loader when your watch is connected.
+
+- __view data__  
+  Display the data to each timestamp in a table.
+- __save csv-file__  
+  Download a csv-file with the data to each timestamp.  
+  The time format is chooseable beneath the file list. 
+- __delete file__  
+  Deletes the logfile from the watch. __Please backup your data first!__
+
+---
+### Timestamps and files
+---
+
+1. externally visible/usable timestamps (in `global.sleeplog`) are formatted as Bangle timestamps:  
+  seconds since 1970-01-01 00:00 UTC
+2. internally used and logged (to `sleeplog.log (StorageFile)`) is within the highest available resolution:  
+  10 minutes since 1970-01-01 00:00 UTC (`Bangle / (10 * 60 * 1000)`)
+3. debug .csv file ID (`sleeplog_123456.csv`) has a hourly resolution:
+  hours since 1970-01-01 00:00 UTC (`Bangle / (60 * 60 * 1000)`)
+4. logged timestamps inside the debug .csv file are formatted for office calculation software:  
+  days since 1900-01-01 00:00 UTC (`Bangle / (24 * 60 * 60 * 1000) + 25569`)
+5. every 14 days the `sleeplog.log (StorageFile)` is reduced and old entries are moved into separat files for each fortnight (`sleeplog_1234.log`) but still accessible though the app:  
+  fortnights since 1970-01-04 12:00 UTC (converted with `require("sleeplog").msToFn(Bangle)` and `require("sleeplog").fnToMs(fortnight)`)
+
+- __Logfiles from before 0.10:__  
+  timestamps and sleeping status of old logfiles are automatically converted on your first consecutive sleep or manually by `require("sleeplog").convertOldLog()`
+
+- __View logged data:__  
+  if you'd like to view your logged data in the IDE, you can access it with `require("sleeplog").printLog(since, until)` or `require("sleeplog").readLog(since, until)` to view the raw data  
+  since & until in Bangle timestamp, e.g. `require("sleeplog").printLog(Date()-24*60*60*1000, Date())` for the last 24h
+
+
+---
+### Access statistics (developer information)
+---
+- Last Asleep Time [Date]:  
+  `Date(sleeplog.awakeSince)`
+- Last Awake Duration [ms]:  
+  `Date() - sleeplog.awakeSince`
+- Last Statistics [object]:  
+  ```
+  // get stats of the last night (period as displayed inside the app)
+  //  as this might be the mostly used function the data is cached inside the global object 
+  sleeplog.getStats();
+
+  // get stats of the last 24h
+  require("sleeplog").getStats(0, 24*60*60*1000);
+  // same as
+  require("sleeplog").getStats(Date.now(), 24*60*60*1000);
+  // output as object, timestamps as UNIX timestamp, durations in minutes
+  ={ calculatedAt: 1653123553810, deepSleep: 250, lightSleep: 150, awakeSleep: 10,
+    consecSleep: 320, awakeTime: 1030, notWornTime: 0, unknownTime: 0, logDuration: 1440,
+    firstDate: 1653036600000, lastDate: 1653111600000 }
   
----
-### Global Object and Module Functions
----
-For easy access from the console or other apps the following parameters, values and functions are noteworthy:
-```
->global.sleeplog
-={
-  enabled: true,                // bool   / service status indicator
-  logfile: "sleeplog.log",      // string / used logfile
-  resting: false,               // bool   / indicates if the watch is resting
-  status: 2,                    // int    / actual status:
-    / undefined = service stopped, 0 = unknown, 1 = not worn, 2 = awake, 3 = sleeping
-  firstnomodate: 1644435877595, // number / Date.now() from first recognised no movement, not available in power saving mode
-  stop: function () { ... },    // funct  / stops the service until the next load()
-  start: function () { ... },   // funct  / restarts the service
-  ...
- }
+  // to get the start of a period defined by "Break TOD" of any date
+  var startOfBreak = require("sleeplog").getLastBreak();
+  // same as
+  var startOfBreak = require("sleeplog").getLastBreak(Date.now());
+  // output as date
+  =Date: Sat May 21 2022 12:00:00 GMT+0200
+  
+  // get stats of this period as displayed inside the app
+  require("sleeplog").getStats(require("sleeplog").getLastBreak(), 24*60*60*1000);
+  // or any other day
+  require("sleeplog").getStats(require("sleeplog").getLastBreak(Date(2022,4,10)), 24*60*60*1000);
+  ```
+- Total Statistics [object]:  
+  ```
+  // use with caution, may take a long time !
+  require("sleeplog").getStats(0, 0, require("sleeplog").readLog());
+  ```
 
->require("sleeplog")
-={
-  setEnabled: function (enable, logfile, powersaving) { ... },
-    // restarts the service with changed settings
-    // * enable        / bool / new service status
-    // * logfile       / bool or string
-    //   - true            = enables logging to "sleeplog.log"
-    //   - "some_file.log" = enables logging to "some_file.log"
-    //   - false           = disables logging
-    // * (powersaving) / bool / new power saving status, default: false
-    // returns: true or undefined
-    // - true      = service restart executed
-    // - undefined = no global.sleeplog found
-  readLog: function (logfile, since, until) { ... },
-    // read the raw log data for a specific time period
-    // * logfile / string / on no string uses logfile from global object or "sleeplog.log" 
-    // * (since) / Date or number / startpoint of period, default: 0
-    // * (until) / Date or number / endpoint of period, default: 1E14
-    // returns: array
-    // * [[number, int, string], [...], ... ] / sorting: latest first
-    //   - number // timestamp in ms
-    //   - int    // status: 0 = unknown, 1 = not worn, 2 = awake, 3 = sleeping
-    //   - string // additional information
-    // * [] = no data available or global.sleeplog not found
-  writeLog: function (logfile, input) { ... },
-    // append or replace log depending on input
-    // * logfile / string / on no string uses logfile from global object or default 
-    // * input   / array
-    //   - append input if array length >1 and element[0] >9E11
-    //   - replace log with input if at least one entry like above is inside another array
-    // returns: true or undefined
-    // - true      = changest written to storage
-    // - undefined = wrong input
-  getReadableLog: function (printLog, since, until, logfile) { ... }
-    // read the log data as humanreadable string for a specific time period
-    // * (printLog) / bool / direct print output with additional information, default: false
-    // * (since)    / Date or number / see readLog(..)
-    // * (until)    / Date or number / see readLog(..)
-    // * (logfile)  / string / see readLog(..)
-    // returns: string
-    // * "{substring of ISO date} - {status} for {duration}min\n...", sorting: latest last
-    // * undefined = no data available or global.sleeplog found
-  restoreLog: function (logfile) { ... }
-    // eliminate some errors inside a specific logfile
-    // * (logfile)  / string / see readLog(..)
-    // returns: int / number of changes that were made
-  reinterpretTemp: function (logfile, tempthresh) { ... }
-    // reinterpret worn status based on given temperature threshold
-    // * (logfile)    / string / see readLog(..)
-    // * (tempthresh) / float  / new temperature threshold, on default uses tempthresh from global object or 27
-    // returns: int / number of changes that were made
- }
-```
 
 ---
 ### Worth Mentioning
 ---
 #### To do list
-* Send the logged information to Gadgetbridge.
-  _(For now I have no idea how to achieve this, help is appreciated.)_
-* View, down- and upload log functions via App Loader.
-* Calculate and display overall sleep statistics.
-* Option to automatically change power saving mode depending on time of day.
+- Check translations.
+- Add more functionallities to interface.html.
+- Enable recieving data on the Gadgetbridge side + testing.  
+  __Help appreciated!__
 
 #### Requests, Bugs and Feedback
-Please leave requests and bug reports by raising an issue at [github.com/storm64/BangleApps](https://github.com/storm64/BangleApps) or send me a [mail](mailto:banglejs@storm64.de).
+Please leave requests and bug reports by raising an issue at [github.com/storm64/BangleApps](https://github.com/storm64/BangleApps) (or send me a [mail](mailto:banglejs@storm64.de)).
 
 #### Creator
 Storm64 ([Mail](mailto:banglejs@storm64.de), [github](https://github.com/storm64))
 
 #### Contributors
-nxdefiant ([github](https://github.com/nxdefiant))
+myxor ([github](https://github.com/myxor))
 
 #### Attributions
-* ESS calculation based on nxdefiant interpretation of the following publication by:  
-  Marko Borazio, Eugen Berlin, Nagihan Kücükyildiz, Philipp M. Scholl and Kristof Van Laerhoven  
-  [Towards a Benchmark for Wearable Sleep Analysis with Inertial Wrist-worn Sensing Units](https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en),  
-  ICHI 2014, Verona, Italy, IEEE Press, 2014.
-* Icons used in this app are from [https://icons8.com](https://icons8.com).
+The app icon is downloaded from [https://icons8.com](https://icons8.com).
 
 #### License
 [MIT License](LICENSE)
diff --git a/apps/sleeplog/app.js b/apps/sleeplog/app.js
index 8077b4d62..c75bf1e4c 100644
--- a/apps/sleeplog/app.js
+++ b/apps/sleeplog/app.js
@@ -1,234 +1,354 @@
-// set storage and define settings
-var storage = require("Storage");
-var breaktod, maxawake, minconsec;
-
-// read required settings from storage
-function readSettings(settings) {
-  breaktod = settings.breaktod || (settings.breaktod === 0 ? 0 : 10); // time of day when to start/end graphs
-  maxawake = settings.maxawake || 36E5; // 60min in ms
-  minconsec = settings.minconsec || 18E5; // 30min in ms
-}
-
-// define draw log function
-function drawLog(topY, viewUntil) {
-  // set default view time
-  viewUntil = viewUntil || Date();
-
-  // define parameters
-  var statusValue = [0, 0.4, 0.6, 1]; // unknown, not worn, awake, sleeping, consecutive sleep
-  var statusColor = [0, 63488, 2016, 32799, 31]; // black, red, green, violet, blue
-  var period = 432E5; // 12h
-  var graphHeight = 18;
-  var labelHeight = 12;
-  var width = g.getWidth();
-  var timestamp0 = viewUntil.valueOf() - period;
-  var y = topY + graphHeight;
-
-  // read 12h wide log
-  var log = require("sleeplog").readLog(0, timestamp0, viewUntil.valueOf());
-
-  // format log array if not empty
-  if (log.length) {
-    // if the period goes into the future add unknown status at the beginning
-    if (viewUntil > Date()) log.unshift([Date().valueOf(), 0]);
-
-    // check if the period goes earlier than logged data
-    if (log[log.length - 1][0] < timestamp0) {
-      // set time of last entry according to period
-      log[log.length - 1][0] = timestamp0;
-    } else {
-      // add entry with unknown status at the end
-      log.push([timestamp0, 0]);
-    }
-
-    // remap each element to [status, relative beginning, relative end, duration]
-    log = log.map((element, index) => [
-      element[1],
-      element[0] - timestamp0,
-      (log[index - 1] || [viewUntil.valueOf()])[0] - timestamp0,
-      (log[index - 1] || [viewUntil.valueOf()])[0] - element[0]
-    ]);
-
-    // start with the oldest entry to build graph left to right
-    log.reverse();
-  }
-
-  // clear area
-  g.reset().clearRect(0, topY, width, y + labelHeight);
-  // draw x axis
-  g.drawLine(0, y + 1, width, y + 1);
-  // draw x label
-  var hours = period / 36E5;
-  var stepwidth = width / hours;
-  var startHour = 24 + viewUntil.getHours() - hours;
-  for (var x = 0; x < hours; x++) {
-    g.fillRect(x * stepwidth, y + 2, x * stepwidth, y + 4);
-    g.setFontAlign(-1, -1).setFont("6x8")
-      .drawString((startHour + x) % 24, x * stepwidth + 1, y + 6);
-  }
-
-  // define variables for sleep calculation
-  var consecutive = 0;
-  var output = [0, 0]; // [estimated, true]
-  var i, nosleepduration;
-
-  // draw graph
-  log.forEach((element, index) => {
-    // set bar color depending on type
-    g.setColor(statusColor[consecutive ? 4 : element[0]]);
-
-    // check for sleeping status
-    if (element[0] === 3) {
-      // count true sleeping hours
-      output[1] += element[3];
-      // count duration of subsequent non sleeping periods
-      i = index + 1;
-      nosleepduration = 0;
-      while (log[i] !== undefined && log[i][0] < 3 && nosleepduration < maxawake) {
-        nosleepduration += log[i++][3];
-      }
-      // check if counted duration lower than threshold to start/stop counting
-      if (log[i] !== undefined && nosleepduration < maxawake) {
-        // start counting consecutive sleeping hours
-        consecutive += element[3];
-        // correct color to match consecutive sleeping
-        g.setColor(statusColor[4]);
-      } else {
-        // check if counted consecutive sleeping greater then threshold
-        if (consecutive >= minconsec) {
-          // write verified consecutive sleeping hours to output
-          output[0] += consecutive + element[3];
+// touch listener for specific areas
+function touchListener(b, c) {
+  // check if inside any area
+  for (var i = 0; i < aaa.length; i++) {
+    if (!(c.x < aaa[i].x0 || c.x > aaa[i].x1 || c.y < aaa[i].y0 || c.y > aaa[i].y1)) {
+      // check if drawing ongoing
+      if (drawingID > 0) {
+        // check if interrupt is set
+        if (aaa[i].interrupt) {
+          // stop ongoing drawing
+          drawingID++;
+          if (ATID) ATID = clearTimeout(ATID);
         } else {
-          // correct color to display a canceled consecutive sleeping period
-          g.setColor(statusColor[3]);
+          // do nothing
+          return;
         }
-        // stop counting consecutive sleeping hours
-        consecutive = 0;
       }
-    } else {
-      // count durations of non sleeping periods for consecutive sleeping
-      if (consecutive) consecutive += element[3];
+      // give feedback
+      Bangle.buzz(25);
+      // execute action
+      aaa[i].funct();
     }
-
-    // calculate points
-    var x1 = Math.ceil(element[1] / period * width);
-    var x2 = Math.floor(element[2] / period * width);
-    var y2 = y - graphHeight * statusValue[element[0]];
-    // draw bar
-    g.clearRect(x1, topY, x2, y);
-    g.fillRect(x1, y, x2, y2).reset();
-    if (y !== y2) g.fillRect(x1, y2, x2, y2);
-  });
-
-  // clear variables
-  log = undefined;
-
-  // return convert output into minutes
-  return output.map(value => value /= 6E4);
-}
-
-// define function to draw the analysis
-function drawAnalysis(toDate) {
-  //var t0 = Date.now();
-
-  // get width
-  var width = g.getWidth();
-
-  // define variable for sleep calculation
-  var outputs = [0, 0]; // [estimated, true]
-
-  // clear analysis area
-  g.clearRect(0, 71, width, width);
-
-  // draw log graphs and read outputs
-  drawLog(110, toDate).forEach(
-    (value, index) => outputs[index] += value);
-  drawLog(144, Date(toDate.valueOf() - 432E5)).forEach(
-    (value, index) => outputs[index] += value);
-
-  // draw outputs
-  g.reset(); // area: 0, 70, width, 105
-  g.setFont("6x8").setFontAlign(-1, -1);
-  g.drawString("consecutive\nsleeping", 10, 70);
-  g.drawString("true\nsleeping", 10, 90);
-  g.setFont("12x20").setFontAlign(1, -1);
-  g.drawString(Math.floor(outputs[0] / 60) + "h " +
-    Math.floor(outputs[0] % 60) + "min", width - 10, 70);
-  g.drawString(Math.floor(outputs[1] / 60) + "h " +
-    Math.floor(outputs[1] % 60) + "min", width - 10, 90);
-
-  //print("analysis processing seconds:", Math.round(Date.now() - t0) / 1000);
-}
-
-// define draw night to function
-function drawNightTo(prevDays) {
-  // calculate 10am of this or a previous day
-  var toDate = Date();
-  toDate = Date(toDate.getFullYear(), toDate.getMonth(), toDate.getDate() - prevDays, breaktod);
-
-  // get width
-  var width = g.getWidth();
-  var center = width / 2;
-
-  // reduce date by 1s to ensure correct headline
-  toDate = Date(toDate.valueOf() - 1E3);
-
-  // clear heading area
-  g.clearRect(0, 24, width, 70);
-
-  // display service states: service, loggging and powersaving
-  if (!sleeplog.enabled) {
-    // draw disabled service icon
-    g.setColor(1, 0, 0)
-      .drawImage(atob("FBSBAAH4AH/gH/+D//w/n8f5/nud7znP85z/f+/3/v8/z/P895+efGPj4Hw//8H/+Af+AB+A"), 2, 36);
-  } else if (!sleeplog.logfile) {
-    // draw disabled log icon
-    g.reset().drawImage(atob("EA6BAM//z/8AAAAAz//P/wAAAADP/8//AAAAAM//z/8="), 4, 40)
-      .setColor(1, 0, 0).fillPoly([2, 38, 4, 36, 22, 54, 20, 56]);
   }
-  // draw power saving icon
-  if (sleeplog.powersaving) g.setColor(0, 1, 0)
-    .drawImage(atob("FBSBAAAAcAD/AH/wP/4P/+H//h//4//+fv/nj/7x/88//Of/jH/4j/8I/+Af+AH+AD8AA4AA"), width - 22, 36);
-
-  // draw headline
-  g.reset().setFont("12x20").setFontAlign(0, -1);
-  g.drawString("Night to " + require('locale').dow(toDate, 1) + "\n" +
-    require('locale').date(toDate, 1), center, 30);
-
-  // show loading info
-  var info = "calculating data ...\nplease be patient :)";
-  var y0 = center + 30;
-  var bounds = [center - 80, y0 - 20, center + 80, y0 + 20];
-  g.clearRect.apply(g, bounds).drawRect.apply(g, bounds);
-  g.setFont("6x8").setFontAlign(0, 0);
-  g.drawString(info, center, y0);
-
-  // calculate and draw analysis after timeout for faster feedback
-  if (ATID) ATID = clearTimeout(ATID);
-  ATID = setTimeout(drawAnalysis, 100, toDate);
 }
 
-// define function to draw and setup UI
-function startApp() {
-  readSettings(storage.readJSON("sleeplog.json", true) || {});
-  drawNightTo(prevDays);
-  Bangle.setUI("leftright", (cb) => {
-    if (!cb) {
-      eval(storage.read("sleeplog.settings.js"))(startApp);
-    } else if (prevDays + cb >= -1) {
-      drawNightTo((prevDays += cb));
+// swipe listener for switching the displayed day
+function swipeListener(h, v) {
+  // give feedback
+  Bangle.buzz(25);
+  // set previous or next day
+  prevDays += h;
+  if (prevDays < -1) prevDays = -1;
+  // redraw
+  draw();
+}
+
+// day selection
+function daySelection() {
+  var date = Date(startDate - prevDays * 864E5).toString().split(" ");
+  E.showPrompt(date.slice(0, 3).join(" ") + "\n" + date[3] + "\n" +
+    prevDays + /*LANG*/" days before today", {
+      title: /*LANG*/"Select Day",
+      buttons: {
+        "<<7": 7,
+        "<1": 1,
+        "Ok": 0,
+        "1>": -1,
+        "7>>": -7
+      }
+    }).then(function(v) {
+    if (v) {
+      prevDays += v;
+      if (prevDays < -1) prevDays = -1;
+      daySelection();
+    } else {
+      fromMenu();
     }
   });
 }
 
-// define day to display and analysis timeout id
-var prevDays = 0;
-var ATID;
+// open settings menu
+function openSettings() {
+  // disable back behaviour to prevent bouncing on return
+  backListener = () => {};
+  // open settings menu
+  eval(require("Storage").read("sleeplog.settings.js"))(fromMenu);
+}
 
-// setup app
-g.clear();
+// draw progress as bar, increment on undefined percentage
+function drawProgress(progress) {
+  g.fillRect(19, 147, 136 * progress + 19, 149);
+}
+
+// (re)draw info data
+function drawInfo() {
+  // set active info type
+  var info = infoData[infoType % infoData.length];
+  // draw info
+  g.clearRect(0, 69, 175, 105).reset()
+    .setFont("6x8").setFontAlign(-1, -1)
+    .drawString(info[0][0], 10, 70)
+    .drawString(info[1][0], 10, 90)
+    .setFont("12x20").setFontAlign(1, -1)
+    .drawString((info[0][1] / 60 | 0) + "h " + (info[0][1] % 60) + "min", 166, 70)
+    .drawString((info[1][1] / 60 | 0) + "h " + (info[1][1] % 60) + "min", 166, 90);
+  // free ram
+  info = undefined;
+}
+
+
+// draw graph for log segment
+function drawGraph(log, date, pos) {
+  // set y position
+  var y = pos ? 144 : 110;
+  // clear area
+  g.reset().clearRect(0, y, width, y + 33);
+  // draw x axis
+  g.drawLine(0, y + 19, width, y + 19);
+  // draw x label
+  var stepWidth = width / 12;
+  var startHour = date.getHours() + (pos ? 0 : 12);
+  for (var x = 0; x < 12; x++) {
+    g.fillRect(x * stepWidth, y + 20, x * stepWidth, y + 22);
+    g.setFontAlign(-1, -1).setFont("6x8")
+      .drawString((startHour + x) % 24, x * stepWidth + 1, y + 24);
+  }
+
+  // set height and color values:
+  // status: unknown, not worn, awake, light sleep, deep sleep, consecutive
+  // color:  black,   red,      green, cyan,        blue,       violet
+  var heights = [0, 0.4, 0.6, 0.8, 1];
+  var colors = [0, 63488, 2016, 2047, 31, 32799];
+
+  // cycle through log
+  log.forEach((entry, index, log) => {
+    // calculate positions
+    var x1 = Math.ceil((entry[0] - log[0][0]) / 72 * width);
+    var x2 = Math.floor(((log[index + 1] || [date / 6E5])[0] - log[0][0]) / 72 * width);
+    // calculate y2 position
+    var y2 = y + 18 * (1 - heights[entry[1]]);
+    // set color depending on status and consecutive sleep
+    g.setColor(colors[entry[2] === 2 ? 5 : entry[1]]);
+    // clear area, draw bar and top line
+    g.clearRect(x1, y, x2, y + 18);
+    g.fillRect(x1, y + 18, x2, y2).reset();
+    if (y + 18 !== y2) g.fillRect(x1, y2, x2, y2);
+  });
+}
+
+// draw information in an interruptable cycle
+function drawingCycle(calcDate, thisID, cycle, log) {
+  // reset analysis timeout ID
+  ATID = undefined;
+
+  // check drawing ID to continue
+  if (thisID !== drawingID) return;
+
+  // check cycle
+  if (!cycle) {
+    /* read log on first cycle */
+    // set initial cycle
+    cycle = 1;
+
+    // read log
+    log = slMod.readLog(calcDate - 864E5, calcDate);
+
+    // draw progress
+    drawProgress(0.6);
+  } else if (cycle === 2) {
+    /* draw stats on second cycle */
+
+    // read stats and process into info data
+    infoData = slMod.getStats(calcDate, 0, log);
+    infoData = [
+      [
+        [ /*LANG*/"consecutive\nsleeping", infoData.consecSleep],
+        [ /*LANG*/"true\nsleeping", infoData.deepSleep + infoData.lightSleep]
+      ],
+      [
+        [ /*LANG*/"deep\nsleep", infoData.deepSleep],
+        [ /*LANG*/"light\nsleep", infoData.lightSleep]
+      ],
+      [
+        [ /*LANG*/"awake", infoData.awakeTime],
+        [ /*LANG*/"not worn", infoData.notWornTime]
+      ]
+    ];
+    // draw info
+    drawInfo();
+
+    // draw progress
+    drawProgress(0.9);
+  } else if (cycle === 3) {
+    /* segment log on third cycle */
+    // calculate segmentation date in 10min steps and index of the segmentation
+    var segmDate = calcDate / 6E5 - 72;
+    var segmIndex = log.findIndex(entry => entry[0] >= segmDate);
+
+    // check if segmentation neccessary
+    if (segmIndex > 0) {
+      // split log
+      log = [log.slice(segmIndex), log.slice(0, segmIndex)];
+      // add entry at segmentation point
+      if (log[0][0] !== segmDate)
+        log[0].unshift([segmDate, log[1][segmIndex - 1][1], log[1][segmIndex - 1][2]]);
+    } else if (segmIndex < 0) {
+      // set log as second log entry
+      log = [
+        [], log
+      ];
+    } else {
+      // add entry at segmentation point
+      if (log[0] !== segmDate) log.unshift([segmDate, 0, 0]);
+      // set log as first log entry
+      log = [log, []];
+    }
+
+    // draw progress
+    drawProgress(1);
+  } else if (cycle === 4) {
+    /* draw upper graph on fourth cycle */
+    drawGraph(log[0], calcDate, 0);
+  } else if (cycle === 5) {
+    /* draw upper graph on fifth cycle */
+    drawGraph(log[1], calcDate, 1);
+  } else {
+    /* stop cycle and set drawing finished */
+    drawingID = 0;
+    // give feedback
+    Bangle.buzz(25);
+  }
+
+  // initiate next cycle if defined
+  if (thisID === drawingID) ATID = setTimeout(drawingCycle, 10, calcDate, drawingID, ++cycle, log);
+}
+
+// return from a menu
+function fromMenu() {
+  // reset UI to custom mode
+  Bangle.setUI(customUI);
+  // enable back behaviour delayed to prevent bouncing
+  setTimeout(() => backListener = load, 500);
+  // redraw app
+  draw();
+}
+
+// draw app
+function draw() {
+  // stop ongoing drawing
+  drawingID++;
+  if (ATID) ATID = clearTimeout(ATID);
+
+  // clear app area
+  g.reset().clearRect(0, 24, width, width);
+
+  // set date to calculate data for
+  var calcDate = new Date(startDate - prevDays * 864E5);
+
+  // draw title
+  g.setFont("12x20").setFontAlign(0, -1)
+    .drawString( /*LANG*/"Night to " + require('locale').dow(calcDate, 1) + "\n" +
+      require('locale').date(calcDate, 1), 87, 28);
+
+  // reset graphics and define image string
+  g.reset();
+  var imgStr = "";
+  // check which icon to set
+  if (!global.sleeplog || sleeplog.conf.enabled !== true) {
+    // set color and disabled service icon
+    g.setColor(1, 0, 0);
+    imgStr = "FBSBAOAAfwAP+AH3wD4+B8Hw+A+fAH/gA/wAH4AB+AA/wAf+APnwHw+D4Hx8A++AH/AA/gAH";
+  } else if (sleeplog.debug) {
+    // set debugging icon
+    imgStr = typeof sleeplog.debug === "object" ?
+      "FBSBAB/4AQDAF+4BfvAX74F+CBf+gX/oFJKBf+gUkoF/6BSSgX/oFJ6Bf+gX/oF/6BAAgf/4" : // file
+      "FBSBAP//+f/V///4AAGAABkAAZgAGcABjgAYcAGDgBhwAY4AGcABmH+ZB/mAABgAAYAAH///"; // console
+  }
+  // draw service and settings icon
+  if (imgStr) g.drawImage(atob(imgStr), 2, 36);
+  g.reset().drawImage(atob("FBSBAAAeAAPgAHwAB4AA8AAPAwDwcA+PAP/wH/4D/8B/8A/gAfwAP4AH8AD+AA/AAPgABwAA"), width - 22, 36);
+
+  // show loading info with progresss bar
+  g.reset().drawRect(7, 117, width - 8, 157)
+    .setFont("6x8").setFontAlign(0, 0)
+    .drawString( /*LANG*/ "calculating data ...\nplease be patient :)", 87, 133)
+    .drawRect(17, 145, 157, 151);
+
+  // draw first progress
+  drawProgress(0.1);
+
+  // initiate drawing cycle
+  ATID = setTimeout(drawingCycle, 10, calcDate, drawingID, 0);
+}
+
+// define sleeplog module
+var slMod = require("sleeplog");
+
+// read app timeout from settings
+var appTimeout = (require("Storage").readJSON("sleeplog.json", true) || {}).appTimeout;
+
+// set listener for back button
+var backListener = load;
+// define custom UI mode
+var customUI = {
+  mode: "custom",
+  back: backListener,
+  touch: touchListener,
+  swipe: swipeListener
+};
+
+// define start values
+var startDate = slMod.getLastBreak(); // date to start from
+var prevDays = 0; //  number of previous days to display
+var infoType = 0; //  type of info data to display
+var infoData; //      storage for info data
+var ATID; //          analysis timeout ID
+var drawingID = 0; // drawing ID for ongoing process
+// get screen width and center (zero based)
+var width = g.getWidth() - 1;
+var center = width / 2 - 1;
+
+// set areas and actions array
+var aaa = [
+  // day selection
+  {
+    x0: 26,
+    x1: width - 26,
+    y0: 24,
+    y1: 68,
+    interrupt: true,
+    funct: () => daySelection()
+  },
+  // open settings
+  {
+    x0: width - 26,
+    x1: width,
+    y0: 24,
+    y1: 68,
+    interrupt: true,
+    funct: () => openSettings()
+  },
+  // change info type
+  {
+    x0: 0,
+    x1: width,
+    y0: 69,
+    y1: 105,
+    funct: () => {
+      // change info type
+      infoType++;
+      // redraw info
+      drawInfo();
+    }
+  }
+];
+
+// clear and reset screen
+g.clear(true);
+
+// load and draw widgets
 Bangle.loadWidgets();
 Bangle.drawWidgets();
 
-// start app
-startApp();
+// set UI in custom mode
+Bangle.setUI(customUI);
+
+// set app timeout if defined
+if (appTimeout) Bangle.setOptions({
+  lockTimeout: appTimeout,
+  backlightTimeout: appTimeout
+});
+
+// draw app
+draw();
diff --git a/apps/sleeplog/boot.js b/apps/sleeplog/boot.js
index f989e2835..c1f8a2d2d 100644
--- a/apps/sleeplog/boot.js
+++ b/apps/sleeplog/boot.js
@@ -1,169 +1,330 @@
-// Sleep/Wake detection with Estimation of Stationary Sleep-segments (ESS):
-// Marko Borazio, Eugen Berlin, Nagihan Kücükyildiz, Philipp M. Scholl and Kristof Van Laerhoven, "Towards a Benchmark for Wearable Sleep Analysis with Inertial Wrist-worn Sensing Units", ICHI 2014, Verona, Italy, IEEE Press, 2014.
-// https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en
+// sleeplog.status values:
+// undefined = service stopped,  0 = unknown, 1 = not worn, 2 = awake, 3 = light sleep, 4 = deep sleep
+// sleeplog.consecutive values:
+// undefined = service stopped,  0 = unknown, 1 = no consecutive sleep, 2 = consecutive sleep
 
-// sleeplog.status values: undefined = service stopped,  0 = unknown, 1 = not worn, 2 = awake, 3 = sleeping
-
-// load settings into global object 
-global.sleeplog = Object.assign({
-  enabled: true, // en-/disable completely
-  logfile: "sleeplog.log", // logfile
-  powersaving: false, // disables ESS and uses build in movement detection
-  winwidth: 13, // 13 values, read with 12.5Hz = every 1.04s
-  nomothresh: 0.012, // values lower than 0.008 getting triggert by noise
-  sleepthresh: 577, // 577 times no movement * 1.04s window width > 10min
-  maxmove: 100, // movement threshold on power saving mode
-  tempthresh: 27, // every temperature above ist registered as worn
-}, require("Storage").readJSON("sleeplog.json", true) || {});
-
-// delete app settings
-["breaktod", "maxawake", "minconsec"].forEach(property => delete sleeplog[property]);
-
-// check if service enabled
-if (sleeplog.enabled) {
-
-  // add always used values and functions to global object
-  sleeplog = Object.assign(sleeplog, {
-    // set cached values
-    resting: undefined,
-    status: undefined,
-
-    // define function to handle stopping the service, it will be restarted on reload if enabled
-    stopHandler: function() {
-      // remove all listeners
-      Bangle.removeListener('accel', sleeplog.accel);
-      Bangle.removeListener('health', sleeplog.health);
-      // write log with undefined sleeping status
-      require("sleeplog").writeLog(0, [Math.floor(Date.now()), 0]);
-      // reset cached values if sleeplog is defined
-      if (global.sleeplog) {
-        sleeplog.resting = undefined;
-        sleeplog.status = undefined;
-        // reset cached ESS calculation values
-        if (!sleeplog.powersaving) {
-          sleeplog.ess_values = [];
-          sleeplog.nomocount = 0;
-          sleeplog.firstnomodate = undefined;
-        }
-      }
-    },
-
-    // define function to remove the kill listener and stop the service
-    // https://github.com/espruino/BangleApps/issues/1445
-    stop: function() {
-      E.removeListener('kill', sleeplog.stopHandler);
-      sleeplog.stopHandler();
-    },
+// create global object with settings
+global.sleeplog = {
+  conf: Object.assign({
+    // main settings
+    enabled: true, //   en-/disable completely
+    // threshold settings
+    maxAwake: 36E5, //  [ms] maximal awake time to count for consecutive sleep
+    minConsec: 18E5, // [ms] minimal time to count for consecutive sleep
+    deepTh: 100, //     threshold for deep sleep
+    lightTh: 200, //    threshold for light sleep
+  }, require("Storage").readJSON("sleeplog.json", true) || {})
+};
 
+// check if service is enabled
+if (sleeplog.conf.enabled) {
+  // assign functions to global object
+  global.sleeplog = Object.assign({
     // define function to initialy start or restart the service
     start: function() {
-      // add kill listener
-      E.on('kill', sleeplog.stopHandler);
-      // add health listener if defined and 
-      if (sleeplog.health) Bangle.on('health', sleeplog.health);
-      // add acceleration listener if defined and set status to unknown
-      if (sleeplog.accel) Bangle.on('accel', sleeplog.accel);
-      // read log since 5min ago and restore status to last known state or unknown
-      sleeplog.status = (require("sleeplog").readLog(0, Date.now() - 3E5)[1] || [0, 0])[1];
-      // update resting according to status
-      sleeplog.resting = sleeplog.status % 2;
-      // write restored status to log
-      require("sleeplog").writeLog(0, [Math.floor(Date.now()), sleeplog.status]);
+      // add kill and health listener
+      E.on('kill', sleeplog.saveStatus);
+      Bangle.on('health', sleeplog.health);
+
+      // restore saved status
+      this.restoreStatus();
+    },
+
+    // define function to stop the service, it will be restarted on reload if enabled
+    stop: function() {
+      // remove all listeners
+      Bangle.removeListener('health', sleeplog.health);
+      E.removeListener('kill', sleeplog.saveStatus);
+
+      // save active values
+      this.saveStatus();
+      // reset active values
+      this.status = undefined;
+      this.consecutive = undefined;
+    },
+
+    // define function to restore active values on a restart or reload
+    restoreStatus: function() {
+      // define restore objects with default values
+      var restore = {
+        status: 0,
+        consecutive: 0,
+        info: {}
+      };
+
+      // open log file
+      var file = require("Storage").open("sleeplog.log", "r");
+      // read last 55 chars from log
+      file.read(file.getLength() - 52);
+      file = file.read(52);
+
+      // check if the log contains data
+      if (file) {
+        // remove unneeded data
+        file = file.trim().split("\n").reverse().filter((e, i) => i < 2);
+        // convert file into accessable array
+        file = file.map(e => e.split(",").map(e => parseInt(e)));
+
+        // add default data if no previous status is available
+        if (file.length < 2 || file[1].length !== 3) file.push([0, 0, 0]);
+
+        // check if data to restore has been saved
+        if (file[0].length > 3) {
+          // read data into restore object
+          restore = {
+            status: file[1][1],
+            consecutive: file[1][2],
+            info: {
+              lastChange: file[1][0] * 6E5,
+              lastCheck: file[0][1] * 6E5,
+              awakeSince: file[0][2] * 6E5,
+              asleepSince: file[0][3] * 6E5
+            }
+          };
+
+          // add debug if set
+          if (file[0].length === 6)
+            restore = Object.assign(restore, {
+              debug: file[0][4] ? {
+                writeUntil: file[0][4] * 6E5,
+                fileid: file[0][5]
+              } : true
+            });
+
+          // calculate timestamp in 10min steps, corrected to 10min ago
+          var timestamp = (Date.now() / 6E5 | 0) - 1;
+
+          // check if restored status not unknown and lastCheck was 20min before timestamp
+          if (restore.status && restore.info.lastCheck + 12E5 < timestamp) {
+            // set status and consecutive to unknown
+            restore.status = 0;
+            restore.consecutive = 0;
+            restore.info.lastChange = restore.info.lastCheck + 6E5;
+            restore.info.lastCheck = timestamp;
+            // write undefined status 10min after restored lastCheck
+            this.appendStatus(restore.info.lastChange, 0, 0);
+          } else {
+            // set saveUpToDate
+            restore.info.saveUpToDate = true;
+          }
+        }
+      }
+
+      // write restored values into global object
+      global.sleeplog = Object.assign(this, restore);
+    },
+
+    // define function to save active values on a stop or kill event
+    // - called by event listener: "this"-reference points to global
+    saveStatus: function(force) {
+      // check if global variable accessable
+      if (!global.sleeplog) return new Error("sleeplog: Can't save status, global object missing!");
+
+      // check saveUpToDate is not set or forced
+      if (!sleeplog.info.saveUpToDate || force) {
+        // save status, consecutive status and info timestamps to restore on reload
+        var save = [sleeplog.info.lastCheck, sleeplog.info.awakeSince, sleeplog.info.asleepSince];
+        // add debuging status if active 
+        if (sleeplog.debug) save.push(sleeplog.debug.writeUntil, sleeplog.debug.fileid);
+
+        // stringify entries
+        save = "," + save.map((entry, index) => {
+          if (index < 4) entry /= 6E5; // store in 10min steps
+          return entry | 0; // sanitize
+        }).join(",") + "\n";
+
+        // add present status if forced
+        if (force) save = (sleeplog.info.lastChange / 6E5) + "," +
+          sleeplog.status + "," + sleeplog.consecutive + "\n" + save;
+
+        // append saved data to StorageFile
+        require("Storage").open("sleeplog.log", "a").write(save);
+
+        // clear save string to free ram
+        save = undefined;
+      }
+    },
+
+    // define health listener function
+    // - called by event listener: "this"-reference points to global
+    health: function(data) {
+      // check if global variable accessable
+      if (!global.sleeplog) return new Error("sleeplog: Can't process health event, global object missing!");
+
+      // check if movement is available
+      if (!data.movement) return;
+
+      // add timestamp rounded to 10min, corrected to 10min ago
+      data.timestamp = data.timestamp || ((Date.now() / 6E5 | 0) - 1) * 6E5;
+
+      // add preliminary status depending on charging and movement thresholds
+      data.status = Bangle.isCharging() ? 1 :
+        data.movement <= sleeplog.conf.deepTh ? 4 :
+        data.movement <= sleeplog.conf.lightTh ? 3 : 2;
+
+      // check if changing to deep sleep from non sleepling
+      if (data.status === 4 && sleeplog.status <= 2) {
+        // check wearing status
+        sleeplog.checkIsWearing((isWearing, data) => {
+          // correct status
+          if (!isWearing) data.status = 1;
+          // set status
+          sleeplog.setStatus(data);
+        }, data);
+      } else {
+        // set status
+        sleeplog.setStatus(data);
+      }
+    },
+
+    // define function to check if the bangle is worn by using the hrm
+    checkIsWearing: function(returnFn, data) {
+      // create a temporary object to store data and functions
+      global.tmpWearingCheck = {
+        // define temporary hrm listener function to read the wearing status
+        hrmListener: hrm => tmpWearingCheck.isWearing = hrm.isWearing,
+        // set default wearing status
+        isWearing: false,
+      };
+
+      // enable HRM
+      Bangle.setHRMPower(true, "wearingCheck");
+      // wait until HRM is initialised
+      setTimeout((returnFn, data) => {
+        // add HRM listener
+        Bangle.on('HRM-raw', tmpWearingCheck.hrmListener);
+        // wait for two cycles (HRM working on 60Hz)
+        setTimeout((returnFn, data) => {
+          // remove listener and disable HRM
+          Bangle.removeListener('HRM-raw', tmpWearingCheck.hrmListener);
+          Bangle.setHRMPower(false, "wearingCheck");
+          // cache wearing status
+          var isWearing = tmpWearingCheck.isWearing;
+          // clear temporary object
+          delete global.tmpWearingCheck;
+          // call return function with status
+          returnFn(isWearing, data);
+        }, 34, returnFn, data);
+      }, 2500, returnFn, data);
+    },
+
+    // define function to set the status
+    setStatus: function(data) {
+      // update lastCheck
+      this.info.lastCheck = data.timestamp;
+
+      // correct light sleep status to awake if
+      //  previous status not deep sleep and not too long awake (asleepSince unset)
+      if (data.status === 3 && this.status !== 4 && !this.info.asleepSince) {
+        data.status = 2;
+      }
+
+      // cache consecutive status to check for changes later on
+      data.consecutive = this.consecutive;
+
+      // check if changing to deep sleep from non sleepling
+      if (data.status === 4 && this.status <= 2) {
+        // set asleepSince if undefined
+        this.info.asleepSince = this.info.asleepSince || data.timestamp;
+        // reset consecutive status
+        data.consecutive = 0;
+        // check if changing to awake
+      } else if (data.status === 2 && this.status > 2) {
+        // set awakeSince if undefined
+        this.info.awakeSince = this.info.awakeSince || data.timestamp;
+        // reset consecutive status
+        data.consecutive = 0;
+      }
+      // check if consecutive unknown
+      if (!this.consecutive) {
+        // check if long enough asleep or too long awake
+        if (data.status === 4 && this.info.asleepSince &&
+          this.info.asleepSince + this.conf.minConsec <= data.timestamp) {
+          // set consecutive sleep
+          data.consecutive = 2;
+          // reset awakeSince
+          this.info.awakeSince = 0;
+        } else if (data.status <= 2 && this.info.awakeSince &&
+          this.info.awakeSince + this.conf.maxAwake <= data.timestamp) {
+          // set non consecutive sleep
+          data.consecutive = 1;
+          // reset asleepSince
+          this.info.asleepSince = 0;
+        }
+      }
+
+      // cache change into a known consecutive state
+      var changeIntoConsec = data.consecutive;
+
+      // check if the status has changed
+      if (data.status !== this.status || data.consecutive !== this.consecutive) {
+        // append status
+        this.appendStatus(data.timestamp, data.status, data.consecutive);
+
+        // set new states and update lastChange
+        this.status = data.status;
+        this.consecutive = data.consecutive;
+        this.info.lastChange = data.timestamp;
+        // reset saveUpToDate status
+        delete this.info.saveUpToDate;
+      }
+      
+      // send status to gadgetbridge
+      var gb_kinds = "unknown,not_worn,activity,light_sleep,deep_sleep";
+      Bluetooth.println(JSON.stringify({
+        t: "act",
+        act: gb_kinds.split(",")[data.status],
+        ts: data.timestamp
+      }));
+
+      // call debugging function if set
+      if (this.debug) require("sleeplog").debug(data);
+
+      // check if changed into known consecutive state
+      if (changeIntoConsec) {
+        // check if change is to consecutive sleep or not
+        if (changeIntoConsec === 2) {
+          // call move log function
+          require("sleeplog").moveLog();
+        } else {
+          // update stats cache if available
+          if (this.statsCache) this.statsCache = require("sleeplog").getStats();
+        }
+        // remove module from cache if cached
+        if (Modules.getCached().includes("sleeplog")) Modules.removeCached("sleeplog");
+      }
+    },
+
+    // define function to append the status to the StorageFile log
+    appendStatus: function(timestamp, status, consecutive) {
+      // exit on missing timestamp
+      if (!timestamp) return;
+      // reduce timestamp to 10min step
+      timestamp = timestamp / 6E5 | 0;
+      // append to StorageFile
+      require("Storage").open("sleeplog.log", "a").write(
+        [timestamp, status || 0, consecutive || 0].join(",") + "\n"
+      );
+    },
+
+    // define function to access stats of the last night
+    getStats: function() {
+      // check if stats cache is not defined or older than 12h
+      //  if stats cache is set it will be updated on every change to non consecutive sleep
+      if (this.statsCache === undefined || this.statsCache.calculatedAt + 432E5 < Date.now()) {
+        // read stats of the last night into cache and remove module from cache
+        this.statsCache = require("sleeplog").getStats();
+        // remove module from cache if cached
+        if (Modules.getCached().includes("sleeplog")) Modules.removeCached("sleeplog");
+      }
+      // return stats cache
+      return this.statsCache;
     }
-  });
-
-  // check for power saving mode
-  if (sleeplog.powersaving) {
-    // power saving mode using build in movement detection
-    // delete unused settings
-    ["winwidth", "nomothresh", "sleepthresh"].forEach(property => delete sleeplog[property]);
-    // add cached values and functions to global object
-    sleeplog = Object.assign(sleeplog, {
-      // define health listener function
-      health: function(data) {
-        // set global object and check for existence
-        var gObj = global.sleeplog;
-        if (!gObj) return;
-
-        // calculate timestamp for this measurement
-        var timestamp = Math.floor(Date.now() - 6E5);
-
-        // check for non-movement according to the threshold
-        if (data.movement <= gObj.maxmove) {
-          // check resting state
-          if (gObj.resting !== true) {
-            // change resting state
-            gObj.resting = true;
-            // set status to sleeping or worn
-            gObj.status = E.getTemperature() > gObj.tempthresh ? 3 : 1;
-            // write status to log, 
-            require("sleeplog").writeLog(0, [timestamp, gObj.status, E.getTemperature()]);
-          }
-        } else {
-          // check resting state
-          if (gObj.resting !== false) {
-            // change resting state, set status and write status to log
-            gObj.resting = false;
-            gObj.status = 2;
-            require("sleeplog").writeLog(0, [timestamp, 2]);
-          }
-        }
-      }
-    });
-  } else {
-    // full ESS calculation
-    // add cached values and functions to global object
-    sleeplog = Object.assign(sleeplog, {
-      // set cached values
-      ess_values: [],
-      nomocount: 0,
-      firstnomodate: undefined,
-
-      // define acceleration listener function
-      accel: function(xyz) {
-        // save acceleration magnitude and start calculation on enough saved data
-        if (global.sleeplog && sleeplog.ess_values.push(xyz.mag) >= sleeplog.winwidth) sleeplog.calc();
-      },
-
-      // define calculator function
-      calc: function() {
-        // exit on wrong this
-        if (this.enabled === undefined) return;
-        // calculate standard deviation over 
-        var mean = this.ess_values.reduce((prev, cur) => cur + prev) / this.winwidth;
-        var stddev = Math.sqrt(this.ess_values.map(val => Math.pow(val - mean, 2)).reduce((prev, cur) => prev + cur) / this.winwidth);
-        // reset saved acceleration data
-        this.ess_values = [];
-
-        // check for non-movement according to the threshold
-        if (stddev < this.nomothresh) {
-          // increment non-movement sections count, set date of first non-movement
-          if (++this.nomocount == 1) this.firstnomodate = Math.floor(Date.now());
-          // check resting state and non-movement count against threshold
-          if (this.resting !== true && this.nomocount >= this.sleepthresh) {
-            // change resting state
-            this.resting = true;
-            // set status to sleeping or worn
-            this.status = E.getTemperature() > this.tempthresh ? 3 : 1;
-            // write status to log, with first no movement timestamp
-            require("sleeplog").writeLog(0, [this.firstnomodate, this.status, E.getTemperature()]);
-          }
-        } else {
-          // reset non-movement sections count
-          this.nomocount = 0;
-          // check resting state
-          if (this.resting !== false) {
-            // change resting state and set status
-            this.resting = false;
-            this.status = 2;
-            // write status to log 
-            require("sleeplog").writeLog(0, [Math.floor(Date.now()), 2]);
-          }
-        }
-      }
-    });
-  }
+  }, sleeplog);
 
   // initial starting
   global.sleeplog.start();
+} else {
+  // clear global object from ram
+  delete global.sleeplog;
 }
diff --git a/apps/sleeplog/conf_20x20.png b/apps/sleeplog/conf_20x20.png
new file mode 100644
index 000000000..4de9e9184
Binary files /dev/null and b/apps/sleeplog/conf_20x20.png differ
diff --git a/apps/sleeplog/debug_20x20.png b/apps/sleeplog/debug_20x20.png
new file mode 100644
index 000000000..f98ca0a88
Binary files /dev/null and b/apps/sleeplog/debug_20x20.png differ
diff --git a/apps/sleeplog/disabled.png b/apps/sleeplog/disabled.png
deleted file mode 100644
index 8e7d9fb2c..000000000
Binary files a/apps/sleeplog/disabled.png and /dev/null differ
diff --git a/apps/sleeplog/file_20x20.png b/apps/sleeplog/file_20x20.png
new file mode 100644
index 000000000..e38399bc6
Binary files /dev/null and b/apps/sleeplog/file_20x20.png differ
diff --git a/apps/sleeplog/interface.html b/apps/sleeplog/interface.html
new file mode 100644
index 000000000..d59515275
--- /dev/null
+++ b/apps/sleeplog/interface.html
@@ -0,0 +1,185 @@
+
+  
+    
+    
+  
+  
+    
+
+ + + + \ No newline at end of file diff --git a/apps/sleeplog/lib.js b/apps/sleeplog/lib.js index 752139e27..1919e7483 100644 --- a/apps/sleeplog/lib.js +++ b/apps/sleeplog/lib.js @@ -1,199 +1,465 @@ +// define accessable functions exports = { // define en-/disable function, restarts the service to make changes take effect - setEnabled: function(enable, logfile, powersaving) { - // check if sleeplog is available - if (typeof global.sleeplog !== "object") return; - - // set default logfile - if ((typeof logfile !== "string" || !logfile.endsWith(".log")) && - logfile !== false) logfile = "sleeplog.log"; - + setEnabled: function(enable) { // stop if enabled - if (global.sleeplog.enabled) global.sleeplog.stop(); + if (global.sleeplog && sleeplog.enabled) sleeplog.stop(); - // define storage and filename - var storage = require("Storage"); - var filename = "sleeplog.json"; + // define settings filename + var settings = "sleeplog.json"; // change enabled value in settings - storage.writeJSON(filename, Object.assign(storage.readJSON(filename, true) || {}, { - enabled: enable, - logfile: logfile, - powersaving: powersaving || false - })); + require("Storage").writeJSON(settings, Object.assign( + require("Storage").readJSON(settings, true) || {}, { + enabled: enable + } + )); // force changes to take effect by executing the boot script - eval(storage.read("sleeplog.boot.js")); + eval(require("Storage").read("sleeplog.boot.js")); - // clear variables - storage = undefined; - filename = undefined; return true; }, - // define read log function - // sorting: latest first, format: - // [[number, int, float, string], [...], ... ] - // - number // timestamp in ms - // - int // status: 0 = unknown, 1 = not worn, 2 = awake, 3 = sleeping - // - float // internal temperature - // - string // additional information - readLog: function(logfile, since, until) { - // check/set logfile - if (typeof logfile !== "string" || !logfile.endsWith(".log")) { - logfile = (global.sleeplog || {}).logfile || "sleeplog.log"; + // define read log function, returns log array + // sorting: ascending (latest first), format: + // [[number, int, int], [...], ... ] + // - number // timestamp in 10min + // - int // status: 0 = unknown, 1 = not worn, 2 = awake, 3 = light sleep, 4 = deep sleep + // - int // consecutive: 0 = unknown, 1 = no consecutive sleep, 2 = consecutive sleep + readLog: function(since, until) { + // set now and check if now is before since + var now = Date.now(); + if (now < since) return []; + + // set defaults and convert since, until and now to 10min steps + since = Math.floor((since || 0) / 6E5); + until = Math.ceil((until || now) / 6E5); + now = Math.ceil(now / 6E5); + + // define output log + var log = []; + + // open StorageFile + var file = require("Storage").open("sleeplog.log", "r"); + // cache StorageFile size + var storageFileSize = file.getLength(); + // check if a Storage File needs to be read + if (storageFileSize) { + // define previous line cache + var prevLine; + // loop through StorageFile entries + while (true) { + // cache new line + var line = file.readLine(); + // exit loop if all lines are read + if (!line) break; + // skip lines starting with "," + if (line.startsWith(",")) continue; + // parse line + line = line.trim().split(",").map(e => parseInt(e)); + // exit loop if new line timestamp is not before until + if (line[0] >= until) break; + // check if new line timestamp is 24h before since or not after since + if (line[0] + 144 < since) { + // skip roughly the next 10 lines + file.read(118); + file.readLine(); + } else if (line[0] <= since) { + // cache line for next cycle + prevLine = line; + } else { + // add previous line if it was cached + if (prevLine) log.push(prevLine); + // add new line at the end of log + log.push(line); + // clear previous line cache + prevLine = undefined; + } + } + // add previous line if it was cached + if (prevLine) log.push(prevLine); + // set unknown consecutive statuses + log = log.reverse().map((entry, index) => { + if (entry[2] === 0) entry[2] = (log[index - 1] || [])[2] || 0; + return entry; + }).reverse(); + // remove duplicates + log = log.filter((entry, index) => + !(index > 0 && entry[1] === log[index - 1][1] && entry[2] === log[index - 1][2]) + ); } - // check if since is in the future - if (since > Date()) return []; + // check if log empty or first entry is after since + if (!log[0] || log[0][0] > since) { + // look for all needed storage files + var files = require("Storage").list(/^sleeplog_\d\d\d\d\.log$/, { + sf: false + }); - // read logfile - var log = require("Storage").read(logfile); - // return empty log - if (!log) return []; - // decode data if needed - if (log[0] !== "[") log = atob(log); - // do a simple check before parsing - if (!log.startsWith("[[") || !log.endsWith("]]")) return []; - log = JSON.parse(log) || []; + // check if any file available + if (files.length) { + // generate start and end times in 10min steps + files = files.map(file => { + var start = this.fnToMs(parseInt(file.substr(9, 4))) / 6E5; + return { + name: file, + start: start, + end: start + 2016 + }; + }).sort((a, b) => b.start - a.start); - // check if filtering is needed - if (since || until) { - // search for latest entry befor since - if (since) since = (log.find(element => element[0] <= since) || [0])[0]; - // filter selected time period - log = log.filter(element => (element[0] >= since) && (element[0] <= (until || 1E14))); + // read all neccessary files + var filesLog = []; + files.some(file => { + // exit loop if since after end + if (since >= file.end) return true; + // read file if until after start and since before end + if (until > file.start || since < file.end) { + var thisLog = require("Storage").readJSON(file.name, 1) || []; + if (thisLog.length) filesLog = thisLog.concat(filesLog); + } + }); + // free ram + files = undefined; + + // check if log from files is available + if (filesLog.length) { + // remove unwanted entries + filesLog = filesLog.filter((entry, index, filesLog) => ( + (filesLog[index + 1] || [now])[0] >= since && entry[0] <= until + )); + // add to log as previous entries + log = filesLog.concat(log); + } + // free ram + filesLog = undefined; + } } - // output log + // define last index + var lastIndex = log.length - 1; + // set timestamp of first entry to since if first entry before since + if (log[0] && log[0][0] < since) log[0][0] = since; + // add timestamp at now with unknown status if until after now + if (until > now) log.push([now, 0, 0]); + return log; }, - // define write log function, append or replace log depending on input - // append input if array length >1 and element[0] >9E11 - // replace log with input if at least one entry like above is inside another array - writeLog: function(logfile, input) { - // check/set logfile - if (typeof logfile !== "string" || !logfile.endsWith(".log")) { - if (!global.sleeplog || sleeplog.logfile === false) return; - logfile = sleeplog.logfile || "sleeplog.log"; + // define move log function, move StorageFile content into files seperated by fortnights + moveLog: function(force) { + /** convert old logfile (< v0.10) if present **/ + if (require("Storage").list("sleeplog.log", { + sf: false + }).length) { + convertOldLog(); } + /** may be removed in later versions **/ - // check if input is an array - if (typeof input !== "object" || typeof input.length !== "number") return; + // first day of this fortnight period + var thisFirstDay = this.fnToMs(this.msToFn(Date.now())); - // check for entry plausibility - if (input.length > 1 && input[0] * 1 > 9E11) { - // read log - var log = this.readLog(logfile); + // read timestamp of the first StorageFile entry + var firstDay = (require("Storage").open("sleeplog.log", "r").read(47) || "").match(/\n\d*/); + // calculate the first day of the fortnight period + if (firstDay) firstDay = this.fnToMs(this.msToFn(parseInt(firstDay[0].trim()) * 6E5)); - // remove last state if it was unknown and less then 5min ago - if (log.length > 0 && log[0][1] === 0 && - Math.floor(Date.now()) - log[0][0] < 3E5) log.shift(); + // check if moving is neccessary or forced + if (force || firstDay && firstDay < thisFirstDay) { + // read log for each fortnight period + while (firstDay) { + // calculate last day + var lastDay = firstDay + 12096E5; + // read log of the fortnight period + var log = require("sleeplog").readLog(firstDay, lastDay); - // add entry at the first position if it has changed - if (log.length === 0 || input.some((e, index) => index > 0 && input[index] !== log[0][index])) log.unshift(input); + // check if before this fortnight period + if (firstDay < thisFirstDay) { + // write log in seperate file + require("Storage").writeJSON("sleeplog_" + this.msToFn(firstDay) + ".log", log); + // set last day as first + firstDay = lastDay; + } else { + // rewrite StorageFile + require("Storage").open("sleeplog.log", "w").write(log.map(e => e.join(",")).join("\n")); + // clear first day to exit loop + firstDay = undefined; + } - // map log as input - input = log; - } - - // check and if neccessary reduce logsize to prevent low mem - if (input.length > 750) input = input.slice(-750); - - // simple check for log plausibility - if (input[0].length > 1 && input[0][0] * 1 > 9E11) { - // write log to storage - require("Storage").write(logfile, btoa(JSON.stringify(input))); - return true; - } - }, - - // define log to humanreadable string function - // sorting: latest last, format: - // "{substring of ISO date} - {status} for {duration}min\n..." - getReadableLog: function(printLog, since, until, logfile) { - // read log and check - var log = this.readLog(logfile, since, until); - if (!log.length) return; - // reverse array to set last timestamp to the end - log.reverse(); - - // define status description and log string - var statusText = ["unknown ", "not worn", "awake ", "sleeping"]; - var logString = []; - - // rewrite each entry - log.forEach((element, index) => { - logString[index] = "" + - Date(element[0] - Date().getTimezoneOffset() * 6E4).toISOString().substr(0, 19).replace("T", " ") + " - " + - statusText[element[1]] + - (index === log.length - 1 ? - element.length < 3 ? "" : " ".repeat(12) : - " for " + ("" + Math.round((log[index + 1][0] - element[0]) / 60000)).padStart(4) + "min" - ) + - (element[2] ? " | Temp: " + ("" + element[2]).padEnd(5) + "°C" : "") + - (element[3] ? " | " + element[3] : ""); - }); - logString = logString.join("\n"); - - // if set print and return string - if (printLog) { - print(logString); - print("- first", Date(log[0][0])); - print("- last", Date(log[log.length - 1][0])); - var period = log[log.length - 1][0] - log[0][0]; - print("- period= " + Math.floor(period / 864E5) + "d " + Math.floor(period % 864E5 / 36E5) + "h " + Math.floor(period % 36E5 / 6E4) + "min"); - } - return logString; - }, - - // define function to eliminate some errors inside the log - restoreLog: function(logfile) { - // read log and check - var log = this.readLog(logfile); - if (!log.length) return; - - // define output variable to show number of changes - var output = log.length; - - // remove non decremental entries - log = log.filter((element, index) => log[index][0] >= (log[index + 1] || [0])[0]); - - // write log - this.writeLog(logfile, log); - - // return difference in length - return output - log.length; - }, - - // define function to reinterpret worn status based on given temperature threshold - reinterpretTemp: function(logfile, tempthresh) { - // read log and check - var log = this.readLog(logfile); - if (!log.length) return; - - // set default tempthresh - tempthresh = tempthresh || (global.sleeplog ? sleeplog.tempthresh : 27); - - // define output variable to show number of changes - var output = 0; - - // remove non decremental entries - log = log.map(element => { - if (element[2]) { - var tmp = element[1]; - element[1] = element[2] > tempthresh ? 3 : 1; - if (tmp !== element[1]) output++; + // free ram + log = undefined; } - return element; + } + }, + + // define function to return stats from the last date [ms] for a specific duration [ms] or for the complete log + getStats: function(until, duration, log) { + // define stats variable + var stats = { + calculatedAt: // [date] timestamp of the calculation + Math.round(Date.now()), + deepSleep: 0, // [min] deep sleep duration + lightSleep: 0, // [min] light sleep duration + awakeSleep: 0, // [min] awake duration inside consecutive sleep + consecSleep: 0, // [min] consecutive sleep duration + awakeTime: 0, // [min] awake duration outside consecutive sleep + notWornTime: 0, // [min] duration of not worn status + unknownTime: 0, // [min] duration of unknown status + logDuration: 0, // [min] duration of all entries taken into account + firstDate: undefined, // [date] first entry taken into account + lastDate: undefined // [date] last entry taken into account + }; + + // set default inputs + until = until || stats.calculatedAt; + if (!duration) duration = 864E5; + + // read log for the specified duration or complete log if not handed over + if (!log) log = this.readLog(duration ? until - duration : 0, until); + + // check if log not empty or corrupted + if (log && log.length && log[0] && log[0].length === 3) { + // calculate and set first log date from 10min steps + stats.firstDate = log[0][0] * 6E5; + stats.lastDate = log[log.length - 1][0] * 6E5; + + // cycle through log to calculate sums til end or duration is exceeded + log.forEach((entry, index, log) => { + // calculate duration of this entry from 10min steps to minutes + var duration = ((log[index + 1] || [until / 6E5 | 0])[0] - entry[0]) * 10; + + // check if duration greater 0 + if (duration) { + // calculate sums + if (entry[1] === 4) stats.deepSleep += duration; + else if (entry[1] === 3) stats.lightSleep += duration; + else if (entry[1] === 2) { + if (entry[2] === 2) stats.awakeSleep += duration; + else if (entry[2] === 1) stats.awakeTime += duration; + } + if (entry[2] === 2) stats.consecSleep += duration; + if (entry[1] === 1) stats.notWornTime += duration; + if (entry[1] === 0) stats.unknownTime += duration; + stats.logDuration += duration; + } + }); + } + + // free ram + log = undefined; + + // return stats of the last day + return stats; + }, + + // define function to return last break time of day from date or now (default: 12 o'clock) + getLastBreak: function(date, ToD) { + // set default date or correct date type if needed + if (!date || !date.getDay) date = date ? new Date(date) : new Date(); + // set default ToD as set in sleeplog.conf or settings if available + if (ToD === undefined) ToD = (global.sleeplog && sleeplog.conf ? sleeplog.conf.breakToD : + (require("Storage").readJSON("sleeplog.json", true) || {}).breakToD) || 12; + // calculate last break time and return + return new Date(date.getFullYear(), date.getMonth(), date.getDate(), ToD); + }, + + // define functions to convert ms to the number of fortnights since the first Sunday at noon: 1970-01-04T12:00 + fnToMs: function(no) { + return (no + 0.25) * 12096E5; + }, + msToFn: function(ms) { + return (ms / 12096E5 - 0.25) | 0; + }, + + // define set debug function, options: + // enable as boolean, start/stop debugging + // duration in hours, generate csv log if set, max: 96h + setDebug: function(enable, duration) { + // check if global variable accessable + if (!global.sleeplog) return new Error("sleeplog: Can't set debugging, global object missing!"); + + // check if nothing has to be changed + if (!duration && + (enable && sleeplog.debug === true) || + (!enable && !sleeplog.debug)) return; + + // check if en- or disable debugging + if (enable) { + // define debug object + sleeplog.debug = {}; + + // check if a file should be generated + if (typeof duration === "number") { + // check duration boundaries, 0 => 8 + duration = duration > 96 ? 96 : duration || 12; + // calculate and set writeUntil in 10min steps + sleeplog.debug.writeUntil = ((Date.now() / 6E5 | 0) + duration * 6) * 6E5; + // set fileid to "{hours since 1970}" + sleeplog.debug.fileid = Date.now() / 36E5 | 0; + // write csv header on empty file + var file = require("Storage").open("sleeplog_" + sleeplog.debug.fileid + ".csv", "a"); + if (!file.getLength()) file.write( + "timestamp,movement,status,consecutive,asleepSince,awakeSince,bpm,bpmConfidence\n" + ); + // free ram + file = undefined; + } else { + // set debug as active + sleeplog.debug = true; + } + } else { + // disable debugging + delete sleeplog.debug; + } + + // save status forced + sleeplog.saveStatus(true); + }, + + // define debugging function, called after logging if debug is set + debug: function(data) { + // check if global variable accessable and debug active + if (!global.sleeplog || !sleeplog.debug) return; + + // set functions to convert timestamps + function localTime(timestamp) { + return timestamp ? Date(timestamp).toString().split(" ")[4].substr(0, 5) : "- - -"; + } + function officeTime(timestamp) { + // days since 30.12.1899 + return timestamp / 864E5 + 25569; + } + + // generate console output + var console = "sleeplog: " + + localTime(data.timestamp) + " > " + + "movement: " + ("" + data.movement).padStart(4) + ", " + + "unknown ,non consec.,consecutive".split(",")[sleeplog.consecutive] + " " + + "unknown,not worn,awake,light sleep,deep sleep".split(",")[data.status].padEnd(12) + ", " + + "asleep since: " + localTime(sleeplog.info.asleepSince) + ", " + + "awake since: " + localTime(sleeplog.info.awakeSince); + // add bpm if set + if (data.bpm) console += ", " + + "bpm: " + ("" + data.bpm).padStart(3) + ", " + + "confidence: " + data.bpmConfidence; + // output to console + print(console); + + // check if debug is set as object with a file id and it is not past writeUntil + if (typeof sleeplog.debug === "object" && sleeplog.debug.fileid && + Date.now() < sleeplog.debug.writeUntil) { + // generate next csv line + var csv = [ + officeTime(data.timestamp), + data.movement, + data.status, + sleeplog.consecutive, + sleeplog.info.asleepSince ? officeTime(sleeplog.info.asleepSince) : "", + sleeplog.info.awakeSince ? officeTime(sleeplog.info.awakeSince) : "", + data.bpm || "", + data.bpmConfidence || "" + ].join(","); + // write next line to log if set + require("Storage").open("sleeplog_" + sleeplog.debug.fileid + ".csv", "a").write(csv + "\n"); + } else { + // clear file setting in debug + sleeplog.debug = true; + } + + }, + + // print log as humanreadable output similar to debug output + printLog: function(since, until) { + // set default until + until = until || Date.now(); + // print each entry inside log + this.readLog(since, until).forEach((entry, index, log) => { + // calculate duration of this entry from 10min steps to minutes + var duration = ((log[index + 1] || [until / 6E5 | 0])[0] - entry[0]) * 10; + // print this entry + print((index + ")").padStart(4) + " " + + Date(entry[0] * 6E5).toString().substr(0, 21) + " > " + + "unknown ,non consec.,consecutive".split(",")[entry[2]] + " " + + "unknown,not worn,awake,light sleep,deep sleep".split(",")[entry[1]].padEnd(12) + + "for" + (duration + "min").padStart(8)); }); + }, - // write log - this.writeLog(logfile, log); + /** convert old (< v0.10) to new logfile data **/ + convertOldLog: function() { + // read old logfile + var oldLog = require("Storage").read("sleeplog.log") || ""; + // decode data if needed + if (!oldLog.startsWith("[")) oldLog = atob(oldLog); + // delete old logfile and return if it is empty or corrupted + if (!oldLog.startsWith("[[") || !oldLog.endsWith("]]")) { + require("Storage").erase("sleeplog.log"); + return; + } - // return output - return output; + // transform into StorageFile and clear oldLog to have more free ram accessable + require("Storage").open("sleeplog_old.log", "w").write(JSON.parse(oldLog).reverse().join("\n")); + oldLog = undefined; + + // calculate fortnight from now + var fnOfNow = this.msToFn(Date.now()); + + // open StorageFile with old log data + var file = require("Storage").open("sleeplog_old.log", "r"); + // define active fortnight and file cache + var activeFn = true; + var fileCache = []; + // loop through StorageFile entries + while (activeFn) { + // define fortnight for this entry + var thisFn = false; + // cache new line + var line = file.readLine(); + // check if line is filled + if (line) { + // parse line + line = line.substr(0, 15).split(",").map(e => parseInt(e)); + // calculate fortnight for this entry + thisFn = this.msToFn(line[0]); + // convert timestamp into 10min steps + line[0] = line[0] / 6E5 | 0; + // set consecutive to unknown + line.push(0); + } + // check if active fortnight and file cache is set, fortnight has changed and + // active fortnight is not fortnight from now + if (activeFn && fileCache.length && activeFn !== thisFn && activeFn !== fnOfNow) { + // write file cache into new file according to fortnight + require("Storage").writeJSON("sleeplog_" + activeFn + ".log", fileCache); + // clear file cache + fileCache = []; + } + // add line to file cache if it is filled + if (line) fileCache.push(line); + // set active fortnight + activeFn = thisFn; + } + // check if entries are leftover + if (fileCache.length) { + // format fileCache entries into a string + fileCache = fileCache.map(e => e.join(",")).join("\n"); + // read complete new log StorageFile as string + file = require("Storage").open("sleeplog.log", "r"); + var newLogString = file.read(file.getLength()); + // add entries at the beginning of the new log string + newLogString = fileCache + "\n" + newLogString; + // rewrite new log StorageFile + require("Storage").open("sleeplog.log", "w").write(newLogString); + } + + // free ram + file = undefined; + fileCache = undefined; + + // clean up old files + require("Storage").erase("sleeplog.log"); + require("Storage").open("sleeplog_old.log", "w").erase(); } - + /** may be removed in later versions **/ }; diff --git a/apps/sleeplog/metadata.json b/apps/sleeplog/metadata.json index c4dbe8631..f6ce661e8 100644 --- a/apps/sleeplog/metadata.json +++ b/apps/sleeplog/metadata.json @@ -2,27 +2,32 @@ "id":"sleeplog", "name":"Sleep Log", "shortName": "SleepLog", - "version": "0.06", - "description": "Log and view your sleeping habits. This app derived from SleepPhaseAlarm and uses also the principe of Estimation of Stationary Sleep-segments (ESS). It also provides a power saving mode using the built in movement calculation.", + "version": "0.11", + "description": "Log and view your sleeping habits. This app is using the built in movement calculation.", "icon": "app.png", "type": "app", "tags": "tool,boot", "supports": ["BANGLEJS2"], "readme": "README.md", + "interface": "interface.html", "storage": [ {"name": "sleeplog.app.js", "url": "app.js"}, - {"name": "sleeplog.img", "url": "app-icon.js", "evaluate":true}, + {"name": "sleeplog.img", "url": "app-icon.js", "evaluate": true}, {"name": "sleeplog.boot.js", "url": "boot.js"}, {"name": "sleeplog", "url": "lib.js"}, {"name": "sleeplog.settings.js", "url": "settings.js"} ], "data": [ - {"name": "sleeplog.json"}, - {"name": "sleeplog.log"} + {"name": "sleeplog.json"} ], "screenshots": [ - {"url": "screenshot1.png"}, - {"url": "screenshot2.png"}, - {"url": "screenshot3.png"} - ] + {"url": "screenshot-1_app_light.png"}, + {"url": "screenshot-2_day_light.png"}, + {"url": "screenshot-3_graph_light.png"}, + {"url": "screenshot-4_graph2_light.png"}, + {"url": "screenshot-5_app_dark.png"}, + {"url": "screenshot-6_day_dark.png"}, + {"url": "screenshot-7_graph_dark.png"}, + {"url": "screenshot-8_graph2_dark.png"} + ] } diff --git a/apps/sleeplog/nolog.png b/apps/sleeplog/nolog.png deleted file mode 100644 index b153b5769..000000000 Binary files a/apps/sleeplog/nolog.png and /dev/null differ diff --git a/apps/sleeplog/off_20x20.png b/apps/sleeplog/off_20x20.png new file mode 100644 index 000000000..abf3d3bfc Binary files /dev/null and b/apps/sleeplog/off_20x20.png differ diff --git a/apps/sleeplog/powersaving.png b/apps/sleeplog/powersaving.png deleted file mode 100644 index ea487b48c..000000000 Binary files a/apps/sleeplog/powersaving.png and /dev/null differ diff --git a/apps/sleeplog/screenshot-1_app_light.png b/apps/sleeplog/screenshot-1_app_light.png new file mode 100644 index 000000000..f4c01773c Binary files /dev/null and b/apps/sleeplog/screenshot-1_app_light.png differ diff --git a/apps/sleeplog/screenshot-2_day_light.png b/apps/sleeplog/screenshot-2_day_light.png new file mode 100644 index 000000000..61e0a60f6 Binary files /dev/null and b/apps/sleeplog/screenshot-2_day_light.png differ diff --git a/apps/sleeplog/screenshot-3_graph_light.png b/apps/sleeplog/screenshot-3_graph_light.png new file mode 100644 index 000000000..4b74afd25 Binary files /dev/null and b/apps/sleeplog/screenshot-3_graph_light.png differ diff --git a/apps/sleeplog/screenshot-4_graph2_light.png b/apps/sleeplog/screenshot-4_graph2_light.png new file mode 100644 index 000000000..300be5d05 Binary files /dev/null and b/apps/sleeplog/screenshot-4_graph2_light.png differ diff --git a/apps/sleeplog/screenshot-5_app_dark.png b/apps/sleeplog/screenshot-5_app_dark.png new file mode 100644 index 000000000..82e1f8c2f Binary files /dev/null and b/apps/sleeplog/screenshot-5_app_dark.png differ diff --git a/apps/sleeplog/screenshot-6_day_dark.png b/apps/sleeplog/screenshot-6_day_dark.png new file mode 100644 index 000000000..a727f73e0 Binary files /dev/null and b/apps/sleeplog/screenshot-6_day_dark.png differ diff --git a/apps/sleeplog/screenshot-7_graph_dark.png b/apps/sleeplog/screenshot-7_graph_dark.png new file mode 100644 index 000000000..71612fa8e Binary files /dev/null and b/apps/sleeplog/screenshot-7_graph_dark.png differ diff --git a/apps/sleeplog/screenshot-8_graph2_dark.png b/apps/sleeplog/screenshot-8_graph2_dark.png new file mode 100644 index 000000000..09c19e95c Binary files /dev/null and b/apps/sleeplog/screenshot-8_graph2_dark.png differ diff --git a/apps/sleeplog/screenshot1.png b/apps/sleeplog/screenshot1.png deleted file mode 100644 index 200a305c4..000000000 Binary files a/apps/sleeplog/screenshot1.png and /dev/null differ diff --git a/apps/sleeplog/screenshot2.png b/apps/sleeplog/screenshot2.png deleted file mode 100644 index 61f580336..000000000 Binary files a/apps/sleeplog/screenshot2.png and /dev/null differ diff --git a/apps/sleeplog/screenshot3.png b/apps/sleeplog/screenshot3.png deleted file mode 100644 index 4a29b5008..000000000 Binary files a/apps/sleeplog/screenshot3.png and /dev/null differ diff --git a/apps/sleeplog/settings.js b/apps/sleeplog/settings.js index 11c7c0adb..9bf37ed69 100644 --- a/apps/sleeplog/settings.js +++ b/apps/sleeplog/settings.js @@ -1,144 +1,431 @@ (function(back) { + // define settings filename var filename = "sleeplog.json"; + // define logging prompt display status + var thresholdsPrompt = true; - // set storage and load settings - var storage = require("Storage"); - var settings = Object.assign({ - breaktod: 10, // time of day when to start/end graphs - maxawake: 36E5, // 60min in ms - minconsec: 18E5, // 30min in ms - tempthresh: 27, // every temperature above ist registered as worn - powersaving: false, // disables ESS and uses build in movement detection - maxmove: 100, // movement threshold on power saving mode - nomothresh: 0.012, // values lower than 0.008 getting triggert by noise - sleepthresh: 577, // 577 times no movement * 1.04s window width > 10min - winwidth: 13, // 13 values, read with 12.5Hz = every 1.04s - enabled: true, // en-/disable completely - logfile: "sleeplog.log", // logfile - }, storage.readJSON(filename, true) || {}); + // define default vaules + var defaults = { + // main settings + enabled: true, // en-/disable completely + // threshold settings + maxAwake: 36E5, // [ms] maximal awake time to count for consecutive sleep + minConsec: 18E5, // [ms] minimal time to count for consecutive sleep + deepTh: 100, // threshold for deep sleep + lightTh: 200, // threshold for light sleep + // app settings + breakToD: 12, // [h] time of day when to start/end graphs + appTimeout: 0 // lock and backlight timeouts for the app + }; - // write change to global.sleeplog and storage - function writeSetting(key, value) { - // change key in global.sleeplog - if (typeof global.sleeplog === "object") global.sleeplog[key] = value; - // reread settings to only change key - settings = Object.assign(settings, storage.readJSON(filename, true) || {}); - // change the value of key - settings[key] = value; - // write to storage - storage.writeJSON(filename, settings); + // assign loaded settings to default values + var settings = Object.assign(defaults, require("Storage").readJSON(filename, true) || {}); + + // write change to storage + function writeSetting() { + require("Storage").writeJSON(filename, settings); } - // define function to change values that need a restart of the service - function changeRestart() { - require("sleeplog").setEnabled(settings.enabled, settings.logfile, settings.powersaving); + // plot a debug file + function plotDebug(filename) { + // handle swipe events + function swipeHandler(x, y) { + if (x) { + start -= x; + if (start < 0 || maxStart && start > maxStart) { + start = start < 0 ? 0 : maxStart; + } else { + drawGraph(); + } + } else { + minMove += y * 10; + if (minMove < 0 || minMove > 300) { + minMove = minMove < 0 ? 0 : 300; + } else { + drawGraph(); + } + } + } + // handle touch events + function touchHandler() { + invert = !invert; + drawGraph(); + } + + // read required entries + function readEntries(count) { + // extract usabble data from line + function extract(line) { + if (!line) return; + line = line.trim().split(","); + return [Math.round((parseFloat(line[0]) - 25569) * 144), parseInt(line[1])]; + } + + // open debug file + var file = require("Storage").open(filename, "r"); + // skip title + file.readLine(); + // skip past entries + for (var i = 0; i < start * count; i++) { file.readLine(); } + // define data with first entry + var data = [extract(file.readLine())]; + // get start time in 10min steps + var start10min = data[0][0]; + // read first required entry + var line = extract(file.readLine()); + + // read next count entries from file + while (data.length < count) { + // check if line is immediately after the last entry + if (line[0] === start10min + data.length) { + // add line to data + data.push(line); + // read new line + line = extract(file.readLine()); + // stop if no more data available + if (!line) break; + } else { + // add line with unknown movement + data.push([start10min + data.length, 0]); + } + } + + // free ram + file = undefined + // set this start as max, if less entries than expected + if (data.length < count) maxStart = start; + return data; + } + + // draw graph at starting point + function drawGraph() { + // set correct or inverted drawing + function rect(fill, x0, y0, x1, y1) { + if (fill ^ invert) { + g.fillRect(x0, y0, x1, y1); + } else { + g.clearRect(x0, y0, x1, y1); + } + } + + // set witdh + var width = g.getWidth(); + // calculate entries to display (+ set width zero based) + var count = (width--) / 4; + // read required entries + var data = readEntries(count); + + // clear app area + g.reset().clearRect(0, width - 13, width, width); + rect(false, 0, 24, width, width - 14); + // draw x axis + g.drawLine(0, width - 13, width, width - 13); + // draw x label + data.forEach((e, i) => { + var startTime = new Date(e[0] * 6E5); + if (startTime.getMinutes() === 0) { + g.fillRect(4 * i, width - 12, 4 * i, width - 9); + g.setFontAlign(-1, -1).setFont("6x8") + .drawString(startTime.getHours(), 4 * i + 1, width - 8); + } else if (startTime.getMinutes() === 30) { + g.fillRect(4 * i, width - 12, 4 * i, width - 11); + } + }); + + // calculate max height + var height = width - 38; + // cycle through entries + data.forEach((e, i) => { + // check if movement available + if (e[1]) { + // set color depending on recognised status + var color = e[1] < deepTh ? 31 : e[1] < lightTh ? 2047 : 2016; + // correct according to min movement + e[1] -= minMove; + // keep movement in bounderies + e[1] = e[1] < 0 ? 0 : e[1] > height ? height : e[1]; + // draw line and rectangle + g.reset(); + rect(true, 4 * i, width - 14, 4 * i, width - 14 - e[1]); + g.setColor(color).fillRect(4 * i + 1, width - 14, 4 * i + 3, width - 14 - e[1]); + } else { + // draw error in red + g.setColor(63488).fillRect(4 * i, width - 14, 4 * i, width - 14 - height); + } + }); + // draw threshold lines + [deepTh, lightTh].forEach(th => { + th -= minMove; + if (th > 0 && th < height) { + // draw line + g.reset(); + rect(true, 0, width - 14 - th, width, width - 14 - th); + // draw value above or below line + var yAlign = th < height / 2 ? -1 : 1; + if (invert) g.setColor(1); + g.setFontAlign(1, yAlign).setFont("6x8") + .drawString(th + minMove, width - 2, width - 13 - th + 10 * yAlign); + } + }); + + // free ram + data = undefined; + } + + // get thresholds + var deepTh = global.sleeplog ? sleeplog.conf.deepTh : defaults.deepTh; + var lightTh = global.sleeplog ? sleeplog.conf.lightTh : defaults.lightTh; + // set lowest movement displayed + var minMove = deepTh - 20; + // set start point + var start = 0; + // define max start point value + var maxStart = 0; + // define inverted color status + var invert = false; + + // setup UI + Bangle.setUI({ + mode: "custom", + back: selectDebug, + touch: touchHandler, + swipe: swipeHandler + }); + + // first draw + drawGraph(start); } - // calculate sleepthresh factor - var stFactor = settings.winwidth / 12.5 / 60; + // select a debug logfile + function selectDebug() { + // load debug files + var files = require("Storage").list(/^sleeplog_\d\d\d\d\d\d\.csv$/, {sf:true}); + + // check if no files found + if (!files.length) { + // show prompt + E.showPrompt( /*LANG*/"No debug files found.", { + title: /*LANG*/"Debug log", + buttons: { + /*LANG*/"Back": 0 + } + }).then(showDebug); + } else { + // prepare scroller + const H = 40; + var menuIcon = "\0\f\f\x81\0\xFF\xFF\xFF\0\0\0\0\x0F\xFF\xFF\xF0\0\0\0\0\xFF\xFF\xFF"; + // show scroller + E.showScroller({ + h: H, c: files.length, + back: showDebug, + scrollMin : -24, scroll : -24, // title is 24px, rendered at -1 + draw : (idx, r) => { + if (idx < 0) { + return g.setFont("12x20").setFontAlign(-1,0).drawString(menuIcon + " Select file", r.x + 12, r.y + H - 12); + } else { + g.setColor(g.theme.bg2).fillRect({x: r.x + 4, y: r.y + 2, w: r.w - 8, h: r.h - 4, r: 5}); + var name = new Date(parseInt(files[idx].match(/\d\d\d\d\d\d/)[0]) * 36E5); + name = name.toString().slice(0, -12).split(" ").filter((e, i) => i !== 3).join(" "); + g.setColor(g.theme.fg2).setFont("12x20").setFontAlign(-1, 0).drawString(name, r.x + 12, r.y + H / 2); + } + }, + select: (idx) => plotDebug(files[idx]) + }); + } + } + + // show menu or promt to change debugging + function showDebug() { + // check if sleeplog is available + if (global.sleeplog) { + // get debug status, file and duration + var enabled = !!sleeplog.debug; + var file = typeof sleeplog.debug === "object"; + var duration = 0; + // setup debugging menu + var debugMenu = { + "": { + title: /*LANG*/"Debugging" + }, + /*LANG*/"< Back": () => { + // check if some value has changed + if (enabled !== !!sleeplog.debug || file !== (typeof sleeplog.debug === "object") || duration) + require("sleeplog").setDebug(enabled, file ? duration || 12 : undefined); + // redraw main menu + showMain(7); + }, + /*LANG*/"View log": () => selectDebug(), + /*LANG*/"Enable": { + value: enabled, + onchange: v => enabled = v + }, + /*LANG*/"write File": { + value: file, + onchange: v => file = v + }, + /*LANG*/"Duration": { + value: file ? (sleeplog.debug.writeUntil - Date.now()) / 36E5 | 0 : 12, + min: 1, + max: 96, + wrap: true, + format: v => v + /*LANG*/ "h", + onchange: v => duration = v + }, + /*LANG*/"Cancel": () => showMain(7), + }; + // show menu + var menu = E.showMenu(debugMenu); + } else { + // show error prompt + E.showPrompt("Sleeplog" + /*LANG*/"not enabled!", { + title: /*LANG*/"Debugging", + buttons: { + /*LANG*/"Back": 7 + } + }).then(showMain); + } + } + + // show menu to change thresholds + function showThresholds() { + // setup logging menu + var menu; + var thresholdsMenu = { + "": { + title: /*LANG*/"Thresholds" + }, + /*LANG*/"< Back": () => showMain(2), + /*LANG*/"Max Awake": { + value: settings.maxAwake / 6E4, + step: 10, + min: 10, + max: 120, + wrap: true, + noList: true, + format: v => v + /*LANG*/"min", + onchange: v => { + settings.maxAwake = v * 6E4; + writeSetting(); + } + }, + /*LANG*/"Min Consecutive": { + value: settings.minConsec / 6E4, + step: 10, + min: 10, + max: 120, + wrap: true, + noList: true, + format: v => v + /*LANG*/"min", + onchange: v => { + settings.minConsec = v * 6E4; + writeSetting(); + } + }, + /*LANG*/"Deep Sleep": { + value: settings.deepTh, + step: 1, + min: 30, + max: 200, + wrap: true, + noList: true, + onchange: v => { + settings.deepTh = v; + writeSetting(); + } + }, + /*LANG*/"Light Sleep": { + value: settings.lightTh, + step: 10, + min: 100, + max: 400, + wrap: true, + noList: true, + onchange: v => { + settings.lightTh = v; + writeSetting(); + } + }, + /*LANG*/"Reset to Default": () => { + settings.maxAwake = defaults.maxAwake; + settings.minConsec = defaults.minConsec; + settings.deepTh = defaults.deepTh; + settings.lightTh = defaults.lightTh; + writeSetting(); + showThresholds(); + } + }; + + // display info/warning prompt or menu + if (thresholdsPrompt) { + thresholdsPrompt = false; + E.showPrompt("Changes take effect from now on, not retrospective", { + title: /*LANG*/"Thresholds", + buttons: { + /*LANG*/"Ok": 0 + } + }).then(() => menu = E.showMenu(thresholdsMenu)); + } else { + menu = E.showMenu(thresholdsMenu); + } + } // show main menu function showMain(selected) { + // set debug image + var debugImg = !global.sleeplog ? + "FBSBAOAAfwAP+AH3wD4+B8Hw+A+fAH/gA/wAH4AB+AA/wAf+APnwHw+D4Hx8A++AH/AA/gAH" : // X + typeof sleeplog.debug === "object" ? + "FBSBAB/4AQDAF+4BfvAX74F+CBf+gX/oFJKBf+gUkoF/6BSSgX/oFJ6Bf+gX/oF/6BAAgf/4" : // file + sleeplog.debug ? + "FBSBAP//+f/V///4AAGAABkAAZgAGcABjgAYcAGDgBhwAY4AGcABmH+ZB/mAABgAAYAAH///" : // console + 0; // off + debugImg = debugImg ? "\0" + atob(debugImg) : false; + // set menu var mainMenu = { "": { title: "Sleep Log", selected: selected }, - "Exit": () => load(), - "< Back": () => back(), - "Break Tod": { - value: settings.breaktod, + /*LANG*/"< Back": () => back(), + /*LANG*/"Thresholds": () => showThresholds(), + /*LANG*/"Break ToD": { + value: settings.breakToD, step: 1, min: 0, max: 23, wrap: true, - onchange: v => writeSetting("breaktod", v), - }, - "Max Awake": { - value: settings.maxawake / 6E4, - step: 5, - min: 15, - max: 120, - wrap: true, - format: v => v + "min", - onchange: v => writeSetting("maxawake", v * 6E4), - }, - "Min Consec": { - value: settings.minconsec / 6E4, - step: 5, - min: 15, - max: 120, - wrap: true, - format: v => v + "min", - onchange: v => writeSetting("minconsec", v * 6E4), - }, - "Temp Thresh": { - value: settings.tempthresh, - step: 0.5, - min: 20, - max: 40, - wrap: true, - format: v => v + "°C", - onchange: v => writeSetting("tempthresh", v), - }, - "Power Saving": { - value: settings.powersaving, - format: v => v ? "on" : "off", - onchange: function(v) { - settings.powersaving = v; - changeRestart(); - // redraw menu with changed entries subsequent to onchange - // https://github.com/espruino/Espruino/issues/2149 - setTimeout(showMain, 1, 6); + noList: true, + format: v => v + ":00", + onchange: v => { + settings.breakToD = v; + writeSetting(); } }, - "Max Move": { - value: settings.maxmove, - step: 1, - min: 50, - max: 200, + /*LANG*/"App Timeout": { + value: settings.appTimeout / 1E3, + step: 10, + min: 0, + max: 120, wrap: true, - onchange: v => writeSetting("maxmove", v), + noList: true, + format: v => v ? v + "s" : "-", + onchange: v => { + settings.appTimeout = v * 1E3; + writeSetting(); + } }, - "NoMo Thresh": { - value: settings.nomothresh, - step: 0.001, - min: 0.006, - max: 0.02, - wrap: true, - format: v => ("" + v).padEnd(5, "0"), - onchange: v => writeSetting("nomothresh", v), - }, - "Min Duration": { - value: Math.floor(settings.sleepthresh * stFactor), - step: 1, - min: 5, - max: 15, - wrap: true, - format: v => v + "min", - onchange: v => writeSetting("sleepthresh", Math.ceil(v / stFactor)), - }, - "Enabled": { + /*LANG*/"Enabled": { value: settings.enabled, - format: v => v ? "on" : "off", - onchange: function(v) { + onchange: v => { settings.enabled = v; - changeRestart(); + require("sleeplog").setEnabled(v); } }, - "Logfile ": { - value: settings.logfile === "sleeplog.log" ? true : (settings.logfile || "").endsWith(".log") ? "custom" : false, - format: v => v === true ? "default" : v ? "custom" : "off", - onchange: function(v) { - if (v !== "custom") { - settings.logfile = v ? "sleeplog.log" : false; - changeRestart(); - } - } + /*LANG*/"Debugging": { + value: debugImg, + onchange: () => setTimeout(showDebug, 10) } }; - // check power saving mode to delete unused entries - (settings.powersaving ? ["NoMo Thresh", "Min Duration"] : ["Max Move"]).forEach(property => delete mainMenu[property]); var menu = E.showMenu(mainMenu); } diff --git a/apps/slidingtext/ChangeLog b/apps/slidingtext/ChangeLog index b3cf16ac7..1b45c36cb 100644 --- a/apps/slidingtext/ChangeLog +++ b/apps/slidingtext/ChangeLog @@ -7,3 +7,4 @@ 0.07: Support for Bangle.js 2 and themes 0.08: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". 0.09: Added button control toggle and other live controls to new settings screen. +0.10: Tell clock widgets to hide. diff --git a/apps/slidingtext/metadata.json b/apps/slidingtext/metadata.json index 0e36f61b8..7b5378f0e 100644 --- a/apps/slidingtext/metadata.json +++ b/apps/slidingtext/metadata.json @@ -1,7 +1,7 @@ { "id": "slidingtext", "name": "Sliding Clock", - "version": "0.09", + "version": "0.10", "description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported", "icon": "slidingtext.png", "type": "clock", diff --git a/apps/slidingtext/slidingtext.js b/apps/slidingtext/slidingtext.js index ddba13c08..b53372fdd 100644 --- a/apps/slidingtext/slidingtext.js +++ b/apps/slidingtext/slidingtext.js @@ -890,11 +890,12 @@ Bangle.on('lcdPower', (on) => { g.clear(); load_settings(); -Bangle.loadWidgets(); -Bangle.drawWidgets(); - -startTimers(); // Show launcher when button pressed Bangle.setUI("clockupdown", d=>{ if (d>0) button3pressed(); }); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +startTimers(); + diff --git a/apps/smpltmr/ChangeLog b/apps/smpltmr/ChangeLog index bf128e2fb..572aaa91e 100644 --- a/apps/smpltmr/ChangeLog +++ b/apps/smpltmr/ChangeLog @@ -1,2 +1,3 @@ 0.01: Release -0.02: Rewrite with new interface \ No newline at end of file +0.02: Rewrite with new interface +0.03: Added clock infos to expose timer functionality to clocks. \ No newline at end of file diff --git a/apps/smpltmr/clkinfo.js b/apps/smpltmr/clkinfo.js new file mode 100644 index 000000000..dfc70aab9 --- /dev/null +++ b/apps/smpltmr/clkinfo.js @@ -0,0 +1,97 @@ +(function() { + const TIMER_IDX = "smpltmr"; + + function isAlarmEnabled(){ + try{ + var alarm = require('sched'); + var alarmObj = alarm.getAlarm(TIMER_IDX); + if(alarmObj===undefined || !alarmObj.on){ + return false; + } + + return true; + + } catch(ex){ } + return false; + } + + function getAlarmMinutes(){ + if(!isAlarmEnabled()){ + return -1; + } + + var alarm = require('sched'); + var alarmObj = alarm.getAlarm(TIMER_IDX); + return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000)); + } + + function getAlarmMinutesText(){ + var min = getAlarmMinutes(); + if(min < 0){ + return "OFF"; + } + + return "T-" + String(min); + } + + function increaseAlarm(t){ + try{ + var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0; + var alarm = require('sched') + alarm.setAlarm(TIMER_IDX, { + timer : (minutes+t)*60*1000, + }); + alarm.reload(); + } catch(ex){ } + } + + function decreaseAlarm(t){ + try{ + var minutes = getAlarmMinutes(); + minutes -= t; + + var alarm = require('sched') + alarm.setAlarm(TIMER_IDX, undefined); + + if(minutes > 0){ + alarm.setAlarm(TIMER_IDX, { + timer : minutes*60*1000, + }); + } + + alarm.reload(); + } catch(ex){ } + } + + var img = atob("GBiBAeAAB+AAB/v/3/v/3/v/3/v/3/v/n/n/H/z+P/48//85//+b//+b//8p//4E//yCP/kBH/oAn/oAX/oAX/oAX/oAX+AAB+AABw==") + var smpltmrItems = { + name: "Timer", + img: img, + items: [ + { + name: "Timer", + get: () => ({ text: getAlarmMinutesText() + (isAlarmEnabled() ? " min" : ""), img: null}), + show: function() { smpltmrItems.items[0].emit("redraw"); }, + hide: function () {}, + run: function() { } + }, + ] + }; + + var offsets = [+1,+5,-1,-5]; + offsets.forEach((o, i) => { + smpltmrItems.items = smpltmrItems.items.concat({ + name: String(o), + get: () => ({ text: getAlarmMinutesText() + " (" + (o > 0 ? "+" : "") + o + ")", img: null}), + show: function() { smpltmrItems.items[i+1].emit("redraw"); }, + hide: function () {}, + run: function() { + if(o > 0) increaseAlarm(o); + else decreaseAlarm(Math.abs(o)); + this.show(); + } + }); + }); + + return smpltmrItems; +}) \ No newline at end of file diff --git a/apps/smpltmr/metadata.json b/apps/smpltmr/metadata.json index cb1ef6eab..4a219fad2 100644 --- a/apps/smpltmr/metadata.json +++ b/apps/smpltmr/metadata.json @@ -2,7 +2,7 @@ "id": "smpltmr", "name": "Simple Timer", "shortName": "Simple Timer", - "version": "0.02", + "version": "0.03", "description": "A very simple app to start a timer.", "icon": "app.png", "tags": "tool,alarm,timer", @@ -12,6 +12,7 @@ "readme": "README.md", "storage": [ {"name":"smpltmr.app.js","url":"app.js"}, + {"name":"smpltmr.clkinfo.js","url":"clkinfo.js"}, {"name":"smpltmr.img","url":"app-icon.js","evaluate":true} ] } diff --git a/apps/stardateclock/ChangeLog b/apps/stardateclock/ChangeLog index 1b1719352..bb6430b65 100644 --- a/apps/stardateclock/ChangeLog +++ b/apps/stardateclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: Initial release on the app repository for Bangle.js 1 and 2 0.02: Fixed let/const usage while using firmware version >=2v14 +0.03: Tell clock widgets to hide. diff --git a/apps/stardateclock/app.js b/apps/stardateclock/app.js index cdc730970..adf2c14c7 100644 --- a/apps/stardateclock/app.js +++ b/apps/stardateclock/app.js @@ -334,10 +334,10 @@ updateStardate(); updateConventionalTime(); // Make sure widgets can be shown. //g.setColor("#FF0000"); g.fillRect(0, 0, g.getWidth(), widgetsHeight); // debug -Bangle.loadWidgets(); -Bangle.drawWidgets(); // Show launcher on button press as usual for a clock face Bangle.setUI("clock", Bangle.showLauncher); +Bangle.loadWidgets(); +Bangle.drawWidgets(); // Stop updates when LCD is off, restart when on Bangle.on('lcdPower', on => { if (on) { diff --git a/apps/stardateclock/metadata.json b/apps/stardateclock/metadata.json index 9569d3a53..d27b14512 100644 --- a/apps/stardateclock/metadata.json +++ b/apps/stardateclock/metadata.json @@ -3,7 +3,7 @@ "name":"Stardate Clock", "shortName":"Stardate Clock", "description": "A clock displaying a stardate along with a 'standard' digital/analog clock in LCARS design", - "version":"0.02", + "version":"0.03", "icon": "app.png", "type":"clock", "tags": "clock", diff --git a/apps/swscroll/ChangeLog b/apps/swscroll/ChangeLog new file mode 100644 index 000000000..c650baf72 --- /dev/null +++ b/apps/swscroll/ChangeLog @@ -0,0 +1 @@ +0.01: Inital release. diff --git a/apps/swscroll/README.md b/apps/swscroll/README.md new file mode 100644 index 000000000..f97d59b71 --- /dev/null +++ b/apps/swscroll/README.md @@ -0,0 +1,9 @@ +This first release seems servicable in testing so far. + +To get the standard menu scrolling back, just remove this app from your Bangle. + +TODO: +- Maybe have how much of "trailing space" there are after the last entry should be dynamic in size, now it's always 8 pixels which corresponds to if there are a widget field and a menu title present. +- I want to change the size of menu entries to be a little bigger vertically. + +Drag List Down icon by Icons8 diff --git a/apps/swscroll/app.png b/apps/swscroll/app.png new file mode 100644 index 000000000..7abd582c2 Binary files /dev/null and b/apps/swscroll/app.png differ diff --git a/apps/swscroll/boot.js b/apps/swscroll/boot.js new file mode 100644 index 000000000..fc5650cad --- /dev/null +++ b/apps/swscroll/boot.js @@ -0,0 +1,100 @@ +E.showScroller = (function(options) { + /* options = { + h = height + c = # of items + scroll = initial scroll position + scrollMin = minimum scroll amount (can be negative) + draw = function(idx, rect) + select = function(idx) + } + + returns { + draw = draw all + drawItem(idx) = draw specific item + } + */ +if (!options) return Bangle.setUI(); // remove existing handlers + +var menuShowing = false; +var R = Bangle.appRect; +var Y = Bangle.appRect.y; +var n = Math.ceil(R.h/options.h); +var menuScrollMin = 0|options.scrollMin; +var menuScrollMax = options.h*options.c - R.h; +if (menuScrollMax { + g.reset().clearRect(R.x,R.y,R.x2,R.y2); + g.setClipRect(R.x,R.y,R.x2,R.y2); + var a = YtoIdx(R.y); + var b = Math.min(YtoIdx(R.y2),options.c-1); + for (var i=a;i<=b;i++) + options.draw(i, {x:R.x,y:idxToY(i),w:R.w,h:options.h}); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); +}, drawItem : i => { + var y = idxToY(i); + g.reset().setClipRect(R.x,y,R.x2,y+options.h); + options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); +}}; +var rScroll = s.scroll&~1; // rendered menu scroll (we only shift by 2 because of dither) +s.draw(); // draw the full scroller +g.flip(); // force an update now to make this snappier +Bangle.setUI({ + mode : "custom", + back : options.back, + swipe : (hor,ver)=>{ + pixels = 120; + var dy = ver*pixels; + if (s.scroll - dy > menuScrollMax) + dy = s.scroll - menuScrollMax-8; // Makes it so the last 'page' has the same position as previous pages. This should be done dynamically (change the static 8 to be a variable) so the offset is correct even when no widget field or title field is present. + if (s.scroll - dy < menuScrollMin) + dy = s.scroll - menuScrollMin; + s.scroll -= dy; + var oldScroll = rScroll; + rScroll = s.scroll &~1; + dy = oldScroll-rScroll; + if (!dy || options.c<=3) return; //options.c<=3 should maybe be dynamic, so 3 would be replaced by a variable dependent on R=Bangle.appRect. It's here so we don't try to scroll if all entries fit in the app rectangle. + g.reset().setClipRect(R.x,R.y,R.x2,R.y2); + g.scroll(0,dy); + var d = ver*pixels; + if (d < 0) { + g.setClipRect(R.x,R.y2-(1-d),R.x2,R.y2); + let i = YtoIdx(R.y2-(1-d)); + let y = idxToY(i); + //print(i, options.c, options.c-i); //debugging info + while (y < R.y2 - (options.h*((options.c-i)<=0)) ) { //- (options.h*((options.c-i)<=0)) makes sure we don't go beyond the menu entries in the menu object "options". This has to do with "dy = s.scroll - menuScrollMax-8" above. + options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); + i++; + y += options.h; + } + } else { // d>0 + g.setClipRect(R.x,R.y,R.x2,R.y+d); + let i = YtoIdx(R.y+d); + let y = idxToY(i); + //print(i, options.c, options.c-i); //debugging info + while (y > R.y-options.h) { + options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); + y -= options.h; + i--; + } + } + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); + }, touch : (_,e)=>{ + if (e.y=0) && i{if (p) onTemperature(p)}); + Bangle.getPressure().then(p =>{if (p) onTemperature(p);}); } else { onTemperature({ temperature : E.getTemperature() @@ -36,6 +36,9 @@ setInterval(function() { drawTemperature(); }, 5000); Bangle.loadWidgets(); -Bangle.drawWidgets(); +Bangle.setUI({ + mode : "custom", + back : function() {load();} +}); E.showMessage("Reading temperature..."); drawTemperature(); diff --git a/apps/thermom/metadata.json b/apps/thermom/metadata.json index c0cfa354d..a215df624 100644 --- a/apps/thermom/metadata.json +++ b/apps/thermom/metadata.json @@ -1,7 +1,7 @@ { "id": "thermom", "name": "Thermometer", - "version": "0.06", + "version": "0.07", "description": "Displays the current temperature in degree Celsius/Fahrenheit (depending on locale), updates every 10 seconds with average of last 5 readings.", "icon": "app.png", "tags": "tool", diff --git a/apps/tinyVario/ChangeLog b/apps/tinyVario/ChangeLog index 4d6cfb0cd..a201ee465 100644 --- a/apps/tinyVario/ChangeLog +++ b/apps/tinyVario/ChangeLog @@ -2,3 +2,4 @@ 0.02: Touch data fields to configure them. 0.03: Changed menu layout, fixed automatic flight time detection. 0.04: flight time detection should work without GPS now. New vario display available. +0.05: some bugs fiexed, no new features. diff --git a/apps/tinyVario/app.js b/apps/tinyVario/app.js index 765bfe2c4..b9a87c821 100644 --- a/apps/tinyVario/app.js +++ b/apps/tinyVario/app.js @@ -266,6 +266,7 @@ function initAltMenu() { }}, {type:"btn", font:"16%", pad:1, fillx:1, label:"SAVE", cb: ()=>{ require('Storage').writeJSON("tinyVario.json", settings); + Bangle.setOptions({seaLevelPressure:qnh}); initPFD(); }} ]} diff --git a/apps/tinyVario/metadata.json b/apps/tinyVario/metadata.json index a689a0353..f038e7515 100644 --- a/apps/tinyVario/metadata.json +++ b/apps/tinyVario/metadata.json @@ -1,7 +1,7 @@ { "id": "tinyVario", "name": "Tiny Vario", "shortName" : "tinyVario", - "version":"0.04", + "version":"0.05", "icon": "app.png", "readme": "README.md", "description": "A very simple app for gliding / paragliding / hang gliding etc.", @@ -10,5 +10,6 @@ "storage": [ {"name":"tinyVario.app.js","url":"app.js"}, {"name":"tinyVario.img","url":"app-icon.js","evaluate":true} - ] + ], + "data": [{"name":"tinyVario.json"}] } diff --git a/apps/torch/ChangeLog b/apps/torch/ChangeLog index 4d8f47500..fd904b6e8 100644 --- a/apps/torch/ChangeLog +++ b/apps/torch/ChangeLog @@ -2,3 +2,4 @@ 0.02: Change start sequence to BTN1/3/1/3 to avoid accidental turning on (fix #342) 0.03: Add Color Changing Settings 0.04: Add Support For Bangle.js 2 +0.05: Default full Brightness diff --git a/apps/torch/app.js b/apps/torch/app.js index 864efb883..2af35fdb6 100644 --- a/apps/torch/app.js +++ b/apps/torch/app.js @@ -7,6 +7,7 @@ function loadSettings() { loadSettings(); +Bangle.setLCDBrightness(1); Bangle.setLCDPower(1); Bangle.setLCDTimeout(0); g.reset(); diff --git a/apps/torch/metadata.json b/apps/torch/metadata.json index 37e6f6b95..af85370ac 100644 --- a/apps/torch/metadata.json +++ b/apps/torch/metadata.json @@ -2,7 +2,7 @@ "id": "torch", "name": "Torch", "shortName": "Torch", - "version": "0.04", + "version": "0.05", "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets on Bangle.js 1. You can also set the color through the app's setting menu.", "icon": "app.png", "tags": "tool,torch", diff --git a/apps/twenties/ChangeLog b/apps/twenties/ChangeLog new file mode 100644 index 000000000..89eb9547f --- /dev/null +++ b/apps/twenties/ChangeLog @@ -0,0 +1,4 @@ +0.01: New Widget! +0.02: Fix calling null on draw +0.03: Only vibrate during work +0.04: Convert to boot code \ No newline at end of file diff --git a/apps/twenties/README.md b/apps/twenties/README.md new file mode 100644 index 000000000..8ee917b0e --- /dev/null +++ b/apps/twenties/README.md @@ -0,0 +1,17 @@ +# Twenties + +Follow the [20-20-20 rule](https://www.aoa.org/AOA/Images/Patients/Eye%20Conditions/20-20-20-rule.pdf) with discrete reminders. Your Bangle will buzz every 20 minutes for you to look away from your screen, and then buzz 20 seconds later to look back. Additionally, alternate between standing and sitting every 20 minutes to be standing for [more than 30 minutes](https://uwaterloo.ca/kinesiology-health-sciences/how-long-should-you-stand-rather-sit-your-work-station) per hour. + +## Usage + +Download this app and it will automatically run in the background. + +## Features + +Vibrates to remind you to stand up and look away for healthy living. + +Only vibrates during work days and hours. + +## Creator + +[@splch](https://github.com/splch/) diff --git a/apps/twenties/app.png b/apps/twenties/app.png new file mode 100644 index 000000000..7c6b02055 Binary files /dev/null and b/apps/twenties/app.png differ diff --git a/apps/twenties/boot.js b/apps/twenties/boot.js new file mode 100644 index 000000000..722af43bc --- /dev/null +++ b/apps/twenties/boot.js @@ -0,0 +1,19 @@ +(() => { + const move = 20 * 60 * 1000; // 20 minutes + const look = 20 * 1000; // 20 seconds + + const buzz = _ => { + const date = new Date(); + const day = date.getDay(); + const hour = date.getHours(); + // buzz at work + if (day >= 1 && day <= 5 && + hour >= 8 && hour <= 17) { + Bangle.buzz().then(_ => { + setTimeout(Bangle.buzz, look); + }); + } + }; + + setInterval(buzz, move); // buzz to stand / sit +})(); diff --git a/apps/twenties/metadata.json b/apps/twenties/metadata.json new file mode 100644 index 000000000..b1dfe2134 --- /dev/null +++ b/apps/twenties/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "twenties", + "name": "Twenties", + "shortName": "twenties", + "version": "0.04", + "description": "Buzzes every 20m to stand / sit and look 20ft away for 20s.", + "icon": "app.png", + "type": "bootloader", + "tags": "alarm,tool", + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [{ "name": "twenties.boot.js", "url": "boot.js" }] +} diff --git a/apps/verticalface/ChangeLog b/apps/verticalface/ChangeLog index 99ab68ec4..dc6c11eab 100644 --- a/apps/verticalface/ChangeLog +++ b/apps/verticalface/ChangeLog @@ -4,3 +4,4 @@ 0.07: Added leading zero to hours and minutes 0.08: Show step count by calling wpedom.getSteps() or activepedom.getSteps() 0.09: Fix time when minutes<10 and hours>9 (fix #767) +0.10: Tell clock widgets to hide. diff --git a/apps/verticalface/app.js b/apps/verticalface/app.js index 4fcae5642..178481047 100644 --- a/apps/verticalface/app.js +++ b/apps/verticalface/app.js @@ -97,6 +97,28 @@ function drawBattery() { // Clear the screen once, at startup g.clear(); +// Show launcher when button pressed +Bangle.setUI("clockupdown", btn=>{ + if (btn!=0) return; + //HRM Controller. + if(!HRMstate){ + //console.log("Toggled HRM"); + //Turn on. + Bangle.buzz(); + Bangle.setHRMPower(1); + currentHRM = "CALC"; + HRMstate = true; + } else if(HRMstate){ + //console.log("Toggled HRM"); + //Turn off. + Bangle.buzz(); + Bangle.setHRMPower(0); + HRMstate = false; + currentHRM = []; + } + drawBPM(HRMstate); +}); + // Load and draw widgets Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -128,28 +150,6 @@ Bangle.on('lcdPower',on=>{ } }); -// Show launcher when button pressed -Bangle.setUI("clockupdown", btn=>{ - if (btn!=0) return; - //HRM Controller. - if(!HRMstate){ - //console.log("Toggled HRM"); - //Turn on. - Bangle.buzz(); - Bangle.setHRMPower(1); - currentHRM = "CALC"; - HRMstate = true; - } else if(HRMstate){ - //console.log("Toggled HRM"); - //Turn off. - Bangle.buzz(); - Bangle.setHRMPower(0); - HRMstate = false; - currentHRM = []; - } - drawBPM(HRMstate); -}); - Bangle.on('touch', function(button) { if(button == 1 || button == 2){ Bangle.showLauncher(); diff --git a/apps/verticalface/metadata.json b/apps/verticalface/metadata.json index da41b3f0d..273070022 100644 --- a/apps/verticalface/metadata.json +++ b/apps/verticalface/metadata.json @@ -2,7 +2,7 @@ "id": "verticalface", "name": "Vertical watch face", "shortName": "Vertical Face", - "version": "0.09", + "version": "0.10", "description": "A simple vertical watch face with the date. Heart rate monitor is toggled with BTN1", "icon": "app.png", "type": "clock", diff --git a/apps/waypoints/lib.js b/apps/waypoints/lib.js index 58cb64d30..88b402a73 100644 --- a/apps/waypoints/lib.js +++ b/apps/waypoints/lib.js @@ -1,7 +1,7 @@ exports.load = (num) => { - return require("Storage").readJSON(`waypoints${num?`.${num}`:""}.json`)||[{name:"NONE"}]; + return require("Storage").readJSON(`waypoints${num?"."+num:""}.json`)||[{name:"NONE"}]; }; exports.save = (waypoints,num) => { - require("Storage").writeJSON(`waypoints${num?`.${num}`:""}.json`, waypoints); + require("Storage").writeJSON(`waypoints${num?"."+num:""}.json`, waypoints); }; diff --git a/apps/waypoints/metadata.json b/apps/waypoints/metadata.json index 0849c590b..d7fa00f7e 100644 --- a/apps/waypoints/metadata.json +++ b/apps/waypoints/metadata.json @@ -5,7 +5,7 @@ "icon": "app.png", "tags": "tool,outdoors,gps", "type": "waypoints", - "supports" : ["BANGLEJS2"], + "supports" : ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "interface": "interface.html", "storage": [ diff --git a/apps/wclock/ChangeLog b/apps/wclock/ChangeLog index 9a2ebdd5f..e50ee6842 100644 --- a/apps/wclock/ChangeLog +++ b/apps/wclock/ChangeLog @@ -1,2 +1,3 @@ 0.02: Modified for use with new bootloader and firmware 0.03: setUI and support for different screens +0.04: Tell clock widgets to hide. diff --git a/apps/wclock/clock-word.js b/apps/wclock/clock-word.js index aff134273..7ddb7bc35 100644 --- a/apps/wclock/clock-word.js +++ b/apps/wclock/clock-word.js @@ -122,11 +122,11 @@ Bangle.on('lcdPower', function(on) { if (on) drawWordClock(); }); +// Show launcher when button pressed +Bangle.setUI("clock"); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); setInterval(drawWordClock, 1E4); drawWordClock(); - -// Show launcher when button pressed -Bangle.setUI("clock"); diff --git a/apps/wclock/metadata.json b/apps/wclock/metadata.json index f22b53dc1..820af7ac0 100644 --- a/apps/wclock/metadata.json +++ b/apps/wclock/metadata.json @@ -1,7 +1,7 @@ { "id": "wclock", "name": "Word Clock", - "version": "0.03", + "version": "0.04", "description": "Display Time as Text", "icon": "clock-word.png", "screenshots": [{"url":"screenshot_word.png"}], diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index 101da48e1..da28d8d5a 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -12,3 +12,5 @@ 0.13: Tweak Bangle.js 2 light theme colors 0.14: Use weather condition code for icon selection 0.15: Fix widget icon +0.16: Don't mark app as clock +0.17: Added clkinfo for clocks. \ No newline at end of file diff --git a/apps/weather/app.js b/apps/weather/app.js index efd9b0209..f63b226b9 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -101,7 +101,11 @@ weather.on("update", update); update(); -// Show launcher when middle button pressed +// We want this app to behave like a clock: +// i.e. show launcher when middle button pressed Bangle.setUI("clock"); +// But the app is not actually a clock +// This matters for widgets that hide themselves for clocks, like widclk or widclose +delete Bangle.CLOCK; Bangle.drawWidgets(); diff --git a/apps/weather/clkinfo.js b/apps/weather/clkinfo.js new file mode 100644 index 000000000..8e502b7fc --- /dev/null +++ b/apps/weather/clkinfo.js @@ -0,0 +1,43 @@ +(function() { + var weather = { + temp: "?", + hum: "?", + wind: "?", + }; + + var weatherJson = storage.readJSON('weather.json'); + if(weatherJson !== undefined && weatherJson.weather !== undefined){ + weather = weatherJson.weather; + weather.temp = locale.temp(weather.temp-273.15); + weather.hum = weather.hum + "%"; + weather.wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/); + weather.wind = Math.round(weather.wind[1]) + "kph"; + } + + var weatherItems = { + name: "Weather", + img: atob("GBiBAf+///u5//n7//8f/9wHP8gDf/gB//AB/7AH/5AcP/AQH/DwD/uAD84AD/4AA/wAAfAAAfAAAfAAAfgAA/////+bP/+zf/+zfw=="), + items: [ + { + name: "temperature", + get: () => ({ text: weather.temp, img: atob("GBiBAf/D//+B//8Y//88//88//88//88//88//8k//8k//8k//8k//8k//8k//4kf/5mf/zDP/yBP/yBP/zDP/5mf/48f/8A///D/w==")}), + show: function() { weatherItems.items[0].emit("redraw"); }, + hide: function () {} + }, + { + name: "humidity", + get: () => ({ text: weather.hum, img: atob("GBiBAf/7///z///x///g///g///Af//Af/3Af/nA//jg//B/v/B/H+A/H8A+D8AeB8AcB4AYA8AYA8AYA+A4A/B4A//4A//8B///Dw==")}), + show: function() { weatherItems.items[1].emit("redraw"); }, + hide: function () {} + }, + { + name: "wind", + get: () => ({ text: weather.wind, img: atob("GBiBAf4f//wP//nn//Pn//Pzg//nAf/meIAOfAAefP///P//+fAAAfAAB////////wAAP4AAH///z///z//nz//nz//zj//wH//8Pw==")}), + show: function() { weatherItems.items[2].emit("redraw"); }, + hide: function () {} + }, + ] + }; + + return weatherItems; +}) \ No newline at end of file diff --git a/apps/weather/metadata.json b/apps/weather/metadata.json index 1d0b6b469..125041ec4 100644 --- a/apps/weather/metadata.json +++ b/apps/weather/metadata.json @@ -1,7 +1,7 @@ { "id": "weather", "name": "Weather", - "version": "0.15", + "version": "0.17", "description": "Show Gadgetbridge weather report", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], @@ -13,7 +13,8 @@ {"name":"weather.wid.js","url":"widget.js"}, {"name":"weather","url":"lib.js"}, {"name":"weather.img","url":"icon.js","evaluate":true}, - {"name":"weather.settings.js","url":"settings.js"} + {"name":"weather.settings.js","url":"settings.js"}, + {"name":"weather.clkinfo.js","url":"clkinfo.js"} ], "data": [{"name":"weather.json"}] } diff --git a/apps/widagps/metadata.json b/apps/widagps/metadata.json index 8d3d37aab..ee1eb9f08 100644 --- a/apps/widagps/metadata.json +++ b/apps/widagps/metadata.json @@ -1,10 +1,10 @@ { "id": "widagps", - "name": "AGPS Widget", + "name": "AGPS Widget (automatic download)", "shortName":"AGPS Widget", "icon": "widget.png", "type": "widget", "version":"0.01", - "description": "Load AGPS data in the background **using Gadgetbridge**", + "description": "Once installed, this widget allows your Bangle.js 2 to load AGPS data in the background **via Gadgetbridge on an Android phone** so it is always up to date. If you just want to upload the latest AGPS data from this app loader, please use the `Assisted GPS Update (AGPS)` app.", "readme": "README.md", "tags": "widget,agps,http", "supports": ["BANGLEJS2"], diff --git a/apps/widalt/ChangeLog b/apps/widalt/ChangeLog new file mode 100644 index 000000000..ec66c5568 --- /dev/null +++ b/apps/widalt/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version diff --git a/apps/widalt/README.md b/apps/widalt/README.md new file mode 100644 index 000000000..08ee4f83d --- /dev/null +++ b/apps/widalt/README.md @@ -0,0 +1,2 @@ +# Altimeter widget +Displays barometric altitude in the top right corner. diff --git a/apps/widalt/metadata.json b/apps/widalt/metadata.json new file mode 100644 index 000000000..309c5bf2c --- /dev/null +++ b/apps/widalt/metadata.json @@ -0,0 +1,18 @@ + +{ + "id": "widalt", + "name": "Altimeter widget", + "version": "0.01", + "description": "Displays barometric altitude", + "readme": "README.md", + "icon": "widalt.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS2"], + "allow_emulator":false, + "storage": [ + {"name":"widalt.wid.js","url":"widalt.wid.js"}, + {"name":"widalt.settings.js","url":"widalt.settings.js"} + ], + "data": [{"name":"widalt.json"}] + } diff --git a/apps/widalt/widalt.png b/apps/widalt/widalt.png new file mode 100644 index 000000000..43e5465bc Binary files /dev/null and b/apps/widalt/widalt.png differ diff --git a/apps/widalt/widalt.settings.js b/apps/widalt/widalt.settings.js new file mode 100644 index 000000000..57993474e --- /dev/null +++ b/apps/widalt/widalt.settings.js @@ -0,0 +1,27 @@ +(function(back) { + var settings = Object.assign({ + interval: 5000, + }, require('Storage').readJSON("widalt.json", true) || {}); + o=Bangle.getOptions(); + Bangle.getPressure().then((p)=>{ + E.showMenu({ + "" : { "title" : "Altimeter Widget" }, + "< Back" : () => back(), + 'QNH': { + value: Math.floor(o.seaLevelPressure), + min: 100, max: 10000, + format: v=>(v+"hPa\nAlt: "+(44330 * (1.0 - Math.pow(p.pressure/v, 0.1903))).toFixed(0)+"m"), + onchange: v => {Bangle.setOptions({seaLevelPressure:v});} + }, + 'update Interval': { + value: settings.interval/1000, + min: 1, max: 60, + format: v=>(v+"s"), + onchange: v => { + settings.interval=v*1000; + require('Storage').writeJSON("widalt.json", settings); + } + } + }); + }); +}) diff --git a/apps/widalt/widalt.wid.js b/apps/widalt/widalt.wid.js new file mode 100644 index 000000000..dbd1a763e --- /dev/null +++ b/apps/widalt/widalt.wid.js @@ -0,0 +1,38 @@ +(()=>{ + var alt=""; + var lastAlt=0; + var settings = Object.assign({ + interval: 5000, + }, require('Storage').readJSON("widalt.json", true) || {}); + Bangle.setBarometerPower(true,"widalt"); + Bangle.on("pressure", (p)=>{ + if (Math.floor(p.altitude)!=lastAlt) { + lastAlt=Math.floor(p.altitude); + alt=p.altitude.toFixed(0); + var w = WIDGETS["widalt"].width; + WIDGETS["widalt"].width = 1 + (alt.length)*12+16; + if (w!=WIDGETS["widalt"].width) Bangle.drawWidgets(); + else WIDGETS["widalt"].draw(); + } + Bangle.setBarometerPower(false,"widalt") + setTimeout(()=>{Bangle.setBarometerPower(true,"widalt");},settings.interval); + }); + + function draw() { + if (!Bangle.isLCDOn()) return; + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(this.x, this.y, this.x + this.width, this.y + 23); + g.setColor(g.theme.fg); + g.drawImage(atob("EBCBAAAAAAAIAAwgFXAX0BCYIIggTD/EYPZADkACf/4AAAAA"), this.x, this.y+4); +g.setFontCustom(atob("AAAAABwAAOAAAgAAHAADwAD4AB8AB8AA+AAeAADAAAAOAAP+AH/8B4DwMAGBgAwMAGBgAwOAOA//gD/4AD4AAAAAAAABgAAcAwDAGAwAwP/+B//wAAGAAAwAAGAAAAAAAAIAwHgOA4DwMA+BgOwMDmBg4wOeGA/gwDwGAAAAAAAAAGAHA8A4DwMAGBhAwMMGBjgwOcOA+/gDj4AAAAABgAAcAAHgADsAA5gAOMAHBgBwMAP/+B//wABgAAMAAAAAAAgD4OB/AwOYGBjAwMYGBjBwMe8Bh/AIHwAAAAAAAAAfAAP8AHxwB8GAdgwPMGBxgwMOOAB/gAH4AAAAAAABgAAMAABgAwMAeBgPgMHwBj4AN8AB+AAPAABAAAAAAAMfAH38B/xwMcGBhgwMMGBjgwP+OA+/gDj4AAAAAAAAOAAH4AA/gQMMGBgzwME8BhvAOPgA/4AD8AAEAAAAAAGAwA4OAHBwAAA="), 46, atob("BAgMDAwMDAwMDAwMBQ=="), 21+(1<<8)+(1<<16)); + g.setFontAlign(-1, 0); + g.drawString(alt, this.x+16, this.y + 12); + } + WIDGETS["widalt"] = { + area: "tr", + width: 6, + draw: draw + }; + +})(); diff --git a/apps/widbt_notify/ChangeLog b/apps/widbt_notify/ChangeLog index 8f1dab908..b9ecd7b7d 100644 --- a/apps/widbt_notify/ChangeLog +++ b/apps/widbt_notify/ChangeLog @@ -11,4 +11,5 @@ 0.12: Prevent repeated execution of `draw()` from the current app. 0.13: Added "connection restored" notification. Fixed restoring of the watchface. 0.14: Added configuration option -0.15: Added option to hide widget when connected \ No newline at end of file +0.15: Added option to hide widget when connected +0.16: Simplify code, add option to disable displaying a message \ No newline at end of file diff --git a/apps/widbt_notify/metadata.json b/apps/widbt_notify/metadata.json index 6def70c64..626ffcb8b 100644 --- a/apps/widbt_notify/metadata.json +++ b/apps/widbt_notify/metadata.json @@ -1,8 +1,8 @@ { "id": "widbt_notify", "name": "Bluetooth Widget with Notification", - "version": "0.15", - "description": "Show the current Bluetooth connection status in the top right of the watch. Optional buzz and/or and hide if disconnected", + "version": "0.16", + "description": "Show the current Bluetooth connection status with some optional features: show message, buzz on connect/loss, hide always/if connected.", "icon": "widget.png", "type": "widget", "tags": "widget,bluetooth", diff --git a/apps/widbt_notify/settings.js b/apps/widbt_notify/settings.js index 1e0d5036b..5c67fed7b 100644 --- a/apps/widbt_notify/settings.js +++ b/apps/widbt_notify/settings.js @@ -1,69 +1,57 @@ (function(back) { - var FILE = "widbt_notify.json"; + + var filename = "widbt_notify.json"; + + // set Storage and load settings + var storage = require("Storage"); var settings = Object.assign({ - secondsOnUnlock: false, - }, require('Storage').readJSON(FILE, true) || {}); + showWidget: true, + buzzOnConnect: true, + buzzOnLoss: true, + hideConnected: true, + showMessage: true, + nextBuzz: 30000 + }, storage.readJSON(filename, true) || {}); - function writeSettings() { - require('Storage').writeJSON(FILE, settings); - } - - // Helper method which uses int-based menu item for set of string values - function stringItems(startvalue, writer, values) { + // setup boolean menu entries + function boolEntry(key) { return { - value: (startvalue === undefined ? 0 : values.indexOf(startvalue)), - format: v => values[v], - min: 0, - max: values.length - 1, - wrap: true, - step: 1, + value: settings[key], onchange: v => { - writer(values[v]); - writeSettings(); + // change the value of key + settings[key] = v; + // write to storage + storage.writeJSON(filename, settings); } }; } - // Helper method which breaks string set settings down to local settings object - function stringInSettings(name, values) { - return stringItems(settings[name], v => settings[name] = v, values); - } - - var mainmenu = { + // setup menu + var menu = { "": { "title": "Bluetooth Widget WN" }, "< Back": () => back(), - "Show Widget": { - value: (settings.showWidget !== undefined ? settings.showWidget : true), + "Show Widget": boolEntry("showWidget"), + "Buzz on connect": boolEntry("buzzOnConnect"), + "Buzz on loss": boolEntry("buzzOnLoss"), + "Hide connected": boolEntry("hideConnected"), + "Show Message": boolEntry("showMessage"), + "Next Buzz": { + value: settings.nextBuzz, + step: 1000, + min: 1000, + max: 120000, + wrap: true, + format: v => (v / 1000) + "s", onchange: v => { - settings.showWidget = v; - writeSettings(); + settings.nextBuzz = v; + storage.writeJSON(filename, settings); } - }, - "Buzz on Connect": { - value: (settings.buzzOnConnect !== undefined ? settings.buzzOnConnect : true), - onchange: v => { - settings.buzzOnConnect = v; - writeSettings(); - } - }, - "Buzz on loss": { - value: (settings.buzzOnLoss !== undefined ? settings.buzzOnLoss : true), - onchange: v => { - settings.buzzOnLoss = v; - writeSettings(); - } - }, - "Hide connected": { - value: (settings.hideConnected !== undefined ? settings.hideConnected : false), - onchange: v => { - settings.hideConnected = v; - writeSettings(); - } - } + } }; - E.showMenu(mainmenu); + // draw main menu + E.showMenu(menu); -}); +}) \ No newline at end of file diff --git a/apps/widbt_notify/widget.js b/apps/widbt_notify/widget.js index de2baa3cf..1b192412a 100644 --- a/apps/widbt_notify/widget.js +++ b/apps/widbt_notify/widget.js @@ -1,110 +1,90 @@ -WIDGETS.bluetooth_notify = { +(function() { + // load settings + var settings = Object.assign({ + showWidget: true, + buzzOnConnect: true, + buzzOnLoss: true, + hideConnected: true, + showMessage: true, + nextBuzz: 30000 + }, require("Storage").readJSON("widbt_notify.json", true) || {}); + + // setup widget with to hide if connected and option set + var widWidth = settings.hideConnected && NRF.getSecurityStatus().connected ? 0 : 15; + + // write widget with loaded settings + WIDGETS.bluetooth_notify = Object.assign(settings, { + + // set area and width area: "tr", - width: 15, + width: widWidth, + + // setup warning status warningEnabled: 1, - // ------------ Settings -------- very lame - need to improve - readshowWidget: function() { - var showWidget; - const SETTINGSFILE = "widbt_notify.json"; - function def (value, def) {return value !== undefined ? value : def;} - var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; - showWidget = def(settings.showWidget, true); - return showWidget; - }, - - readBuzzOnConnect: function() { - var buzzOnConnect; - const SETTINGSFILE = "widbt_notify.json"; - function def (value, def) {return value !== undefined ? value : def;} - var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; - buzzOnConnect = def(settings.buzzOnConnect, true); - return buzzOnConnect; - }, - - readBuzzOnLoss: function() { - var buzzOnLoss; - const SETTINGSFILE = "widbt_notify.json"; - function def (value, def) {return value !== undefined ? value : def;} - var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; - buzzOnLoss = def(settings.buzzOnLoss, true); - return buzzOnLoss; - }, - - readHideConnected: function() { - var hideConnected; - const SETTINGSFILE = "widbt_notify.json"; - function def (value, def) {return value !== undefined ? value : def;} - var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; - hideConnected = def(settings.hideConnected, true); - return hideConnected; - }, - - - // ------------ Settings -------- - draw: function() { - if (WIDGETS.bluetooth_notify.readshowWidget()){ - g.reset(); - if (NRF.getSecurityStatus().connected) { - if (!WIDGETS.bluetooth_notify.readHideConnected()) { - g.setColor((g.getBPP() > 8) ? "#07f" : (g.theme.dark ? "#0ff" : "#00f")); - g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); - } - } else { - // g.setColor(g.theme.dark ? "#666" : "#999"); - g.setColor("#f00"); // red is easier to distinguish from blue - g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); - } + if (this.showWidget) { + g.reset(); + if (NRF.getSecurityStatus().connected) { + if (!this.hideConnected) { + g.setColor((g.getBPP() > 8) ? "#07f" : (g.theme.dark ? "#0ff" : "#00f")); + g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); + } + } else { + // g.setColor(g.theme.dark ? "#666" : "#999"); + g.setColor("#f00"); // red is easier to distinguish from blue + g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); } + } }, - - redrawCurrentApp: function(){ - if(typeof(draw)=='function'){ - g.clear(); - draw(); - Bangle.loadWidgets(); - Bangle.drawWidgets(); - }else{ - load(); // fallback. This might reset some variables + + redrawCurrentApp: function() { + if (typeof(draw) == 'function') { + g.clear(); + draw(); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + } else { + load(); // fallback. This might reset some variables + } + }, + + onNRF: function(connect) { + // setup widget with and reload widgets to show/hide if hideConnected is enabled + if (this.hideConnected) { + this.width = connect ? 0 : 15; // ensures correct redraw + Bangle.drawWidgets(); + } else { + // redraw widget + this.draw(); + } + + if (this.warningEnabled) { + if (this.showMessage) { + E.showMessage( /*LANG*/ 'Connection\n' + (connect ? /*LANG*/ 'restored.' : /*LANG*/ 'lost.'), 'Bluetooth'); + setTimeout(() => { + WIDGETS.bluetooth_notify.redrawCurrentApp(); + }, 3000); // clear message - this will reload the widget, resetting 'warningEnabled'. } - }, - - connect: function() { - if(WIDGETS.bluetooth_notify.warningEnabled == 1){ - E.showMessage(/*LANG*/'Connection\nrestored.', 'Bluetooth'); - setTimeout(()=>{WIDGETS.bluetooth_notify.redrawCurrentApp();}, 3000); // clear message - this will reload the widget, resetting 'warningEnabled'. - - WIDGETS.bluetooth_notify.warningEnabled = 0; - setTimeout('WIDGETS.bluetooth_notify.warningEnabled = 1;', 30000); // don't buzz for the next 30 seconds. - - var quiet = (require('Storage').readJSON('setting.json',1)||{}).quiet; - if(!quiet && WIDGETS.bluetooth_notify.readBuzzOnConnect()){ - Bangle.buzz(700, 1); // buzz on connection resume - } - } - WIDGETS.bluetooth_notify.draw(); + this.warningEnabled = 0; + setTimeout('WIDGETS.bluetooth_notify.warningEnabled = 1;', this.nextBuzz); // don't buzz for the next X seconds. - }, - - disconnect: function() { - if(WIDGETS.bluetooth_notify.warningEnabled == 1){ - E.showMessage(/*LANG*/ 'Connection\nlost.', 'Bluetooth'); - setTimeout(()=>{WIDGETS.bluetooth_notify.redrawCurrentApp();}, 3000); // clear message - this will reload the widget, resetting 'warningEnabled'. - - WIDGETS.bluetooth_notify.warningEnabled = 0; - setTimeout('WIDGETS.bluetooth_notify.warningEnabled = 1;', 30000); // don't buzz for the next 30 seconds. - - var quiet = (require('Storage').readJSON('setting.json',1)||{}).quiet; - if(!quiet && WIDGETS.bluetooth_notify.readBuzzOnLoss()){ - Bangle.buzz(700, 1); // buzz on connection loss - } - } - - WIDGETS.bluetooth_notify.draw(); + var quiet = (require('Storage').readJSON('setting.json', 1) || {}).quiet; + if (!quiet && (connect ? this.buzzOnConnect : this.buzzOnLoss)) { + Bangle.buzz(700, 1); // buzz on connection resume or loss + } + } } -}; -NRF.on('connect', WIDGETS.bluetooth_notify.connect); -NRF.on('disconnect', WIDGETS.bluetooth_notify.disconnect); + }); + + // clear variables + settings = undefined; + widWidth = undefined; + + // setup bluetooth connection events + NRF.on('connect', (addr) => WIDGETS.bluetooth_notify.onNRF(addr)); + NRF.on('disconnect', () => WIDGETS.bluetooth_notify.onNRF()); + +})() \ No newline at end of file diff --git a/apps/widcw/ChangeLog b/apps/widcw/ChangeLog index a4bc24d1a..07b8f7424 100644 --- a/apps/widcw/ChangeLog +++ b/apps/widcw/ChangeLog @@ -1 +1,2 @@ -0.01: First version \ No newline at end of file +0.01: First version +0.02: Fix memory leak \ No newline at end of file diff --git a/apps/widcw/metadata.json b/apps/widcw/metadata.json index 653b093ec..467ab1729 100644 --- a/apps/widcw/metadata.json +++ b/apps/widcw/metadata.json @@ -1,7 +1,7 @@ { "id": "widcw", "name": "Calendar Week Widget", - "version": "0.01", + "version": "0.02", "description": "Widget which shows the current calendar week", "icon": "widget.png", "type": "widget", diff --git a/apps/widcw/widget.js b/apps/widcw/widget.js index ef43a4551..e33ad0aad 100644 --- a/apps/widcw/widget.js +++ b/apps/widcw/widget.js @@ -34,8 +34,8 @@ } // redraw when date changes - setTimeout(()=>WIDGETS["widcw"].draw(), (86401 - Math.floor(date/1000) % 86400)*1000); - + if (WIDGETS["widcw"].to) clearTimeout(WIDGETS["widcw"].to); + WIDGETS["widcw"].to = setTimeout(()=>WIDGETS["widcw"].draw(), (86401 - Math.floor(date/1000) % 86400)*1000); } // add your widget diff --git a/apps/widgps/ChangeLog b/apps/widgps/ChangeLog index d4a569574..b530843e7 100644 --- a/apps/widgps/ChangeLog +++ b/apps/widgps/ChangeLog @@ -5,3 +5,5 @@ 0.05: Don't poll for GPS status, override setGPSPower handler (fix #1456) 0.06: Periodically update so the always on display does show current GPS fix 0.07: Alternative marker icon (configurable via settings) +0.08: Add ability to hide the icon when GPS is off, for a cleaner appearance. +0.09: Do not take widget space if icon is hidden diff --git a/apps/widgps/README.md b/apps/widgps/README.md index 81a24100b..98f0ba6f7 100644 --- a/apps/widgps/README.md +++ b/apps/widgps/README.md @@ -14,6 +14,7 @@ There are two icons which can be used to visualize the GPS/GNSS status: - Shows in green when the GPS is on and has a fix 2. Different place markers depending on GPS/GNSS status +You can also choose to hide the icon when the GPS is off in the settings. Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS @@ -21,4 +22,6 @@ Forum](http://forum.espruino.com/microcosms/1424/) Extended by Marco ([myxor](https://github.com/myxor)) +Extended by khromov ([khromov](https://github.com/khromov)) + Place marker icons from [icons8.com](https://icons8.com/icon/set/maps/material-outlined). diff --git a/apps/widgps/default.json b/apps/widgps/default.json index d1ab3f797..28482ddb0 100644 --- a/apps/widgps/default.json +++ b/apps/widgps/default.json @@ -1 +1 @@ -{"crossIcon": "true"} +{"crossIcon": true, "hideWhenGpsOff": false} \ No newline at end of file diff --git a/apps/widgps/metadata.json b/apps/widgps/metadata.json index 144dd6cc6..cfd35f5bb 100644 --- a/apps/widgps/metadata.json +++ b/apps/widgps/metadata.json @@ -1,7 +1,7 @@ { "id": "widgps", "name": "GPS Widget", - "version": "0.07", + "version": "0.09", "description": "Tiny widget to show the power and fix status of the GPS/GNSS", "icon": "widget.png", "type": "widget", diff --git a/apps/widgps/settings.js b/apps/widgps/settings.js index 4cd9e0b83..7a1c186c9 100644 --- a/apps/widgps/settings.js +++ b/apps/widgps/settings.js @@ -20,9 +20,13 @@ var mainmenu = { '' : {'title' : 'GPS widget'}, '< Back' : back, "Cross icon" : { - value : !!settings.crossIcon , + value : settings.crossIcon , onchange : v => { writeSettings("crossIcon", v); } }, + "Hide icon when GPS off" : { + value : settings.hideWhenGpsOff , + onchange : v => { writeSettings("hideWhenGpsOff", v); } + }, }; E.showMenu(mainmenu); -}); +}); \ No newline at end of file diff --git a/apps/widgps/widget.js b/apps/widgps/widget.js index fd9b44484..73351eaa6 100644 --- a/apps/widgps/widget.js +++ b/apps/widgps/widget.js @@ -1,6 +1,9 @@ (function() { -let settings = - require("Storage").readJSON("widgps.json", 1) || {crossIcon : true}; + +let settings = Object.assign( + require('Storage').readJSON("widgps.default.json", true) || {}, + require('Storage').readJSON("widgps.json", true) || {} +); var interval; @@ -8,13 +11,14 @@ var interval; var oldSetGPSPower = Bangle.setGPSPower; Bangle.setGPSPower = function(on, id) { var isGPSon = oldSetGPSPower(on, id); - WIDGETS.gps.draw(); + WIDGETS.gps.width = !isGPSon && settings.hideWhenGpsOff ? 0 : 24; + Bangle.drawWidgets(); return isGPSon; }; WIDGETS.gps = { area : "tr", - width : 24, + width : !Bangle.isGPSOn() && settings.hideWhenGpsOff ? 0 : 24, draw : function() { g.reset(); @@ -35,13 +39,23 @@ WIDGETS.gps = { } else { g.setColor("#FD0"); // on but no fix = amber } - } else { - g.setColor("#888"); // off = grey - } - g.drawImage( + + g.drawImage( atob( "GBiBAAAAAAAAAAAAAA//8B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+A//8AAAAAAAAAAAAA=="), this.x, 2 + this.y); + + } else { + if(!settings.hideWhenGpsOff) { + g.setColor("#888"); // off = grey + + g.drawImage( + atob( + "GBiBAAAAAAAAAAAAAA//8B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+A//8AAAAAAAAAAAAA=="), + this.x, 2 + this.y); + } + } + } else { // marker icons if (Bangle.isGPSOn()) { const gpsObject = Bangle.getGPSFix(); @@ -59,9 +73,11 @@ WIDGETS.gps = { } } else { // GNSS off - g.drawImage( - atob("GBiBAAAAAAAAAAB+ABj/ABxDgA4AwAcAwAeMYAfEYAbgYAZwYAM4wAMcQAOOAAGHAAHDgADDwABm4AB+cAA8OAAYGAAAAAAAAAAAAA=="), - this.x, 2 + this.y); + if(!settings.hideWhenGpsOff) { + g.drawImage( + atob("GBiBAAAAAAAAAAB+ABj/ABxDgA4AwAcAwAeMYAfEYAbgYAZwYAM4wAMcQAOOAAGHAAHDgADDwABm4AB+cAA8OAAYGAAAAAAAAAAAAA=="), + this.x, 2 + this.y); + } } } } diff --git a/apps/widmeda/ChangeLog b/apps/widmeda/ChangeLog new file mode 100644 index 000000000..7415150e6 --- /dev/null +++ b/apps/widmeda/ChangeLog @@ -0,0 +1 @@ +0.01: Initial Medical Alert Widget! diff --git a/apps/widmeda/README.md b/apps/widmeda/README.md new file mode 100644 index 000000000..0bbfc4dc3 --- /dev/null +++ b/apps/widmeda/README.md @@ -0,0 +1,23 @@ +# Medical Alert Widget + +Shows a medical alert logo in the top right widget area, and a medical alert message in the bottom widget area. + +**Note:** this is not a replacement for a medical alert band but hopefully a useful addition. + +## Features + +Implemented: + +- Basic medical alert logo and message +- Only display bottom widget on clocks +- High contrast colours depending on theme + +Future: + +- Configure when to show bottom widget (always/never/clocks) +- Configure medical alert text +- Show details when touched + +## Creator + +James Taylor ([jt-nti](https://github.com/jt-nti)) diff --git a/apps/widmeda/metadata.json b/apps/widmeda/metadata.json new file mode 100644 index 000000000..346306b8e --- /dev/null +++ b/apps/widmeda/metadata.json @@ -0,0 +1,15 @@ +{ "id": "widmeda", + "name": "Medical Alert Widget", + "shortName":"Medical Alert", + "version":"0.01", + "description": "Display a medical alert in the bottom widget section.", + "icon": "widget.png", + "type": "widget", + "tags": "health,medical,tools,widget", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "screenshots": [{"url":"screenshot_light.png"}], + "storage": [ + {"name":"widmeda.wid.js","url":"widget.js"} + ] +} diff --git a/apps/widmeda/screenshot_light.png b/apps/widmeda/screenshot_light.png new file mode 100644 index 000000000..bf92d753d Binary files /dev/null and b/apps/widmeda/screenshot_light.png differ diff --git a/apps/widmeda/widget.js b/apps/widmeda/widget.js new file mode 100644 index 000000000..a2d109596 --- /dev/null +++ b/apps/widmeda/widget.js @@ -0,0 +1,30 @@ +(() => { + // Top right star of life logo + WIDGETS["widmedatr"]={ + area: "tr", + width: 24, + draw: function() { + g.reset(); + g.setColor("#f00"); + g.drawImage(atob("FhYBAAAAA/AAD8AAPwAc/OD/P8P8/x/z/n+/+P5/wP58A/nwP5/x/v/n/P+P8/w/z/Bz84APwAA/AAD8AAAAAA=="), this.x + 1, this.y + 1); + } + }; + + // Bottom medical alert message + WIDGETS["widmedabl"]={ + area: "bl", + width: Bangle.CLOCK?Bangle.appRect.w:0, + draw: function() { + // Only show the widget on clocks + if (!Bangle.CLOCK) return; + + g.reset(); + g.setBgColor(g.theme.dark ? "#fff" : "#f00"); + g.setColor(g.theme.dark ? "#f00" : "#fff"); + g.setFont("Vector",18); + g.setFontAlign(0,0); + g.clearRect(this.x, this.y, this.x + this.width - 1, this.y + 23); + g.drawString("MEDICAL ALERT", this.width / 2, this.y + ( 23 / 2 )); + } + }; +})(); diff --git a/apps/widmeda/widget.png b/apps/widmeda/widget.png new file mode 100644 index 000000000..249bf15bf Binary files /dev/null and b/apps/widmeda/widget.png differ diff --git a/apps/widram/ChangeLog b/apps/widram/ChangeLog index e7b406081..7b00c8a48 100644 --- a/apps/widram/ChangeLog +++ b/apps/widram/ChangeLog @@ -1,2 +1,3 @@ 0.01: New Widget! 0.02: Now also visible on Bangle.js 2 +0.03: Remove global declaration of BANGLEJS2 var (fix #2123) diff --git a/apps/widram/metadata.json b/apps/widram/metadata.json index 19ae6d311..ebf23742b 100644 --- a/apps/widram/metadata.json +++ b/apps/widram/metadata.json @@ -2,7 +2,7 @@ "id": "widram", "name": "RAM Widget", "shortName": "RAM Widget", - "version": "0.02", + "version": "0.03", "description": "Display your Bangle's RAM usage percentage in a widget", "icon": "widget.png", "type": "widget", diff --git a/apps/widram/widget.js b/apps/widram/widget.js index 210c85357..07b7c0a5f 100644 --- a/apps/widram/widget.js +++ b/apps/widram/widget.js @@ -1,6 +1,6 @@ (() => { function draw() { - BANGLEJS2 = process.env.HWVERSION==2; + const BANGLEJS2 = process.env.HWVERSION==2; g.reset(); var m = process.memory(); var percent = Math.round(m.usage*100/m.total); diff --git a/backup.js b/backup.js index 8a894666e..06d98a366 100644 --- a/backup.js +++ b/backup.js @@ -101,6 +101,7 @@ function bangleUpload() { return Comms.showMessage(`Restoring...`); }) .then(() => Comms.write("\x10"+Comms.getProgressCmd()+"\n")) .then(() => Comms.uploadCommandList(cmds, 0, cmds.length)) + .then(() => getInstalledApps(true)) .then(() => Comms.showMessage(Const.MESSAGE_RELOAD)) .then(() => { Progress.hide({sticky:true}); diff --git a/bin/apploader.js b/bin/apploader.js index 427a0ef99..26c4c1f09 100755 --- a/bin/apploader.js +++ b/bin/apploader.js @@ -1,4 +1,4 @@ -#!/usr/bin/nodejs +#!/usr/bin/env node /* Simple Command-line app loader for Node.js =============================================== @@ -8,35 +8,44 @@ as a normal dependency) because we want `sanitycheck.js` to be able to run *quickly* in travis for every commit, and we don't want NPM pulling in (and compiling native modules) for Noble. + */ var SETTINGS = { pretokenise : true }; var APPSDIR = __dirname+"/../apps/"; -var Utils = require("../core/js/utils.js"); -var AppInfo = require("../core/js/appinfo.js"); var noble; -try { - noble = require('@abandonware/noble'); -} catch (e) {} -if (!noble) try { - noble = require('noble'); -} catch (e) { } +["@abandonware/noble", "noble"].forEach(module => { + if (!noble) try { + noble = require(module); + } catch(e) { + if (e.code !== 'MODULE_NOT_FOUND') { + throw e; + } + } +}); if (!noble) { console.log("You need to:") console.log(" npm install @abandonware/noble") console.log("or:") console.log(" npm install noble") + process.exit(1); } - -var apps = []; - function ERROR(msg) { console.error(msg); process.exit(1); } +//eval(require("fs").readFileSync(__dirname+"../core/js/utils.js")); +var AppInfo = require("../core/js/appinfo.js"); +global.Const = { + /* Are we only putting a single app on a device? If so + apps should all be saved as .bootcde and we write info + about the current app into app.info */ + SINGLE_APP_ONLY : false, +}; +var deviceId = "BANGLEJS2"; var apps = []; var dirs = require("fs").readdirSync(APPSDIR, {withFileTypes: true}); dirs.forEach(dir => { @@ -54,6 +63,10 @@ dirs.forEach(dir => { var args = process.argv; +var bangleParam = args.findIndex(arg => /-b\d/.test(arg)); +if (bangleParam!==-1) { + deviceId = "BANGLEJS"+args.splice(bangleParam, 1)[0][2]; +} if (args.length==3 && args[2]=="list") cmdListApps(); else if (args.length==3 && args[2]=="devices") cmdListDevices(); else if (args.length==4 && args[2]=="install") cmdInstallApp(args[3]); @@ -68,7 +81,10 @@ apploader.js list - list available apps apploader.js devices - list available device addresses -apploader.js install appname [de:vi:ce:ad:dr:es] +apploader.js install [-b1] appname [de:vi:ce:ad:dr:es] + +NOTE: By default this App Loader expects the device it uploads to +(deviceId) to be BANGLEJS2, pass '-b1' for it to work with Bangle.js 1 `); process.exit(0); } @@ -104,7 +120,10 @@ function cmdInstallApp(appId, deviceAddress) { fileGetter:function(url) { console.log(__dirname+"/"+url); return Promise.resolve(require("fs").readFileSync(__dirname+"/../"+url).toString("binary")); - }, settings : SETTINGS}).then(files => { + }, + settings : SETTINGS, + device : { id : deviceId } + }).then(files => { //console.log(files); var command = files.map(f=>f.cmd).join("\n")+"\n"; bangleSend(command, deviceAddress).then(() => process.exit(0)); diff --git a/bin/create_app_supports_field.js b/bin/create_app_supports_field.js index d6aada357..24d6694f2 100644 --- a/bin/create_app_supports_field.js +++ b/bin/create_app_supports_field.js @@ -1,4 +1,4 @@ -#!/usr/bin/nodejs +#!/usr/bin/env nodejs /* Quick hack to add proper 'supports' field to apps.json */ diff --git a/bin/create_apps_json.sh b/bin/create_apps_json.sh index 30c58bc93..c9f310e57 100755 --- a/bin/create_apps_json.sh +++ b/bin/create_apps_json.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # ================================================================ # apps.json used to contain the metadata for every app. Now the # metadata is stored in each apps's directory - app/yourapp/metadata.js diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 1c2d9cb77..1dc5ec073 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -1,4 +1,4 @@ -#!/usr/bin/nodejs +#!/usr/bin/env nodejs /* Mashes together a bunch of different apps to make a single firmware JS file which can be uploaded. diff --git a/bin/firmwaremaker_c.js b/bin/firmwaremaker_c.js index 4aa8e087f..87065dab4 100755 --- a/bin/firmwaremaker_c.js +++ b/bin/firmwaremaker_c.js @@ -1,4 +1,4 @@ -#!/usr/bin/node +#!/usr/bin/env node /* Mashes together a bunch of different apps into a big binary blob. We then store this *inside* the Bangle.js firmware and can use it diff --git a/bin/pre-publish.sh b/bin/pre-publish.sh index ee73968d7..710160ded 100755 --- a/bin/pre-publish.sh +++ b/bin/pre-publish.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash cd `dirname $0`/.. nodejs bin/sanitycheck.js || exit 1 diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 9939b061b..8bd23dd77 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -1,4 +1,4 @@ -#!/usr/bin/node +#!/usr/bin/env node /* Checks for any obvious problems in apps.json */ @@ -30,7 +30,11 @@ function ERROR(msg, opt) { function WARN(msg, opt) { // file=app.js,line=1,col=5,endColumn=7 opt = opt||{}; - console.log(`::warning${Object.keys(opt).length?" ":""}${Object.keys(opt).map(k=>k+"="+opt[k]).join(",")}::${msg}`); + if (KNOWN_WARNINGS.includes(msg)) { + console.log(`Known warning : ${msg}`); + } else { + console.log(`::warning${Object.keys(opt).length?" ":""}${Object.keys(opt).map(k=>k+"="+opt[k]).join(",")}::${msg}`); + } warningCount++; } @@ -86,6 +90,10 @@ const INTERNAL_FILES_IN_APP_TYPE = { // list of app types and files they SHOULD 'waypoints' : ['waypoints'], // notify? }; +/* These are warnings we know about but don't want in our output */ +var KNOWN_WARNINGS = [ +"App gpsrec data file wildcard .gpsrc? does not include app ID" +]; function globToRegex(pattern) { const ESCAPE = '.*+-?^${}()|[]\\'; @@ -225,6 +233,13 @@ apps.forEach((app,appIdx) => { console.log("====================================================="); ERROR(`App ${app.id}'s ${file.name} is a JS file but isn't valid JS`, {file:appDirRelative+file.url}); } + // clock app checks + if (app.type=="clock") { + var a = fileContents.indexOf("Bangle.loadWidgets()"); + var b = fileContents.indexOf("Bangle.setUI("); + if (a>=0 && b>=0 && aOfficial Version here.'; } -var RECOMMENDED_VERSION = "2v14"; +var RECOMMENDED_VERSION = "2v15"; // could check http://www.espruino.com/json/BANGLEJS.json for this // We're only interested in Bangles diff --git a/modules/clock_info.js b/modules/clock_info.js new file mode 100644 index 000000000..6a810371a --- /dev/null +++ b/modules/clock_info.js @@ -0,0 +1,130 @@ +var exports = {}; +/* Module that allows for loading of clock 'info' displays +that can be scrolled through on the clock face. + +`load()` returns an array of menu objects, where each object contains a list of menu items: +* 'name' : text to display and identify menu object (e.g. weather) +* 'img' : a 24x24px image +* 'items' : menu items such as temperature, humidity, wind etc. + +Note that each item is an object with: + +* 'item.name' : friendly name to identify an item (e.g. temperature) +* 'item.get' : function that resolves with: + { + 'text' : the text to display for this item + 'img' : a 24x24px image to display for this item + } +* 'item.show' : called when item should be shown. Enables updates. Call BEFORE 'get' +* 'item.hide' : called when item should be hidden. Disables updates. +* .on('redraw', ...) : event that is called when 'get' should be called again (only after 'item.show') +* 'item.run' : (optional) called if the info screen is tapped - can perform some action. Return true if the caller should feedback the user. + +See the bottom of this file for example usage... + +example.clkinfo.js : + +(function() { + return { + name: "Bangle", + img: atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA==") }), + items: [ + { name : "Item1", + get : () => ({ text : "TextOfItem1", + img : atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA==") }), + show : () => {}, + hide : () => {} + } + ] + }; +}) // must not have a semi-colon! + +*/ + + +exports.load = function() { + // info used for drawing... + var hrm = "--"; + var alt = "--"; + // callbacks (needed for easy removal of listeners) + function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } + function stepUpdateHandler() { bangleItems[1].emit("redraw"); } + function hrmUpdateHandler() { bangleItems[2].emit("redraw"); } + function altUpdateHandler() { + Bangle.getPressure().then(data=>{ + if (!data) return; + alt = Math.round(data.altitude) + "m"; + bangleItems[3].emit("redraw"); + }); + } + // actual menu + var menu = [{ + name: "Bangle", + img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w=="), + items: [ + { name : "Battery", + get : () => ({ + text : E.getBattery() + "%", + img : atob(Bangle.isCharging() ? "GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA==" : "GBiBAAAAAAAAAAAAAAAAAAAAAD//+P///IAAAr//Ar//Ar//A7//A7//A7//A7//Ar//AoAAAv///D//+AAAAAAAAAAAAAAAAAAAAA==") }), + show : function() { this.interval = setInterval(()=>this.emit('redraw'), 60000); Bangle.on("charging", batteryUpdateHandler); batteryUpdateHandler(); }, + hide : function() { clearInterval(this.interval); delete this.interval; Bangle.removeListener("charging", batteryUpdateHandler); }, + }, + { name : "Steps", get : () => ({ + text : Bangle.getHealthStatus("day").steps, + img : atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA==") }), + show : function() { Bangle.on("step", stepUpdateHandler); stepUpdateHandler(); }, + hide : function() { Bangle.removeListener("step", stepUpdateHandler); }, + }, + { name : "HRM", get : () => ({ + text : Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", + img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAADAAADAAAHAAAHjAAHjgAPngH9n/n82/gA+AAA8AAA8AAAcAAAYAAAYAAAAAAAAAAAAAAAAAAAAAA==") }), + show : function() { Bangle.setHRMPower(1,"clkinfo"); Bangle.on("HRM", hrmUpdateHandler); hrm = Math.round(Bangle.getHealthStatus("last").bpm); hrmUpdateHandler(); }, + hide : function() { Bangle.setHRMPower(0,"clkinfo"); Bangle.removeListener("HRM", hrmUpdateHandler); hrm = "--"; }, + } + ], + }]; + var bangleItems = menu[0].items; + + if (Bangle.getPressure){ // Altimeter may not exist + bangleItems.push({ name : "Altitude", get : () => ({ + text : alt, + img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA==") }), + show : function() { this.interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, + hide : function() { clearInterval(this.interval); delete this.interval; }, + }); + } + + // In case there exists already a menu object b with the same name as the next + // object a, we append the items. Otherwise we add the new object a to the list. + require("Storage").list(/clkinfo.js$/).forEach(fn => { + var a = eval(require("Storage").read(fn))(); + var b = menu.find(x => x.name === a.name) + if(b) b.items = b.items.concat(a.items); + else menu = menu.concat(a); + }); + + // return it all! + return menu; +}; + + +// Code for testing +/* +g.clear(); +var menu = exports.load(); // or require("clock_info").load() +var itemsFirstMenu = menu[0].items; +items.forEach((itm,i) => { + var y = i*24; + console.log("Starting", itm.name); + function draw() { + var info = itm.get(); + g.reset().setFont("6x8:2").setFontAlign(-1,0); + g.clearRect(0,y,g.getWidth(),y+23); + g.drawImage(info.img, 0,y); + g.drawString(info.text, 48,y+12); + } + itm.on('redraw', draw); // ensures we redraw when we need to + itm.show(); + draw(); +}); +*/ diff --git a/modules/wear_detect.js b/modules/wear_detect.js new file mode 100644 index 000000000..9581657cf --- /dev/null +++ b/modules/wear_detect.js @@ -0,0 +1,18 @@ +/** Returns a promise that resolves with whether the Bangle +is worn or not. + +Usage: + +require("wear_detect").isWorn().then(worn => { + console.log(worn ? "is worn" : "not worn"); +}); +*/ +exports.isWorn = function() { + return new Promise(resolve => { + if (Bangle.isCharging()) + return resolve(false); + if (Bangle.getHealthStatus().movement > 124) + return resolve(true); + return resolve(false); + }); +}; diff --git a/tests/Layout/bin/runalltests.sh b/tests/Layout/bin/runalltests.sh index 3a7aac50b..2d2985a4f 100755 --- a/tests/Layout/bin/runalltests.sh +++ b/tests/Layout/bin/runalltests.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash cd `dirname $0`/.. ls tests/*.js | xargs -I{} bin/runtest.sh {} diff --git a/tests/Layout/bin/runtest.sh b/tests/Layout/bin/runtest.sh index 9bac72283..f6c566d18 100755 --- a/tests/Layout/bin/runtest.sh +++ b/tests/Layout/bin/runtest.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Requires Linux x64 (for ./espruino) # Also imagemagick for display diff --git a/typescript/tsconfig.json b/tsconfig.json similarity index 85% rename from typescript/tsconfig.json rename to tsconfig.json index 1148c67c1..db3db1fc3 100644 --- a/typescript/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "noUnusedLocals": true, "noUnusedParameters": true, "strict": true, - "typeRoots": ["./types"] + "typeRoots": ["./typescript/types"] }, - "include": ["../apps/**/*", "./**/*"] + "include": ["./**/*"] } diff --git a/typescript/README.md b/typescript/README.md index a5bd69c04..7c1e21abd 100644 --- a/typescript/README.md +++ b/typescript/README.md @@ -1,7 +1,10 @@ # Bangle.ts -A generic project setup for compiling apps from Typescript to Bangle.js ready, readable JavaScript. -The types are now automatically generated by a script (see below), although they are still a work-in-progress. +A generic project setup for compiling apps from Typescript to +Bangle.js-ready, readable JavaScript. + +The types are now automatically generated by a script (see +[here](https://github.com/espruino/Espruino/blob/master/TYPESCRIPT.md). ## Compilation @@ -21,13 +24,3 @@ npm run build ``` To build all Typescript apps and widgets. The last command will generate the `app.js` files containing the transpiled code for the Bangle.js. - -## Generating types - -To generate the types, ensure this repository and [Espruino](https://github.com/espruino/Espruino) are in the same folder. From the Espruino folder run: - -``` -node scripts/build_types.js -``` - -This will update the file in `types/main.d.ts`. diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index 5a2ddd885..3e14741ee 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -2,10 +2,283 @@ /// +// TYPES + +/** + * Menu item that holds a boolean value. + */ +type MenuBooleanItem = { + value: boolean; + format?: (value: boolean) => string; + onchange?: (value: boolean) => void; +}; + +/** + * Menu item that holds a numerical value. + */ +type MenuNumberItem = { + value: number; + format?: (value: number) => string; + onchange?: (value: number) => void; + step?: number; + min?: number; + max?: number; + wrap?: boolean; +}; + +/** + * Options passed to a menu. + */ +type MenuOptions = { + title?: string; + back?: () => void; + selected?: number; + fontHeight?: number; + x?: number; + y?: number; + x2?: number; + y2?: number; + cB?: number; + cF?: number; + cHB?: number; + cHF?: number; + predraw?: (g: Graphics) => void; + preflip?: (g: Graphics, less: boolean, more: boolean) => void; +}; + +/** + * Object containing data about a menu to pass to `E.showMenu`. + */ +type Menu = { + ""?: MenuOptions; + [key: string]: + | MenuOptions + | (() => void) + | MenuBooleanItem + | MenuNumberItem + | { value: string; onchange?: () => void } + | undefined; +}; + +/** + * Menu instance. + */ +type MenuInstance = { + draw: () => void; + move: (n: number) => void; + select: () => void; +}; + +type ImageObject = { + width: number; + height: number; + bpp?: number; + buffer: ArrayBuffer | string; + transparent?: number; + palette?: Uint16Array; +}; + +type Image = string | ImageObject | ArrayBuffer | Graphics; + +type ColorResolvable = number | `#${string}`; + +type FontName = + | "4x4" + | "4x4Numeric" + | "4x5" + | "4x5Numeric" + | "4x8Numeric" + | "5x7Numeric7Seg" + | "5x9Numeric7Seg" + | "6x8" + | "6x12" + | "7x11Numeric7Seg" + | "8x12" + | "8x16" + | "Dennis8" + | "Cherry6x10" + | "Copasectic40x58Numeric" + | "Dylex7x13" + | "HaxorNarrow7x17" + | "Sinclair" + | "Teletext10x18Mode7" + | "Teletext5x9Ascii" + | "Teletext5x9Mode7" + | "Vector"; + +type FontNameWithScaleFactor = + | FontName + | `${FontName}:${number}` + | `${FontName}:${number}x${number}`; + +type Theme = { + fg: number; + bg: number; + fg2: number; + bg2: number; + fgH: number; + bgH: number; + dark: boolean; +}; + +type NRFFilters = { + services?: string[]; + name?: string; + namePrefix?: string; + id?: string; + serviceData?: object; + manufacturerData?: object; +}; + +declare const BTN1: Pin; +declare const BTN2: Pin; +declare const BTN3: Pin; +declare const BTN4: Pin; +declare const BTN5: Pin; + +declare const g: Graphics; + +type WidgetArea = "tl" | "tr" | "bl" | "br"; +type Widget = { + area: WidgetArea; + width: number; + draw: (this: { x: number; y: number }) => void; +}; +declare const WIDGETS: { [key: string]: Widget }; + +type AccelData = { + x: number; + y: number; + z: number; + diff: number; + mag: number; +}; + +type HealthStatus = { + movement: number; + steps: number; + bpm: number; + bpmConfidence: number; +}; + +type CompassData = { + x: number; + y: number; + z: number; + dx: number; + dy: number; + dz: number; + heading: number; +}; + +type GPSFix = { + lat: number; + lon: number; + alt: number; + speed: number; + course: number; + time: Date; + satellites: number; + fix: number; + hdop: number +}; + +type PressureData = { + temperature: number; + pressure: number; + altitude: number; +} + +type TapAxis = -2 | -1 | 0 | 1 | 2; + +type SwipeCallback = (directionLR: -1 | 0 | 1, directionUD?: -1 | 0 | 1) => void; + +type TouchCallback = (button: number, xy?: { x: number, y: number }) => void; + +type DragCallback = (event: { + x: number; + y: number; + dx: number; + dy: number; + b: 1 | 0; +}) => void; + +type LCDMode = + | "direct" + | "doublebuffered" + | "120x120" + | "80x80" + +type BangleOptions = { + wakeOnBTN1: boolean; + wakeOnBTN2: boolean; + wakeOnBTN3: boolean; + wakeOnFaceUp: boolean; + wakeOnTouch: boolean; + wakeOnTwist: boolean; + twistThreshold: number; + twistMaxY: number; + twistTimeout: number; + gestureStartThresh: number; + gestureEndThresh: number; + gestureInactiveCount: number; + gestureMinLength: number; + powerSave: boolean; + lockTimeout: number; + lcdPowerTimeout: number; + backlightTimeout: number; +}; + +interface ArrayLike { + readonly length: number; + readonly [n: number]: T; +} + +type PinMode = + | "analog" + | "input" + | "input_pullup" + | "input_pulldown" + | "output" + | "opendrain" + | "af_output" + | "af_opendrain"; + +type ErrorFlag = + | "FIFO_FULL" + | "BUFFER_FULL" + | "CALLBACK" + | "LOW_MEMORY" + | "MEMORY" + | "UART_OVERFLOW"; + +type Flag = + | "deepSleep" + | "pretokenise" + | "unsafeFlash" + | "unsyncFiles"; + +type Uint8ArrayResolvable = + | number + | string + | Uint8ArrayResolvable[] + | ArrayBuffer + | ArrayBufferView + | { data: Uint8ArrayResolvable, count: number } + | { callback: () => Uint8ArrayResolvable } + +type VariableSizeInformation = { + name: string; + size: number; + more?: VariableSizeInformation; +}; + + // CLASSES /** - * Class containing [micro:bit's](https://www.espruino.com/MicroBit) utility functions. + * Class containing [micro:bit's](https://www.espruino.com/MicroBit) utility + * functions. * @url http://www.espruino.com/Reference#Microbit */ declare class Microbit { @@ -32,7 +305,8 @@ declare class Microbit { static MIC_ENABLE: Pin; /** - * Called when the Micro:bit is moved in a deliberate fashion, and includes data on the detected gesture. + * Called when the Micro:bit is moved in a deliberate fashion, and includes data on + * the detected gesture. * @param {string} event - The event to listen to. * @param {(gesture: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `gesture` An Int8Array containing the accelerations (X,Y,Z) from the last gesture detected by the accelerometer @@ -53,28 +327,30 @@ declare class Microbit { static accel(): any; /** - * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) board + * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) + * board * Write the given value to the accelerometer * * @param {number} addr - Accelerometer address * @param {number} data - Data to write * @url http://www.espruino.com/Reference#l_Microbit_accelWr */ - static accelWr(addr: number, data: number): any; + static accelWr(addr: number, data: number): void; /** - * Turn on the accelerometer, and create `Microbit.accel` and `Microbit.gesture` events. - * **Note:** The accelerometer is currently always enabled - this code - * just responds to interrupts and reads + * Turn on the accelerometer, and create `Microbit.accel` and `Microbit.gesture` + * events. + * **Note:** The accelerometer is currently always enabled - this code just + * responds to interrupts and reads * @url http://www.espruino.com/Reference#l_Microbit_accelOn */ - static accelOn(): any; + static accelOn(): void; /** - * Turn off events from the accelerometer (started with `Microbit.accelOn`) + * Turn off events from the accelerometer (started with `Microbit.accelOn`) * @url http://www.espruino.com/Reference#l_Microbit_accelOff */ - static accelOff(): any; + static accelOff(): void; /** * Play a waveform on the Micro:bit's speaker @@ -84,7 +360,7 @@ declare class Microbit { * @param {any} callback - A function to call when playback is finished * @url http://www.espruino.com/Reference#l_Microbit_play */ - static play(waveform: any, samplesPerSecond: any, callback: any): any; + static play(waveform: any, samplesPerSecond: any, callback: any): void; /** * Records sound from the micro:bit's onboard microphone and returns the result @@ -94,7 +370,9 @@ declare class Microbit { * @param {any} [samples] - [optional] How many samples to record (6000 default) * @url http://www.espruino.com/Reference#l_Microbit_record */ - static record(samplesPerSecond: any, callback: any, samples?: any): any; + static record(samplesPerSecond: any, callback: any, samples?: any): void; + + } interface MathConstructor { @@ -172,7 +450,7 @@ interface MathConstructor { /** * - * @param {number} x - The value to get the arc tangent of + * @param {number} x - The value to get the arc tangent of * @returns {number} The arc tangent of x, between -PI/2 and PI/2 * @url http://www.espruino.com/Reference#l_Math_atan */ @@ -275,7 +553,8 @@ interface MathConstructor { log(x: number): number; /** - * DEPRECATED - Please use `E.clip()` instead. Clip a number to be between min and max (inclusive) + * DEPRECATED - Please use `E.clip()` instead. Clip a number to be between min and + * max (inclusive) * * @param {number} x - A floating point value to clip * @param {number} min - The smallest the value should be @@ -287,7 +566,8 @@ interface MathConstructor { /** * DEPRECATED - This is not part of standard JavaScript libraries - * Wrap a number around if it is less than 0 or greater than or equal to max. For instance you might do: ```Math.wrap(angleInDegrees, 360)``` + * Wrap a number around if it is less than 0 or greater than or equal to max. For + * instance you might do: ```Math.wrap(angleInDegrees, 360)``` * * @param {number} x - A floating point value to wrap * @param {number} max - The largest the value should be @@ -330,6 +610,8 @@ declare const Math: MathConstructor * @url http://www.espruino.com/Reference#TFMicroInterpreter */ declare class TFMicroInterpreter { + + /** * @returns {any} An arraybuffer referencing the input data * @url http://www.espruino.com/Reference#l_TFMicroInterpreter_getInput @@ -345,7 +627,7 @@ declare class TFMicroInterpreter { /** * @url http://www.espruino.com/Reference#l_TFMicroInterpreter_invoke */ - invoke(): any; + invoke(): void; } /** @@ -355,7 +637,8 @@ declare class TFMicroInterpreter { declare class Badge { /** * Capacitive sense - the higher the capacitance, the higher the number returned. - * Supply a corner number between 1 and 6, and an integer value will be returned that is proportional to the capacitance + * Supply a corner number between 1 and 6, and an integer value will be returned + * that is proportional to the capacitance * * @param {number} corner - The corner to use * @returns {number} Capacitive sense counter @@ -364,8 +647,8 @@ declare class Badge { static capSense(corner: number): number; /** - * Return an approximate battery percentage remaining based on - * a normal CR2032 battery (2.8 - 2.2v) + * Return an approximate battery percentage remaining based on a normal CR2032 + * battery (2.8 - 2.2v) * @returns {number} A percentage between 0 and 100 * @url http://www.espruino.com/Reference#l_Badge_getBatteryPercentage */ @@ -377,7 +660,9 @@ declare class Badge { * @param {number} c - Contrast between 0 and 1 * @url http://www.espruino.com/Reference#l_Badge_setContrast */ - static setContrast(c: number): any; + static setContrast(c: number): void; + + } /** @@ -388,40 +673,43 @@ declare class Puck { /** * Turn on the magnetometer, take a single reading, and then turn it off again. * An object of the form `{x,y,z}` is returned containing magnetometer readings. - * Due to residual magnetism in the Puck and magnetometer itself, with - * no magnetic field the Puck will not return `{x:0,y:0,z:0}`. - * Instead, it's up to you to figure out what the 'zero value' is for your - * Puck in your location and to then subtract that from the value returned. If - * you're not trying to measure the Earth's magnetic field then it's a good idea - * to just take a reading at startup and use that. + * Due to residual magnetism in the Puck and magnetometer itself, with no magnetic + * field the Puck will not return `{x:0,y:0,z:0}`. + * Instead, it's up to you to figure out what the 'zero value' is for your Puck in + * your location and to then subtract that from the value returned. If you're not + * trying to measure the Earth's magnetic field then it's a good idea to just take + * a reading at startup and use that. * With the aerial at the top of the board, the `y` reading is vertical, `x` is * horizontal, and `z` is through the board. * Readings are in increments of 0.1 micro Tesla (uT). The Earth's magnetic field - * varies from around 25-60 uT, so the reading will vary by 250 to 600 depending - * on location. + * varies from around 25-60 uT, so the reading will vary by 250 to 600 depending on + * location. * @returns {any} An Object `{x,y,z}` of magnetometer readings as integers * @url http://www.espruino.com/Reference#l_Puck_mag */ static mag(): any; /** - * Turn on the magnetometer, take a single temperature reading from the MAG3110 chip, and then turn it off again. + * Turn on the magnetometer, take a single temperature reading from the MAG3110 + * chip, and then turn it off again. * (If the magnetometer is already on, this just returns the last reading obtained) - * `E.getTemperature()` uses the microcontroller's temperature sensor, but this uses the magnetometer's. - * The reading obtained is an integer (so no decimal places), but the sensitivity is factory trimmed. to 1°C, however the temperature - * offset isn't - so absolute readings may still need calibrating. + * `E.getTemperature()` uses the microcontroller's temperature sensor, but this + * uses the magnetometer's. + * The reading obtained is an integer (so no decimal places), but the sensitivity + * is factory trimmed. to 1°C, however the temperature offset isn't - so + * absolute readings may still need calibrating. * @returns {number} Temperature in degrees C * @url http://www.espruino.com/Reference#l_Puck_magTemp */ static magTemp(): number; /** - * Called after `Puck.magOn()` every time magnetometer data - * is sampled. There is one argument which is an object - * of the form `{x,y,z}` containing magnetometer readings - * as integers (for more information see `Puck.mag()`). - * Check out [the Puck.js page on the magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information. + * Called after `Puck.magOn()` every time magnetometer data is sampled. There is + * one argument which is an object of the form `{x,y,z}` containing magnetometer + * readings as integers (for more information see `Puck.mag()`). + * Check out [the Puck.js page on the + * magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_Puck_mag @@ -430,12 +718,12 @@ declare class Puck { /** * Only on Puck.js v2.0 - * Called after `Puck.accelOn()` every time accelerometer data - * is sampled. There is one argument which is an object - * of the form `{acc:{x,y,z}, gyro:{x,y,z}}` containing the data. - * The data is as it comes off the accelerometer and is not - * scaled to 1g. For more information see `Puck.accel()` or - * [the Puck.js page on the magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals). + * Called after `Puck.accelOn()` every time accelerometer data is sampled. There is + * one argument which is an object of the form `{acc:{x,y,z}, gyro:{x,y,z}}` + * containing the data. + * The data is as it comes off the accelerometer and is not scaled to 1g. For more + * information see `Puck.accel()` or [the Puck.js page on the + * magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals). * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_Puck_accel @@ -443,8 +731,8 @@ declare class Puck { static on(event: "accel", callback: () => void): void; /** - * Turn the magnetometer on and start periodic sampling. Samples will then cause - * a 'mag' event on 'Puck': + * Turn the magnetometer on and start periodic sampling. Samples will then cause a + * 'mag' event on 'Puck': * ``` * Puck.magOn(); * Puck.on('mag', function(xyz) { @@ -454,8 +742,9 @@ declare class Puck { * // Turn events off with Puck.magOff(); * ``` * This call will be ignored if the sampling is already on. - * If given an argument, the sample rate is set (if not, it's at 0.63 Hz). - * The sample rate must be one of the following (resulting in the given power consumption): + * If given an argument, the sample rate is set (if not, it's at 0.63 Hz). The + * sample rate must be one of the following (resulting in the given power + * consumption): * * 80 Hz - 900uA * * 40 Hz - 550uA * * 20 Hz - 275uA @@ -467,38 +756,43 @@ declare class Puck { * * 0.31 Hz - 8uA * * 0.16 Hz - 8uA * * 0.08 Hz - 8uA - * When the battery level drops too low while sampling is turned on, - * the magnetometer may stop sampling without warning, even while other - * Puck functions continue uninterrupted. - * Check out [the Puck.js page on the magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information. + * When the battery level drops too low while sampling is turned on, the + * magnetometer may stop sampling without warning, even while other Puck functions + * continue uninterrupted. + * Check out [the Puck.js page on the + * magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information. * * @param {number} samplerate - The sample rate in Hz, or undefined * @url http://www.espruino.com/Reference#l_Puck_magOn */ - static magOn(samplerate: number): any; + static magOn(samplerate: number): void; /** * Turn the magnetometer off * @url http://www.espruino.com/Reference#l_Puck_magOff */ - static magOff(): any; + static magOff(): void; /** - * Writes a register on the LIS3MDL / MAX3110 Magnetometer. Can be used for configuring advanced functions. - * Check out [the Puck.js page on the magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information and links to modules that use this function. + * Writes a register on the LIS3MDL / MAX3110 Magnetometer. Can be used for + * configuring advanced functions. + * Check out [the Puck.js page on the + * magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information and links to modules that use this function. * * @param {number} reg * @param {number} data * @url http://www.espruino.com/Reference#l_Puck_magWr */ - static magWr(reg: number, data: number): any; + static magWr(reg: number, data: number): void; /** - * Reads a register from the LIS3MDL / MAX3110 Magnetometer. Can be used for configuring advanced functions. - * Check out [the Puck.js page on the magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information and links to modules that use this function. + * Reads a register from the LIS3MDL / MAX3110 Magnetometer. Can be used for + * configuring advanced functions. + * Check out [the Puck.js page on the + * magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information and links to modules that use this function. * * @param {number} reg * @returns {number} @@ -507,7 +801,8 @@ declare class Puck { static magRd(reg: number): number; /** - * On Puck.js v2.0 this will use the on-board PCT2075TP temperature sensor, but on Puck.js the less accurate on-chip Temperature sensor is used. + * On Puck.js v2.0 this will use the on-board PCT2075TP temperature sensor, but on + * Puck.js the less accurate on-chip Temperature sensor is used. * @returns {number} Temperature in degrees C * @url http://www.espruino.com/Reference#l_Puck_getTemperature */ @@ -524,7 +819,8 @@ declare class Puck { * * 416 Hz (with Gyro) (not recommended) * * 833 Hz (with Gyro) (not recommended) * * 1660 Hz (with Gyro) (not recommended) - * Once `Puck.accelOn()` is called, the `Puck.accel` event will be called each time data is received. `Puck.accelOff()` can be called to turn the accelerometer off. + * Once `Puck.accelOn()` is called, the `Puck.accel` event will be called each time + * data is received. `Puck.accelOff()` can be called to turn the accelerometer off. * For instance to light the red LED whenever Puck.js is face up: * ``` * Puck.on('accel', function(a) { @@ -532,48 +828,57 @@ declare class Puck { * }); * Puck.accelOn(); * ``` - * Check out [the Puck.js page on the accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information. + * Check out [the Puck.js page on the + * accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information. * * @param {number} samplerate - The sample rate in Hz, or undefined * @url http://www.espruino.com/Reference#l_Puck_accelOn */ - static accelOn(samplerate: number): any; + static accelOn(samplerate: number): void; /** * Turn the accelerometer off after it has been turned on by `Puck.accelOn()`. - * Check out [the Puck.js page on the accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information. + * Check out [the Puck.js page on the + * accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information. * @url http://www.espruino.com/Reference#l_Puck_accelOff */ - static accelOff(): any; + static accelOff(): void; /** * Turn on the accelerometer, take a single reading, and then turn it off again. * The values reported are the raw values from the chip. In normal configuration: - * * accelerometer: full-scale (32768) is 4g, so you need to divide by 8192 to get correctly scaled values - * * gyro: full-scale (32768) is 245 dps, so you need to divide by 134 to get correctly scaled values - * If taking more than one reading, we'd suggest you use `Puck.accelOn()` and the `Puck.accel` event. + * * accelerometer: full-scale (32768) is 4g, so you need to divide by 8192 to get + * correctly scaled values + * * gyro: full-scale (32768) is 245 dps, so you need to divide by 134 to get + * correctly scaled values + * If taking more than one reading, we'd suggest you use `Puck.accelOn()` and the + * `Puck.accel` event. * @returns {any} An Object `{acc:{x,y,z}, gyro:{x,y,z}}` of accelerometer/gyro readings * @url http://www.espruino.com/Reference#l_Puck_accel */ static accel(): any; /** - * Writes a register on the LSM6DS3TR-C Accelerometer. Can be used for configuring advanced functions. - * Check out [the Puck.js page on the accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information and links to modules that use this function. + * Writes a register on the LSM6DS3TR-C Accelerometer. Can be used for configuring + * advanced functions. + * Check out [the Puck.js page on the + * accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information and links to modules that use this function. * * @param {number} reg * @param {number} data * @url http://www.espruino.com/Reference#l_Puck_accelWr */ - static accelWr(reg: number, data: number): any; + static accelWr(reg: number, data: number): void; /** - * Reads a register from the LSM6DS3TR-C Accelerometer. Can be used for configuring advanced functions. - * Check out [the Puck.js page on the accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) - * for more information and links to modules that use this function. + * Reads a register from the LSM6DS3TR-C Accelerometer. Can be used for configuring + * advanced functions. + * Check out [the Puck.js page on the + * accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more + * information and links to modules that use this function. * * @param {number} reg * @returns {number} @@ -582,21 +887,21 @@ declare class Puck { static accelRd(reg: number): number; /** - * Transmit the given set of IR pulses - data should be an array of pulse times - * in milliseconds (as `[on, off, on, off, on, etc]`). + * Transmit the given set of IR pulses - data should be an array of pulse times in + * milliseconds (as `[on, off, on, off, on, etc]`). * For example `Puck.IR(pulseTimes)` - see http://www.espruino.com/Puck.js+Infrared * for a full example. - * You can also attach an external LED to Puck.js, in which case - * you can just execute `Puck.IR(pulseTimes, led_cathode, led_anode)` - * It is also possible to just supply a single pin for IR transmission - * with `Puck.IR(pulseTimes, led_anode)` (on 2v05 and above). + * You can also attach an external LED to Puck.js, in which case you can just + * execute `Puck.IR(pulseTimes, led_cathode, led_anode)` + * It is also possible to just supply a single pin for IR transmission with + * `Puck.IR(pulseTimes, led_anode)` (on 2v05 and above). * * @param {any} data - An array of pulse lengths, in milliseconds * @param {Pin} cathode - (optional) pin to use for IR LED cathode - if not defined, the built-in IR LED is used * @param {Pin} anode - (optional) pin to use for IR LED anode - if not defined, the built-in IR LED is used * @url http://www.espruino.com/Reference#l_Puck_IR */ - static IR(data: any, cathode: Pin, anode: Pin): any; + static IR(data: any, cathode: Pin, anode: Pin): void; /** * Capacitive sense - the higher the capacitance, the higher the number returned. @@ -604,11 +909,10 @@ declare class Puck { * attached to pin D11 will be returned. If you attach a length of wire to D11, * you'll be able to see a higher value returned when your hand is near the wire * than when it is away. - * You can also supply pins to use yourself, however if you do this then - * the TX pin must be connected to RX pin and sense plate via a roughly 1MOhm - * resistor. - * When not supplying pins, Puck.js uses an internal resistor between D12(tx) - * and D11(rx). + * You can also supply pins to use yourself, however if you do this then the TX pin + * must be connected to RX pin and sense plate via a roughly 1MOhm resistor. + * When not supplying pins, Puck.js uses an internal resistor between D12(tx) and + * D11(rx). * * @param {Pin} tx * @param {Pin} rx @@ -619,8 +923,8 @@ declare class Puck { /** * Return a light value based on the light the red LED is seeing. - * **Note:** If called more than 5 times per second, the received light value - * may not be accurate. + * **Note:** If called more than 5 times per second, the received light value may + * not be accurate. * @returns {number} A light value from 0 to 1 * @url http://www.espruino.com/Reference#l_Puck_light */ @@ -628,49 +932,57 @@ declare class Puck { /** * DEPRECATED - Please use `E.getBattery()` instead. - * Return an approximate battery percentage remaining based on - * a normal CR2032 battery (2.8 - 2.2v). + * Return an approximate battery percentage remaining based on a normal CR2032 + * battery (2.8 - 2.2v). * @returns {number} A percentage between 0 and 100 * @url http://www.espruino.com/Reference#l_Puck_getBatteryPercentage */ static getBatteryPercentage(): number; /** - * Run a self-test, and return true for a pass. This checks for shorts - * between pins, so your Puck shouldn't have anything connected to it. - * **Note:** This self-test auto starts if you hold the button on your Puck - * down while inserting the battery, leave it pressed for 3 seconds (while - * the green LED is lit) and release it soon after all LEDs turn on. 5 - * red blinks is a fail, 5 green is a pass. - * If the self test fails, it'll set the Puck.js Bluetooth advertising name - * to `Puck.js !ERR` where ERR is a 3 letter error code. + * Run a self-test, and return true for a pass. This checks for shorts between + * pins, so your Puck shouldn't have anything connected to it. + * **Note:** This self-test auto starts if you hold the button on your Puck down + * while inserting the battery, leave it pressed for 3 seconds (while the green LED + * is lit) and release it soon after all LEDs turn on. 5 red blinks is a fail, 5 + * green is a pass. + * If the self test fails, it'll set the Puck.js Bluetooth advertising name to + * `Puck.js !ERR` where ERR is a 3 letter error code. * @returns {boolean} True if the self-test passed * @url http://www.espruino.com/Reference#l_Puck_selfTest */ static selfTest(): boolean; + + } /** - * This is the File object - it allows you to stream data to and from files (As opposed to the `require('fs').readFile(..)` style functions that read an entire file). - * To create a File object, you must type ```var fd = E.openFile('filepath','mode')``` - see [E.openFile](#l_E_openFile) for more information. - * **Note:** If you want to remove an SD card after you have started using it, you *must* call `E.unmountSD()` or you may cause damage to the card. + * This is the File object - it allows you to stream data to and from files (As + * opposed to the `require('fs').readFile(..)` style functions that read an entire + * file). + * To create a File object, you must type ```var fd = + * E.openFile('filepath','mode')``` - see [E.openFile](#l_E_openFile) for more + * information. + * **Note:** If you want to remove an SD card after you have started using it, you + * *must* call `E.unmountSD()` or you may cause damage to the card. * @url http://www.espruino.com/Reference#File */ declare class File { + + /** * Close an open file. * @url http://www.espruino.com/Reference#l_File_close */ - close(): any; + close(): void; /** * Write data to a file. - * **Note:** By default this function flushes all changes to the - * SD card, which makes it slow (but also safe!). You can use - * `E.setFlags({unsyncFiles:1})` to disable this behaviour and - * really speed up writes - but then you must be sure to close - * all files you are writing before power is lost or you will - * cause damage to your SD card's filesystem. + * **Note:** By default this function flushes all changes to the SD card, which + * makes it slow (but also safe!). You can use `E.setFlags({unsyncFiles:1})` to + * disable this behaviour and really speed up writes - but then you must be sure to + * close all files you are writing before power is lost or you will cause damage to + * your SD card's filesystem. * * @param {any} buffer - A string containing the bytes to write * @returns {number} the number of bytes written @@ -693,7 +1005,7 @@ declare class File { * @param {number} nBytes - is a positive integer specifying the number of bytes to skip forwards. * @url http://www.espruino.com/Reference#l_File_skip */ - skip(nBytes: number): any; + skip(nBytes: number): void; /** * Seek to a certain position in the file @@ -701,7 +1013,7 @@ declare class File { * @param {number} nBytes - is an integer specifying the number of bytes to skip forwards. * @url http://www.espruino.com/Reference#l_File_seek */ - seek(nBytes: number): any; + seek(nBytes: number): void; /** * Pipe this file to a stream (an object with a 'write' method) @@ -714,7 +1026,7 @@ declare class File { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_File_pipe */ - pipe(destination: any, options: any): any; + pipe(destination: any, options: any): void; } /** @@ -730,24 +1042,26 @@ declare class WioLTE { * @param {number} blue - 0-255, blue LED intensity * @url http://www.espruino.com/Reference#l_WioLTE_LED */ - static LED(red: number, green: number, blue: number): any; + static LED(red: number, green: number, blue: number): void; /** - * Set the power of Grove connectors, except for `D38` and `D39` which are always on. + * Set the power of Grove connectors, except for `D38` and `D39` which are always + * on. * * @param {boolean} onoff - Whether to turn the Grove connectors power on or off (D38/D39 are always powered) * @url http://www.espruino.com/Reference#l_WioLTE_setGrovePower */ - static setGrovePower(onoff: boolean): any; + static setGrovePower(onoff: boolean): void; /** * Turn power to the WIO's LED on or off. - * Turning the LED on won't immediately display a color - that must be done with `WioLTE.LED(r,g,b)` + * Turning the LED on won't immediately display a color - that must be done with + * `WioLTE.LED(r,g,b)` * * @param {boolean} onoff - true = on, false = off * @url http://www.espruino.com/Reference#l_WioLTE_setLEDPower */ - static setLEDPower(onoff: boolean): any; + static setLEDPower(onoff: boolean): void; /** * @returns {any} @@ -784,17 +1098,20 @@ declare class WioLTE { * @url http://www.espruino.com/Reference#l_WioLTE_A4 */ static A4: any; + + } /** - * Class containing utility functions for [Pixl.js](http://www.espruino.com/Pixl.js) + * Class containing utility functions for + * [Pixl.js](http://www.espruino.com/Pixl.js) * @url http://www.espruino.com/Reference#Pixl */ declare class Pixl { /** * DEPRECATED - Please use `E.getBattery()` instead. - * Return an approximate battery percentage remaining based on - * a normal CR2032 battery (2.8 - 2.2v) + * Return an approximate battery percentage remaining based on a normal CR2032 + * battery (2.8 - 2.2v) * @returns {number} A percentage between 0 and 100 * @url http://www.espruino.com/Reference#l_Pixl_getBatteryPercentage */ @@ -806,7 +1123,7 @@ declare class Pixl { * @param {number} c - Contrast between 0 and 1 * @url http://www.espruino.com/Reference#l_Pixl_setContrast */ - static setContrast(c: number): any; + static setContrast(c: number): void; /** * This function can be used to turn Pixl.js's LCD off or on. @@ -816,7 +1133,7 @@ declare class Pixl { * @param {boolean} isOn - True if the LCD should be on, false if not * @url http://www.espruino.com/Reference#l_Pixl_setLCDPower */ - static setLCDPower(isOn: boolean): any; + static setLCDPower(isOn: boolean): void; /** * Writes a command directly to the ST7567 LCD controller @@ -824,21 +1141,28 @@ declare class Pixl { * @param {number} c * @url http://www.espruino.com/Reference#l_Pixl_lcdw */ - static lcdw(c: number): any; + static lcdw(c: number): void; /** - * Display a menu on Pixl.js's screen, and set up the buttons to navigate through it. + * Display a menu on Pixl.js's screen, and set up the buttons to navigate through + * it. * DEPRECATED: Use `E.showMenu` * * @param {any} menu - An object containing name->function mappings to to be used in a menu * @returns {any} A menu object with `draw`, `move` and `select` functions * @url http://www.espruino.com/Reference#l_Pixl_menu */ - static menu(menu: any): any; + static menu(menu: Menu): MenuInstance; + + } /** - * This class exists in order to interface Espruino with fast-moving trigger wheels. Trigger wheels are physical discs with evenly spaced teeth cut into them, and often with one or two teeth next to each other missing. A sensor sends a signal whenever a tooth passed by, and this allows a device to measure not only RPM, but absolute position. + * This class exists in order to interface Espruino with fast-moving trigger + * wheels. Trigger wheels are physical discs with evenly spaced teeth cut into + * them, and often with one or two teeth next to each other missing. A sensor sends + * a signal whenever a tooth passed by, and this allows a device to measure not + * only RPM, but absolute position. * This class is currently in testing - it is NOT AVAILABLE on normal boards. * @url http://www.espruino.com/Reference#Trig */ @@ -859,7 +1183,7 @@ declare class Trig { * @param {any} options - Additional options as an object. defaults are: ```{teethTotal:60,teethMissing:2,minRPM:30,keyPosition:0}``` * @url http://www.espruino.com/Reference#l_Trig_setup */ - static setup(pin: Pin, options: any): any; + static setup(pin: Pin, options: any): void; /** * Set a trigger for a certain point in the cycle @@ -870,7 +1194,7 @@ declare class Trig { * @param {number} pulseLength - The time (in msec) to pulse for * @url http://www.espruino.com/Reference#l_Trig_setTrigger */ - static setTrigger(num: number, pos: number, pins: any, pulseLength: number): any; + static setTrigger(num: number, pos: number, pins: any, pulseLength: number): void; /** * Disable a trigger @@ -878,7 +1202,7 @@ declare class Trig { * @param {number} num - The trigger number (0..7) * @url http://www.espruino.com/Reference#l_Trig_killTrigger */ - static killTrigger(num: number): any; + static killTrigger(num: number): void; /** * Get the current state of a trigger @@ -909,11 +1233,15 @@ declare class Trig { * @url http://www.espruino.com/Reference#l_Trig_getErrorArray */ static getErrorArray(): any; + + } /** * Class containing AES encryption/decryption - * **Note:** This library is currently only included in builds for boards where there is space. For other boards there is `crypto.js` which implements SHA1 in JS. + * **Note:** This library is currently only included in builds for boards where + * there is space. For other boards there is `crypto.js` which implements SHA1 in + * JS. * @url http://www.espruino.com/Reference#AES */ declare class AES { @@ -936,27 +1264,34 @@ declare class AES { * @url http://www.espruino.com/Reference#l_AES_decrypt */ static decrypt(passphrase: any, key: any, options: any): ArrayBuffer; + + } /** * This class provides Graphics operations that can be applied to a surface. - * Use Graphics.createXXX to create a graphics object that renders in the way you want. See [the Graphics page](https://www.espruino.com/Graphics) for more information. - * **Note:** On boards that contain an LCD, there is a built-in 'LCD' object of type Graphics. For instance to draw a line you'd type: ```LCD.drawLine(0,0,100,100)``` + * Use Graphics.createXXX to create a graphics object that renders in the way you + * want. See [the Graphics page](https://www.espruino.com/Graphics) for more + * information. + * **Note:** On boards that contain an LCD, there is a built-in 'LCD' object of + * type Graphics. For instance to draw a line you'd type: + * ```LCD.drawLine(0,0,100,100)``` * @url http://www.espruino.com/Reference#Graphics */ -declare class Graphics { +declare class Graphics { /** - * On devices like Pixl.js or HYSTM boards that contain a built-in display - * this will return an instance of the graphics class that can be used to - * access that display. + * On devices like Pixl.js or HYSTM boards that contain a built-in display this + * will return an instance of the graphics class that can be used to access that + * display. * Internally, this is stored as a member called `gfx` inside the 'hiddenRoot'. * @returns {any} An instance of `Graphics` or undefined * @url http://www.espruino.com/Reference#l_Graphics_getInstance */ - static getInstance(): any; + static getInstance(): Graphics | undefined /** - * Create a Graphics object that renders to an Array Buffer. This will have a field called 'buffer' that can get used to get at the buffer itself + * Create a Graphics object that renders to an Array Buffer. This will have a field + * called 'buffer' that can get used to get at the buffer itself * * @param {number} width - Pixels wide * @param {number} height - Pixels high @@ -971,10 +1306,11 @@ declare class Graphics { * @returns {any} The new Graphics object * @url http://www.espruino.com/Reference#l_Graphics_createArrayBuffer */ - static createArrayBuffer(width: number, height: number, bpp: number, options: any): Graphics; + static createArrayBuffer(width: number, height: number, bpp: number, options?: { zigzag?: boolean, vertical_byte?: boolean, msb?: boolean, color_order?: "rgb" | "rbg" | "brg" | "bgr" | "grb" | "gbr" }): Graphics; /** - * Create a Graphics object that renders by calling a JavaScript callback function to draw pixels + * Create a Graphics object that renders by calling a JavaScript callback function + * to draw pixels * * @param {number} width - Pixels wide * @param {number} height - Pixels high @@ -983,7 +1319,7 @@ declare class Graphics { * @returns {any} The new Graphics object * @url http://www.espruino.com/Reference#l_Graphics_createCallback */ - static createCallback(width: number, height: number, bpp: number, callback: any): Graphics; + static createCallback(width: number, height: number, bpp: number, callback: ((x: number, y: number, col: number) => void) | { setPixel: (x: number, y: number, col: number) => void; fillRect: (x1: number, y1: number, x2: number, y2: number, col: number) => void }): Graphics; /** * Create a Graphics object that renders to SDL window (Linux-based devices only) @@ -1010,14 +1346,16 @@ declare class Graphics { * `); * g.drawImage(img, x,y); * ``` - * If the characters at the beginning and end of the string are newlines, they - * will be ignored. Spaces are treated as `0`, and any other character is a `1` + * If the characters at the beginning and end of the string are newlines, they will + * be ignored. Spaces are treated as `0`, and any other character is a `1` * * @param {any} str - A String containing a newline-separated image - space is 0, anything else is 1 * @returns {any} An Image object that can be used with `Graphics.drawImage` * @url http://www.espruino.com/Reference#l_Graphics_createImage */ - static createImage(str: any): any;/** + static createImage(str: string): ImageObject; + + /** * Set the current font * * @param {number} scale - (optional) If >1 the font will be scaled up by that amount @@ -1036,34 +1374,28 @@ declare class Graphics { setFont12x20(scale: number): Graphics; /** - * On instances of graphics that drive a display with - * an offscreen buffer, calling this function will - * copy the contents of the offscreen buffer to the + * On instances of graphics that drive a display with an offscreen buffer, calling + * this function will copy the contents of the offscreen buffer to the screen. + * Call this when you have drawn something to Graphics and you want it shown on the * screen. - * Call this when you have drawn something to Graphics - * and you want it shown on the screen. - * If a display does not have an offscreen buffer, - * it may not have a `g.flip()` method. - * On Bangle.js 1, there are different graphics modes - * chosen with `Bangle.setLCDMode()`. The default mode - * is unbuffered and in this mode `g.flip()` does not - * affect the screen contents. - * On some devices, this command will attempt to - * only update the areas of the screen that have - * changed in order to increase speed. If you have - * accessed the `Graphics.buffer` directly then you - * may need to use `Graphics.flip(true)` to force - * a full update of the screen. + * If a display does not have an offscreen buffer, it may not have a `g.flip()` + * method. + * On Bangle.js 1, there are different graphics modes chosen with + * `Bangle.setLCDMode()`. The default mode is unbuffered and in this mode + * `g.flip()` does not affect the screen contents. + * On some devices, this command will attempt to only update the areas of the + * screen that have changed in order to increase speed. If you have accessed the + * `Graphics.buffer` directly then you may need to use `Graphics.flip(true)` to + * force a full update of the screen. * * @param {boolean} [all] - [optional] (only on some devices) If `true` then copy all pixels, not just those that have changed. * @url http://www.espruino.com/Reference#l_Graphics_flip */ - flip(all?: boolean): any; + flip(all?: boolean): void; /** - * On Graphics instances with an offscreen buffer, this - * is an `ArrayBuffer` that provides access to the underlying - * pixel data. + * On Graphics instances with an offscreen buffer, this is an `ArrayBuffer` that + * provides access to the underlying pixel data. * ``` * g=Graphics.createArrayBuffer(8,8,8) * g.drawLine(0,0,7,7) @@ -1081,7 +1413,7 @@ declare class Graphics { * @returns {any} An ArrayBuffer (or not defined on Graphics instances not created with `Graphics.createArrayBuffer`) * @url http://www.espruino.com/Reference#l_Graphics_buffer */ - buffer: any; + buffer: IsBuffer extends true ? ArrayBuffer : undefined /** * The width of this Graphics instance @@ -1099,18 +1431,18 @@ declare class Graphics { /** * The number of bits per pixel of this Graphics instance - * **Note:** Bangle.js 2 behaves a little differently here. The display - * is 3 bit, so `getBPP` returns 3 and `asBMP`/`asImage`/etc return 3 bit images. - * However in order to allow dithering, the colors returned by `Graphics.getColor` and `Graphics.theme` - * are actually 16 bits. + * **Note:** Bangle.js 2 behaves a little differently here. The display is 3 bit, + * so `getBPP` returns 3 and `asBMP`/`asImage`/etc return 3 bit images. However in + * order to allow dithering, the colors returned by `Graphics.getColor` and + * `Graphics.theme` are actually 16 bits. * @returns {number} The bits per pixel of this Graphics instance * @url http://www.espruino.com/Reference#l_Graphics_getBPP */ getBPP(): number; /** - * Reset the state of Graphics to the defaults (eg. Color, Font, etc) - * that would have been used when Graphics was initialised. + * Reset the state of Graphics to the defaults (e.g. Color, Font, etc) that would + * have been used when Graphics was initialised. * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_reset */ @@ -1119,11 +1451,11 @@ declare class Graphics { /** * Clear the LCD with the Background Color * - * @param {boolean} reset - If `true`, resets the state of Graphics to the default (eg. Color, Font, etc) as if calling `Graphics.reset` + * @param {boolean} [reset] - [optional] If `true`, resets the state of Graphics to the default (eg. Color, Font, etc) as if calling `Graphics.reset` * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_clear */ - clear(reset: boolean): Graphics; + clear(reset?: boolean): Graphics; /** * Fill a rectangular area in the Foreground Color @@ -1137,7 +1469,8 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_fillRect */ - fillRect(x1: any, y1: number, x2: number, y2: number): Graphics; + fillRect(x1: number, y1: number, x2: number, y2: number): Graphics; + fillRect(rect: { x: number, y: number, x2: number, y2: number } | { x: number, y: number, w: number, h: number }): Graphics; /** * Fill a rectangular area in the Background Color @@ -1151,7 +1484,8 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_clearRect */ - clearRect(x1: any, y1: number, x2: number, y2: number): Graphics; + clearRect(x1: number, y1: number, x2: number, y2: number): Graphics; + clearRect(rect: { x: number, y: number, x2: number, y2: number } | { x: number, y: number, w: number, h: number }): Graphics; /** * Draw an unfilled rectangle 1px wide in the Foreground Color @@ -1163,7 +1497,8 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_drawRect */ - drawRect(x1: any, y1: number, x2: number, y2: number): Graphics; + drawRect(x1: number, y1: number, x2: number, y2: number): Graphics; + drawRect(rect: { x: number, y: number, x2: number, y2: number } | { x: number, y: number, w: number, h: number }): Graphics; /** * Draw a filled circle in the Foreground Color @@ -1241,7 +1576,7 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setPixel */ - setPixel(x: number, y: number, col: any): Graphics; + setPixel(x: number, y: number, col?: ColorResolvable): Graphics; /** * Work out the color value to be used in the current bit depth based on the arguments. @@ -1259,7 +1594,8 @@ declare class Graphics { * @returns {number} The color index represented by the arguments * @url http://www.espruino.com/Reference#l_Graphics_toColor */ - toColor(r: any, g: any, b: any): number; + toColor(r: number, g: number, b: number): number; + toColor(col: ColorResolvable): number; /** * Blend between two colors, and return the result. @@ -1278,7 +1614,7 @@ declare class Graphics { * @returns {number} The color index represented by the blended colors * @url http://www.espruino.com/Reference#l_Graphics_blendColor */ - blendColor(col_a: any, col_b: any, amt: any): number; + blendColor(col_a: ColorResolvable, col_b: ColorResolvable, amt: number): number; /** * Set the color to use for subsequent drawing operations. @@ -1299,7 +1635,8 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setColor */ - setColor(r: any, g?: any, b?: any): Graphics; + setColor(r: number, g: number, b: number): number; + setColor(col: ColorResolvable): number; /** * Set the background color to use for subsequent drawing operations. @@ -1313,7 +1650,8 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setBgColor */ - setBgColor(r: any, g: any, b: any): Graphics; + setBgColor(r: number, g: number, b: number): number; + setBgColor(col: ColorResolvable): number; /** * Get the color to use for subsequent drawing operations @@ -1330,14 +1668,15 @@ declare class Graphics { getBgColor(): number; /** - * This sets the 'clip rect' that subsequent drawing operations are clipped to - * sit between. - * These values are inclusive - eg `g.setClipRect(1,0,5,0)` will ensure that only + * This sets the 'clip rect' that subsequent drawing operations are clipped to sit + * between. + * These values are inclusive - e.g. `g.setClipRect(1,0,5,0)` will ensure that only * pixel rows 1,2,3,4,5 are touched on column 0. - * **Note:** For maximum flexibility on Bangle.js 1, the values here are not range checked. For normal - * use, X and Y should be between 0 and `getWidth()-1`/`getHeight()-1`. - * **Note:** The x/y values here are rotated, so that if `Graphics.setRotation` is used - * they correspond to the coordinates given to the draw functions, *not to the + * **Note:** For maximum flexibility on Bangle.js 1, the values here are not range + * checked. For normal use, X and Y should be between 0 and + * `getWidth()-1`/`getHeight()-1`. + * **Note:** The x/y values here are rotated, so that if `Graphics.setRotation` is + * used they correspond to the coordinates given to the draw functions, *not to the * physical device pixels*. * * @param {number} x1 - Top left X coordinate @@ -1359,7 +1698,8 @@ declare class Graphics { /** * Make subsequent calls to `drawString` use a Vector Font of the given height. - * It is recommended that you use `Graphics.setFont("Vector", size)` for more flexibility. + * It is recommended that you use `Graphics.setFont("Vector", size)` for more + * flexibility. * * @param {number} size - The height of the font, as an integer * @returns {any} The instance of Graphics this was called on, to allow call chaining @@ -1368,11 +1708,14 @@ declare class Graphics { setFontVector(size: number): Graphics; /** - * Make subsequent calls to `drawString` use a Custom Font of the given height. See the [Fonts page](http://www.espruino.com/Fonts) for more - * information about custom fonts and how to create them. - * For examples of use, see the [font modules](https://www.espruino.com/Fonts#font-modules). - * **Note:** while you can specify the character code of the first character with `firstChar`, - * the newline character 13 will always be treated as a newline and not rendered. + * Make subsequent calls to `drawString` use a Custom Font of the given height. See + * the [Fonts page](http://www.espruino.com/Fonts) for more information about + * custom fonts and how to create them. + * For examples of use, see the [font + * modules](https://www.espruino.com/Fonts#font-modules). + * **Note:** while you can specify the character code of the first character with + * `firstChar`, the newline character 13 will always be treated as a newline and + * not rendered. * * @param {any} bitmap - A column-first, MSB-first, 1bpp bitmap containing the font bitmap * @param {number} firstChar - The first character in the font - usually 32 (space) @@ -1381,7 +1724,7 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setFontCustom */ - setFontCustom(bitmap: any, firstChar: number, width: any, height: number): Graphics; + setFontCustom(bitmap: ArrayBuffer, firstChar: number, width: number | string, height: number): Graphics; /** * Set the alignment for subsequent calls to `drawString` @@ -1392,7 +1735,7 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setFontAlign */ - setFontAlign(x: number, y: number, rotation: number): Graphics; + setFontAlign(x: -1 | 0 | 1, y?: -1 | 0 | 1, rotation?: 0 | 1 | 2 | 3): Graphics; /** * Set the font by name. Various forms are available: @@ -1411,27 +1754,28 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setFont */ - setFont(name: any, size: number): Graphics; + setFont(name: FontNameWithScaleFactor): Graphics; + setFont(name: FontName, size: number): Graphics; /** * Get the font by name - can be saved and used with `Graphics.setFont`. - * Normally this might return something like `"4x6"`, but if a scale - * factor is specified, a colon and then the size is reported, like "4x6:2" - * **Note:** For custom fonts, `Custom` is currently - * reported instead of the font name. + * Normally this might return something like `"4x6"`, but if a scale factor is + * specified, a colon and then the size is reported, like "4x6:2" + * **Note:** For custom fonts, `Custom` is currently reported instead of the font + * name. * @returns {any} Get the name of the current font * @url http://www.espruino.com/Reference#l_Graphics_getFont */ - getFont(): String; + getFont(): FontNameWithScaleFactor | "Custom" /** * Return an array of all fonts currently in the Graphics library. - * **Note:** Vector fonts are specified as `Vector#` where `#` is the font height. As there - * are effectively infinite fonts, just `Vector` is included in the list. + * **Note:** Vector fonts are specified as `Vector#` where `#` is the font height. + * As there are effectively infinite fonts, just `Vector` is included in the list. * @returns {any} And array of font names * @url http://www.espruino.com/Reference#l_Graphics_getFonts */ - getFonts(): any[]; + getFonts(): FontName[]; /** * Return the height in pixels of the current font @@ -1447,7 +1791,7 @@ declare class Graphics { * @returns {number} The length of the string in pixels * @url http://www.espruino.com/Reference#l_Graphics_stringWidth */ - stringWidth(str: any): number; + stringWidth(str: string): number; /** * Return the width and height in pixels of a string of text in the current font @@ -1456,7 +1800,7 @@ declare class Graphics { * @returns {any} An object containing `{width,height}` of the string * @url http://www.espruino.com/Reference#l_Graphics_stringMetrics */ - stringMetrics(str: any): any; + stringMetrics(str: string): { width: number, height: number }; /** * Wrap a string to the given pixel width using the current font, and return the @@ -1471,16 +1815,16 @@ declare class Graphics { * @returns {any} An array of lines that are all less than `maxWidth` * @url http://www.espruino.com/Reference#l_Graphics_wrapString */ - wrapString(str: any, maxWidth: number): any; + wrapString(str: string, maxWidth: number): string[]; /** * Draw a string of text in the current font. * ``` * g.drawString("Hello World", 10, 10); * ``` - * Images may also be embedded inside strings (eg to render Emoji or characters not in the current font). - * To do this, just add `0` then the image string ([about Images](http://www.espruino.com/Graphics#images-bitmaps)) - * For example: + * Images may also be embedded inside strings (e.g. to render Emoji or characters + * not in the current font). To do this, just add `0` then the image string ([about + * Images](http://www.espruino.com/Graphics#images-bitmaps)) For example: * ``` * g.drawString("Hi \0\7\5\1\x82 D\x17\xC0"); * // draws: @@ -1498,7 +1842,7 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_drawString */ - drawString(str: any, x: number, y: number, solid: boolean): Graphics; + drawString(str: string, x: number, y: number, solid?: boolean): Graphics; /** * Draw a line between x1,y1 and x2,y2 in the current foreground color @@ -1525,7 +1869,7 @@ declare class Graphics { drawLineAA(x1: number, y1: number, x2: number, y2: number): Graphics; /** - * Draw a line from the last position of lineTo or moveTo to this position + * Draw a line from the last position of `lineTo` or `moveTo` to this position * * @param {number} x - X value * @param {number} y - Y value @@ -1545,7 +1889,8 @@ declare class Graphics { moveTo(x: number, y: number): Graphics; /** - * Draw a polyline (lines between each of the points in `poly`) in the current foreground color + * Draw a polyline (lines between each of the points in `poly`) in the current + * foreground color * **Note:** there is a limit of 64 points (128 XY elements) for polygons * * @param {any} poly - An array of vertices, of the form ```[x1,y1,x2,y2,x3,y3,etc]``` @@ -1553,10 +1898,11 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_drawPoly */ - drawPoly(poly: any, closed: boolean): Graphics; + drawPoly(poly: number[], closed?: boolean): Graphics; /** - * Draw an **antialiased** polyline (lines between each of the points in `poly`) in the current foreground color + * Draw an **antialiased** polyline (lines between each of the points in `poly`) in + * the current foreground color * **Note:** there is a limit of 64 points (128 XY elements) for polygons * * @param {any} poly - An array of vertices, of the form ```[x1,y1,x2,y2,x3,y3,etc]``` @@ -1564,7 +1910,7 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_drawPolyAA */ - drawPolyAA(poly: any, closed: boolean): Graphics; + drawPolyAA(poly: number[], closed?: boolean): Graphics; /** * Draw a filled polygon in the current foreground color. @@ -1577,17 +1923,17 @@ declare class Graphics { * 6, 28, * 0, 27 ]); * ``` - * This fills from the top left hand side of the polygon (low X, low Y) - * *down to but not including* the bottom right. When placed together polygons - * will align perfectly without overdraw - but this will not fill the - * same pixels as `drawPoly` (drawing a line around the edge of the polygon). + * This fills from the top left hand side of the polygon (low X, low Y) *down to + * but not including* the bottom right. When placed together polygons will align + * perfectly without overdraw - but this will not fill the same pixels as + * `drawPoly` (drawing a line around the edge of the polygon). * **Note:** there is a limit of 64 points (128 XY elements) for polygons * * @param {any} poly - An array of vertices, of the form ```[x1,y1,x2,y2,x3,y3,etc]``` * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_fillPoly */ - fillPoly(poly: any): Graphics; + fillPoly(poly: number[]): Graphics; /** * Draw a filled polygon in the current foreground color. @@ -1600,17 +1946,17 @@ declare class Graphics { * 6, 28, * 0, 27 ]); * ``` - * This fills from the top left hand side of the polygon (low X, low Y) - * *down to but not including* the bottom right. When placed together polygons - * will align perfectly without overdraw - but this will not fill the - * same pixels as `drawPoly` (drawing a line around the edge of the polygon). + * This fills from the top left hand side of the polygon (low X, low Y) *down to + * but not including* the bottom right. When placed together polygons will align + * perfectly without overdraw - but this will not fill the same pixels as + * `drawPoly` (drawing a line around the edge of the polygon). * **Note:** there is a limit of 64 points (128 XY elements) for polygons * * @param {any} poly - An array of vertices, of the form ```[x1,y1,x2,y2,x3,y3,etc]``` * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_fillPolyAA */ - fillPolyAA(poly: any): Graphics; + fillPolyAA(poly: number[]): Graphics; /** * Set the current rotation of the graphics device. @@ -1620,34 +1966,47 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setRotation */ - setRotation(rotation: number, reflect: boolean): Graphics; + setRotation(rotation: 0 | 1 | 2 | 3, reflect?: boolean): Graphics; /** - * Return the width and height in pixels of an image (either Graphics, Image Object, Image String or ArrayBuffer). Returns - * `undefined` if image couldn't be decoded. - * `frames` is also included is the image contains more information than you'd expect for a single bitmap. In - * this case the bitmap might be an animation with multiple frames + * Return the width and height in pixels of an image (either Graphics, Image + * Object, Image String or ArrayBuffer). Returns `undefined` if image couldn't be + * decoded. + * `frames` is also included is the image contains more information than you'd + * expect for a single bitmap. In this case the bitmap might be an animation with + * multiple frames * * @param {any} str - The string * @returns {any} An object containing `{width,height,bpp,transparent}` for the image * @url http://www.espruino.com/Reference#l_Graphics_imageMetrics */ - imageMetrics(str: any): any; + imageMetrics(img: Image): { width: number, height: number, bpp: number, transparent: number, frames?: ArrayBuffer[] } | undefined; /** * Image can be: - * * An object with the following fields `{ width : int, height : int, bpp : optional int, buffer : ArrayBuffer/String, transparent: optional int, palette : optional Uint16Array(2/4/16) }`. bpp = bits per pixel (default is 1), transparent (if defined) is the colour that will be treated as transparent, and palette is a color palette that each pixel will be looked up in first - * * A String where the the first few bytes are: `width,height,bpp,[transparent,]image_bytes...`. If a transparent colour is specified the top bit of `bpp` should be set. - * * An ArrayBuffer Graphics object (if `bpp<8`, `msb:true` must be set) - this is disabled on devices without much flash memory available + * * An object with the following fields `{ width : int, height : int, bpp : + * optional int, buffer : ArrayBuffer/String, transparent: optional int, + * palette : optional Uint16Array(2/4/16) }`. bpp = bits per pixel (default is + * 1), transparent (if defined) is the colour that will be treated as + * transparent, and palette is a color palette that each pixel will be looked up + * in first + * * A String where the the first few bytes are: + * `width,height,bpp,[transparent,]image_bytes...`. If a transparent colour is + * specified the top bit of `bpp` should be set. + * * An ArrayBuffer Graphics object (if `bpp<8`, `msb:true` must be set) - this is + * disabled on devices without much flash memory available * Draw an image at the specified position. - * * If the image is 1 bit, the graphics foreground/background colours will be used. - * * If `img.palette` is a Uint16Array or 2/4/16 elements, color data will be looked from the supplied palette + * * If the image is 1 bit, the graphics foreground/background colours will be + * used. + * * If `img.palette` is a Uint16Array or 2/4/16 elements, color data will be + * looked from the supplied palette * * On Bangle.js, 2 bit images blend from background(0) to foreground(1) colours * * On Bangle.js, 4 bit images use the Apple Mac 16 color palette * * On Bangle.js, 8 bit images use the Web Safe 216 color palette * * Otherwise color data will be copied as-is. Bitmaps are rendered MSB-first - * If `options` is supplied, `drawImage` will allow images to be rendered at any scale or angle. If `options.rotate` is set it will - * center images at `x,y`. `options` must be an object of the form: + * If `options` is supplied, `drawImage` will allow images to be rendered at any + * scale or angle. If `options.rotate` is set it will center images at `x,y`. + * `options` must be an object of the form: * ``` * { * rotate : float, // the amount to rotate the image in radians (default 0) @@ -1674,7 +2033,7 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_drawImage */ - drawImage(image: any, x: number, y: number, options: any): Graphics; + drawImage(image: Image, x: number, y: number, options?: { rotate?: number, scale?: number, frame?: number }): Graphics; /** * Draws multiple images *at once* - which avoids flicker on unbuffered systems @@ -1702,43 +2061,45 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_drawImages */ - drawImages(layers: any, options: any): Graphics; + drawImages(layers: { x: number, y: number, image: Image, scale?: number, rotate?: number, center?: boolean, repeat?: boolean, nobounds?: boolean }[], options?: { x: number, y: number, width: number, height: number }): Graphics; /** - * Return this Graphics object as an Image that can be used with `Graphics.drawImage`. - * Check out [the Graphics reference page](http://www.espruino.com/Graphics#images-bitmaps) - * for more information on images. + * Return this Graphics object as an Image that can be used with + * `Graphics.drawImage`. Check out [the Graphics reference + * page](http://www.espruino.com/Graphics#images-bitmaps) for more information on + * images. * Will return undefined if data can't be allocated for the image. * The image data itself will be referenced rather than copied if: * * An image `object` was requested (not `string`) * * The Graphics instance was created with `Graphics.createArrayBuffer` * * Is 8 bpp *OR* the `{msb:true}` option was given * * No other format options (zigzag/etc) were given - * Otherwise data will be copied, which takes up more space and - * may be quite slow. + * Otherwise data will be copied, which takes up more space and may be quite slow. * * @param {any} type - The type of image to return. Either `object`/undefined to return an image object, or `string` to return an image string * @returns {any} An Image that can be used with `Graphics.drawImage` * @url http://www.espruino.com/Reference#l_Graphics_asImage */ - asImage(type: any): any; + asImage(type?: "object"): ImageObject; + asImage(type: "string"): string; /** - * Return the area of the Graphics canvas that has been modified, and optionally clear - * the modified area to 0. - * For instance if `g.setPixel(10,20)` was called, this would return `{x1:10, y1:20, x2:10, y2:20}` + * Return the area of the Graphics canvas that has been modified, and optionally + * clear the modified area to 0. + * For instance if `g.setPixel(10,20)` was called, this would return `{x1:10, + * y1:20, x2:10, y2:20}` * * @param {boolean} reset - Whether to reset the modified area or not * @returns {any} An object {x1,y1,x2,y2} containing the modified area, or undefined if not modified * @url http://www.espruino.com/Reference#l_Graphics_getModified */ - getModified(reset: boolean): any; + getModified(reset?: boolean): { x1: number, y1: number, x2: number, y2: number }; /** * Scroll the contents of this graphics in a certain direction. The remaining area * is filled with the background color. - * Note: This uses repeated pixel reads and writes, so will not work on platforms that - * don't support pixel reads. + * Note: This uses repeated pixel reads and writes, so will not work on platforms + * that don't support pixel reads. * * @param {number} x - X direction. >0 = to right * @param {number} y - Y direction. >0 = down @@ -1757,44 +2118,50 @@ declare class Graphics { * setModified : true // should we set the modified area? * }); * ``` - * Note: This uses repeated pixel reads and writes, so will not work on platforms that - * don't support pixel reads. + * Note: This uses repeated pixel reads and writes, so will not work on platforms + * that don't support pixel reads. * * @param {any} options - options - see below * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_blit */ - blit(options: any): Graphics; + blit(options: { x1: number, y1: number, x2: number, y2: number, w: number, h: number, setModified?: boolean }): Graphics; /** - * Create a Windows BMP file from this Graphics instance, and return it as a String. + * Create a Windows BMP file from this Graphics instance, and return it as a + * String. * @returns {any} A String representing the Graphics as a Windows BMP file (or 'undefined' if not possible) * @url http://www.espruino.com/Reference#l_Graphics_asBMP */ - asBMP(): any; + asBMP(): string; /** - * Create a URL of the form `data:image/bmp;base64,...` that can be pasted into the browser. - * The Espruino Web IDE can detect this data on the console and render the image inline automatically. + * Create a URL of the form `data:image/bmp;base64,...` that can be pasted into the + * browser. + * The Espruino Web IDE can detect this data on the console and render the image + * inline automatically. * @returns {any} A String representing the Graphics as a URL (or 'undefined' if not possible) * @url http://www.espruino.com/Reference#l_Graphics_asURL */ - asURL(): any; + asURL(): string; /** - * Output this image as a bitmap URL of the form `data:image/bmp;base64,...`. The Espruino Web IDE will detect this on the console and will render the image inline automatically. - * This is identical to `console.log(g.asURL())` - it is just a convenient function for easy debugging and producing screenshots of what is currently in the Graphics instance. - * **Note:** This may not work on some bit depths of Graphics instances. It will also not work for the main Graphics instance - * of Bangle.js 1 as the graphics on Bangle.js 1 are stored in write-only memory. + * Output this image as a bitmap URL of the form `data:image/bmp;base64,...`. The + * Espruino Web IDE will detect this on the console and will render the image + * inline automatically. + * This is identical to `console.log(g.asURL())` - it is just a convenient function + * for easy debugging and producing screenshots of what is currently in the + * Graphics instance. + * **Note:** This may not work on some bit depths of Graphics instances. It will + * also not work for the main Graphics instance of Bangle.js 1 as the graphics on + * Bangle.js 1 are stored in write-only memory. * @url http://www.espruino.com/Reference#l_Graphics_dump */ - dump(): any; + dump(): void; /** * Calculate the square area under a Bezier curve. - * x0,y0: start point - * x1,y1: control point - * y2,y2: end point + * x0,y0: start point x1,y1: control point y2,y2: end point * Max 10 points without start point. * * @param {any} arr - An array of three vertices, six enties in form of ```[x0,y0,x1,y1,x2,y2]``` @@ -1802,7 +2169,7 @@ declare class Graphics { * @returns {any} Array with calculated points * @url http://www.espruino.com/Reference#l_Graphics_quadraticBezier */ - quadraticBezier(arr: any, options: any): any; + quadraticBezier(arr: [number, number, number, number, number, number], options?: number): number[]; /** * Transformation can be: @@ -1828,7 +2195,7 @@ declare class Graphics { * @returns {any} Array of transformed vertices * @url http://www.espruino.com/Reference#l_Graphics_transformVertices */ - transformVertices(verts: any, transformation: any): any; + transformVertices(arr: number[], transformation: { x?: number, y?: number, scale?: number, rotate?: number } | [number, number, number, number, number, number]): number[]; /** * Returns an object of the form: @@ -1840,22 +2207,26 @@ declare class Graphics { * bg2 : 0x0007, // accented background colour * fgH : 0xFFFF, // highlighted foreground colour * bgH : 0x02F7, // highlighted background colour - * dark : true, // Is background dark (eg. foreground should be a light colour) + * dark : true, // Is background dark (e.g. foreground should be a light colour) * } * ``` - * These values can then be passed to `g.setColor`/`g.setBgColor` for example `g.setColor(g.theme.fg2)`. When the Graphics - * instance is reset, the background color is automatically set to `g.theme.bg` and foreground is set to `g.theme.fg`. - * On Bangle.js these values can be changed by writing updated values to `theme` in `settings.js` and reloading the app - or they can - * be changed temporarily by calling `Graphics.setTheme` + * These values can then be passed to `g.setColor`/`g.setBgColor` for example + * `g.setColor(g.theme.fg2)`. When the Graphics instance is reset, the background + * color is automatically set to `g.theme.bg` and foreground is set to + * `g.theme.fg`. + * On Bangle.js these values can be changed by writing updated values to `theme` in + * `settings.js` and reloading the app - or they can be changed temporarily by + * calling `Graphics.setTheme` * @returns {any} An object containing the current 'theme' (see below) * @url http://www.espruino.com/Reference#l_Graphics_theme */ - theme: any; + theme: Theme; /** - * Set the global colour scheme. On Bangle.js, this is reloaded from `settings.json` for each new app loaded. - * See `Graphics.theme` for the fields that can be provided. For instance you can change - * the background to red using: + * Set the global colour scheme. On Bangle.js, this is reloaded from + * `settings.json` for each new app loaded. + * See `Graphics.theme` for the fields that can be provided. For instance you can + * change the background to red using: * ``` * g.setTheme({bg:"#f00"}); * ``` @@ -1864,18 +2235,20 @@ declare class Graphics { * @returns {any} The instance of Graphics this was called on, to allow call chaining * @url http://www.espruino.com/Reference#l_Graphics_setTheme */ - setTheme(theme: any): Graphics; + setTheme(theme: { [key in keyof Theme]?: Theme[key] extends number ? ColorResolvable : Theme[key] }): Graphics; } /** - * This class helps to convert URLs into Objects of information ready for http.request/get + * This class helps to convert URLs into Objects of information ready for + * http.request/get * @url http://www.espruino.com/Reference#url */ declare class url { /** * A utility function to split a URL into parts * This is useful in web servers for instance when handling a request. - * For instance `url.parse("/a?b=c&d=e",true)` returns `{"method":"GET","host":"","path":"/a?b=c&d=e","pathname":"/a","search":"?b=c&d=e","port":80,"query":{"b":"c","d":"e"}}` + * For instance `url.parse("/a?b=c&d=e",true)` returns + * `{"method":"GET","host":"","path":"/a?b=c&d=e","pathname":"/a","search":"?b=c&d=e","port":80,"query":{"b":"c","d":"e"}}` * * @param {any} urlStr - A URL to be parsed * @param {boolean} parseQuery - Whether to parse the query string into an object not (default = false) @@ -1883,6 +2256,8 @@ declare class url { * @url http://www.espruino.com/Reference#l_url_parse */ static parse(urlStr: any, parseQuery: boolean): any; + + } /** @@ -1890,6 +2265,8 @@ declare class url { * @url http://www.espruino.com/Reference#Server */ declare class Server { + + /** * Start listening for new connections on the given port * @@ -1903,7 +2280,7 @@ declare class Server { * Stop listening for new connections * @url http://www.espruino.com/Reference#l_Server_close */ - close(): any; + close(): void; } /** @@ -1912,7 +2289,9 @@ declare class Server { */ declare class Socket { /** - * The 'data' event is called when data is received. If a handler is defined with `X.on('data', function(data) { ... })` then it will be called, otherwise data will be stored in an internal buffer, where it can be retrieved with `X.read()` + * The 'data' event is called when data is received. If a handler is defined with + * `X.on('data', function(data) { ... })` then it will be called, otherwise data + * will be stored in an internal buffer, where it can be retrieved with `X.read()` * @param {string} event - The event to listen to. * @param {(data: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `data` A string containing one or more characters of received data @@ -1930,9 +2309,11 @@ declare class Socket { static on(event: "close", callback: (had_error: any) => void): void; /** - * There was an error on this socket and it is closing (or wasn't opened in the first place). If a "connected" event was issued on this socket then the error event is always followed by a close event. - * The error codes are: - * * -1: socket closed (this is not really an error and will not cause an error callback) + * There was an error on this socket and it is closing (or wasn't opened in the + * first place). If a "connected" event was issued on this socket then the error + * event is always followed by a close event. The error codes are: + * * -1: socket closed (this is not really an error and will not cause an error + * callback) * * -2: out of memory (typically while allocating a buffer to hold data) * * -3: timeout * * -4: no route @@ -1954,13 +2335,17 @@ declare class Socket { static on(event: "error", callback: (details: any) => void): void; /** - * An event that is fired when the buffer is empty and it can accept more data to send. + * An event that is fired when the buffer is empty and it can accept more data to + * send. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_Socket_drain */ - static on(event: "drain", callback: () => void): void;/** - * Return how many bytes are available to read. If there is already a listener for data, this will always return 0. + static on(event: "drain", callback: () => void): void; + + /** + * Return how many bytes are available to read. If there is already a listener for + * data, this will always return 0. * @returns {number} How many bytes are available * @url http://www.espruino.com/Reference#l_Socket_available */ @@ -1986,7 +2371,7 @@ declare class Socket { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_Socket_pipe */ - pipe(destination: any, options: any): any; + pipe(destination: any, options: any): void; /** * This function writes the `data` argument as a string. Data that is passed in @@ -1994,8 +2379,8 @@ declare class Socket { * `toString` method. * If you wish to send binary data then you need to convert that data directly to a * String. This can be done with `String.fromCharCode`, however it's often easier - * and faster to use the Espruino-specific `E.toString`, which will read its arguments - * as an array of bytes and convert that to a String: + * and faster to use the Espruino-specific `E.toString`, which will read its + * arguments as an array of bytes and convert that to a String: * ``` * socket.write(E.toString([0,1,2,3,4,5])); * ``` @@ -2021,7 +2406,7 @@ declare class Socket { * @param {any} data - A string containing data to send * @url http://www.espruino.com/Reference#l_Socket_end */ - end(data: any): any; + end(data: any): void; } /** @@ -2030,7 +2415,8 @@ declare class Socket { */ declare class dgramSocket { /** - * The 'message' event is called when a datagram message is received. If a handler is defined with `X.on('message', function(msg) { ... })` then it will be called` + * The 'message' event is called when a datagram message is received. If a handler + * is defined with `X.on('message', function(msg) { ... })` then it will be called` * @param {string} event - The event to listen to. * @param {(msg: any, rinfo: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `msg` A string containing the received message @@ -2046,7 +2432,9 @@ declare class dgramSocket { * * `had_error` A boolean indicating whether the connection had an error (use an error event handler to get error details). * @url http://www.espruino.com/Reference#l_dgramSocket_close */ - static on(event: "close", callback: (had_error: any) => void): void;/** + static on(event: "close", callback: (had_error: any) => void): void; + + /** * * @param {any} buffer - A string containing message to send * @param {any} offset - Offset in the passed string where the message starts [optional] @@ -2054,7 +2442,7 @@ declare class dgramSocket { * @param {any} args - Destination port number, Destination IP address string * @url http://www.espruino.com/Reference#l_dgramSocket_send */ - send(buffer: any, offset: any, length: any, ...args: any[]): any; + send(buffer: any, offset: any, length: any, ...args: any[]): void; /** * @@ -2069,7 +2457,7 @@ declare class dgramSocket { * Close the socket * @url http://www.espruino.com/Reference#l_dgramSocket_close */ - close(): any; + close(): void; /** * @@ -2077,7 +2465,7 @@ declare class dgramSocket { * @param {any} ip - A string containing the ip to join with * @url http://www.espruino.com/Reference#l_dgramSocket_addMembership */ - addMembership(group: any, ip: any): any; + addMembership(group: any, ip: any): void; } /** @@ -2085,6 +2473,8 @@ declare class dgramSocket { * @url http://www.espruino.com/Reference#WLAN */ declare class WLAN { + + /** * Connect to a wireless network * @@ -2097,16 +2487,18 @@ declare class WLAN { connect(ap: any, key: any, callback: any): boolean; /** - * Completely uninitialise and power down the CC3000. After this you'll have to use ```require("CC3000").connect()``` again. + * Completely uninitialise and power down the CC3000. After this you'll have to use + * ```require("CC3000").connect()``` again. * @url http://www.espruino.com/Reference#l_WLAN_disconnect */ - disconnect(): any; + disconnect(): void; /** - * Completely uninitialise and power down the CC3000, then reconnect to the old access point. + * Completely uninitialise and power down the CC3000, then reconnect to the old + * access point. * @url http://www.espruino.com/Reference#l_WLAN_reconnect */ - reconnect(): any; + reconnect(): void; /** * Get the current IP address @@ -2116,10 +2508,12 @@ declare class WLAN { getIP(): any; /** - * Set the current IP address for get an IP from DHCP (if no options object is specified). - * **Note:** Changes are written to non-volatile memory, but will only take effect after calling `wlan.reconnect()` + * Set the current IP address for get an IP from DHCP (if no options object is + * specified). + * **Note:** Changes are written to non-volatile memory, but will only take effect + * after calling `wlan.reconnect()` * - * @param {any} options - Object containing IP address options `{ ip : '1,2,3,4', subnet, gateway, dns }`, or do not supply an object in otder to force DHCP. + * @param {any} options - Object containing IP address options `{ ip : '1,2,3,4', subnet, gateway, dns }`, or do not supply an object in otder to force DHCP. * @returns {boolean} True on success * @url http://www.espruino.com/Reference#l_WLAN_setIP */ @@ -2127,29 +2521,33 @@ declare class WLAN { } /** - * Class containing utility functions for the [ESP8266](http://www.espruino.com/EspruinoESP8266) + * Class containing utility functions for the + * [ESP8266](http://www.espruino.com/EspruinoESP8266) * @url http://www.espruino.com/Reference#ESP8266 */ declare class ESP8266 { /** * **DEPRECATED** - please use `Wifi.ping` instead. - * Perform a network ping request. The parameter can be either a String or a numeric IP address. + * Perform a network ping request. The parameter can be either a String or a + * numeric IP address. * * @param {any} ipAddr - A string representation of an IP address. * @param {any} pingCallback - Optional callback function. * @url http://www.espruino.com/Reference#l_ESP8266_ping */ - static ping(ipAddr: any, pingCallback: any): any; + static ping(ipAddr: any, pingCallback: any): void; /** * Perform a hardware reset/reboot of the esp8266. * @url http://www.espruino.com/Reference#l_ESP8266_reboot */ - static reboot(): any; + static reboot(): void; /** - * At boot time the esp8266's firmware captures the cause of the reset/reboot. This function returns this information in an object with the following fields: - * * `reason`: "power on", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", or "reset pin" + * At boot time the esp8266's firmware captures the cause of the reset/reboot. This + * function returns this information in an object with the following fields: + * * `reason`: "power on", "wdt reset", "exception", "soft wdt", "restart", "deep + * sleep", or "reset pin" * * `exccause`: exception cause * * `epc1`, `epc2`, `epc3`: instruction pointers * * `excvaddr`: address being accessed @@ -2160,59 +2558,66 @@ declare class ESP8266 { static getResetInfo(): any; /** - * Enable or disable the logging of debug information. A value of `true` enables debug logging while a value of `false` disables debug logging. Debug output is sent to UART1 (gpio2). + * Enable or disable the logging of debug information. A value of `true` enables + * debug logging while a value of `false` disables debug logging. Debug output is + * sent to UART1 (gpio2). * * @param {boolean} enable - Enable or disable the debug logging. * @url http://www.espruino.com/Reference#l_ESP8266_logDebug */ - static logDebug(enable: boolean): any; + static logDebug(enable: boolean): void; /** - * Set the debug logging mode. It can be disabled (which frees ~1.2KB of heap), enabled in-memory only, or in-memory and output to a UART. + * Set the debug logging mode. It can be disabled (which frees ~1.2KB of heap), + * enabled in-memory only, or in-memory and output to a UART. * * @param {number} mode - Debug log mode: 0=off, 1=in-memory only, 2=in-mem and uart0, 3=in-mem and uart1. * @url http://www.espruino.com/Reference#l_ESP8266_setLog */ - static setLog(mode: number): any; + static setLog(mode: number): void; /** * Prints the contents of the debug log to the console. * @url http://www.espruino.com/Reference#l_ESP8266_printLog */ - static printLog(): any; + static printLog(): void; /** * Returns one line from the log or up to 128 characters. * @url http://www.espruino.com/Reference#l_ESP8266_readLog */ - static readLog(): any; + static readLog(): void; /** - * Dumps info about all sockets to the log. This is for troubleshooting the socket implementation. + * Dumps info about all sockets to the log. This is for troubleshooting the socket + * implementation. * @url http://www.espruino.com/Reference#l_ESP8266_dumpSocketInfo */ - static dumpSocketInfo(): any; + static dumpSocketInfo(): void; /** - * **Note:** This is deprecated. Use `E.setClock(80/160)` - * **Note:** - * Set the operating frequency of the ESP8266 processor. The default is 160Mhz. - * **Warning**: changing the cpu frequency affects the timing of some I/O operations, notably of software SPI and I2C, so things may be a bit slower at 80Mhz. + * **Note:** This is deprecated. Use `E.setClock(80/160)` **Note:** Set the + * operating frequency of the ESP8266 processor. The default is 160Mhz. + * **Warning**: changing the cpu frequency affects the timing of some I/O + * operations, notably of software SPI and I2C, so things may be a bit slower at + * 80Mhz. * * @param {any} freq - Desired frequency - either 80 or 160. * @url http://www.espruino.com/Reference#l_ESP8266_setCPUFreq */ - static setCPUFreq(freq: any): any; + static setCPUFreq(freq: any): void; /** - * Returns an object that contains details about the state of the ESP8266 with the following fields: - * * `sdkVersion` - Version of the SDK. + * Returns an object that contains details about the state of the ESP8266 with the + * following fields: + * * `sdkVersion` - Version of the SDK. * * `cpuFrequency` - CPU operating frequency in Mhz. - * * `freeHeap` - Amount of free heap in bytes. - * * `maxCon` - Maximum number of concurrent connections. - * * `flashMap` - Configured flash size&map: '512KB:256/256' .. '4MB:512/512' - * * `flashKB` - Configured flash size in KB as integer - * * `flashChip` - Type of flash chip as string with manufacturer & chip, ex: '0xEF 0x4016` + * * `freeHeap` - Amount of free heap in bytes. + * * `maxCon` - Maximum number of concurrent connections. + * * `flashMap` - Configured flash size&map: '512KB:256/256' .. '4MB:512/512' + * * `flashKB` - Configured flash size in KB as integer + * * `flashChip` - Type of flash chip as string with manufacturer & chip, ex: '0xEF + * 0x4016` * @returns {any} The state of the ESP8266 * @url http://www.espruino.com/Reference#l_ESP8266_getState */ @@ -2234,31 +2639,38 @@ declare class ESP8266 { static crc32(arrayOfData: any): any; /** - * **This function is deprecated.** Please use `require("neopixel").write(pin, data)` instead + * **This function is deprecated.** Please use `require("neopixel").write(pin, + * data)` instead * * @param {Pin} pin - Pin for output signal. * @param {any} arrayOfData - Array of LED data. * @url http://www.espruino.com/Reference#l_ESP8266_neopixelWrite */ - static neopixelWrite(pin: Pin, arrayOfData: any): any; + static neopixelWrite(pin: Pin, arrayOfData: any): void; /** - * Put the ESP8266 into 'deep sleep' for the given number of microseconds, - * reducing power consumption drastically. + * Put the ESP8266 into 'deep sleep' for the given number of microseconds, reducing + * power consumption drastically. * meaning of option values: - * 0 - the 108th Byte of init parameter decides whether RF calibration will be performed or not. + * 0 - the 108th Byte of init parameter decides whether RF calibration will be + * performed or not. * 1 - run RF calibration after waking up. Power consumption is high. * 2 - no RF calibration after waking up. Power consumption is low. * 4 - no RF after waking up. Power consumption is the lowest. - * **Note:** unlike normal Espruino boards' 'deep sleep' mode, ESP8266 deep sleep actually turns off the processor. After the given number of microseconds have elapsed, the ESP8266 will restart as if power had been turned off and then back on. *All contents of RAM will be lost*. - * Connect GPIO 16 to RST to enable wakeup. - * **Special:** 0 microseconds cause sleep forever until external wakeup RST pull down occurs. + * **Note:** unlike normal Espruino boards' 'deep sleep' mode, ESP8266 deep sleep + * actually turns off the processor. After the given number of microseconds have + * elapsed, the ESP8266 will restart as if power had been turned off and then back + * on. *All contents of RAM will be lost*. Connect GPIO 16 to RST to enable wakeup. + * **Special:** 0 microseconds cause sleep forever until external wakeup RST pull + * down occurs. * * @param {any} micros - Number of microseconds to sleep. * @param {any} option - posible values are 0, 1, 2 or 4 * @url http://www.espruino.com/Reference#l_ESP8266_deepSleep */ - static deepSleep(micros: any, option: any): any; + static deepSleep(micros: any, option: any): void; + + } /** @@ -2266,6 +2678,8 @@ declare class ESP8266 { * @url http://www.espruino.com/Reference#Ethernet */ declare class Ethernet { + + /** * Get the current IP address, subnet, gateway and mac address. * @@ -2276,9 +2690,10 @@ declare class Ethernet { getIP(options: any): any; /** - * Set the current IP address or get an IP from DHCP (if no options object is specified) - * If 'mac' is specified as an option, it must be a string of the form `"00:01:02:03:04:05"` - * The default mac is 00:08:DC:01:02:03. + * Set the current IP address or get an IP from DHCP (if no options object is + * specified) + * If 'mac' is specified as an option, it must be a string of the form + * `"00:01:02:03:04:05"` The default mac is 00:08:DC:01:02:03. * * @param {any} options - Object containing IP address options `{ ip : '1.2.3.4', subnet : '...', gateway: '...', dns:'...', mac:':::::' }`, or do not supply an object in order to force DHCP. * @param {any} callback - An optional `callback(err)` function to invoke when ip is set. `err==null` on success, or a string on failure. @@ -2288,10 +2703,10 @@ declare class Ethernet { setIP(options: any, callback: any): boolean; /** - * Set hostname allow to set the hosname used during the dhcp request. - * min 8 and max 12 char, best set before calling `eth.setIP()` - * Default is WIZnet010203, 010203 is the default nic as part of the mac. - * Best to set the hosname before calling setIP(). + * Set hostname allow to set the hosname used during the dhcp request. min 8 and + * max 12 char, best set before calling `eth.setIP()` Default is WIZnet010203, + * 010203 is the default nic as part of the mac. Best to set the hosname before + * calling setIP(). * * @param {any} hostname - hostname as string * @param {any} callback - An optional `callback(err)` function to be called back with null or error text. @@ -2324,6 +2739,8 @@ declare class Ethernet { * @url http://www.espruino.com/Reference#httpSrv */ declare class httpSrv { + + /** * Start listening for new HTTP connections on the given port * @@ -2337,7 +2754,7 @@ declare class httpSrv { * Stop listening for new HTTP connections * @url http://www.espruino.com/Reference#l_httpSrv_close */ - close(): any; + close(): void; } /** @@ -2346,7 +2763,9 @@ declare class httpSrv { */ declare class httpSRq { /** - * The 'data' event is called when data is received. If a handler is defined with `X.on('data', function(data) { ... })` then it will be called, otherwise data will be stored in an internal buffer, where it can be retrieved with `X.read()` + * The 'data' event is called when data is received. If a handler is defined with + * `X.on('data', function(data) { ... })` then it will be called, otherwise data + * will be stored in an internal buffer, where it can be retrieved with `X.read()` * @param {string} event - The event to listen to. * @param {(data: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `data` A string containing one or more characters of received data @@ -2360,7 +2779,9 @@ declare class httpSRq { * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_httpSRq_close */ - static on(event: "close", callback: () => void): void;/** + static on(event: "close", callback: () => void): void; + + /** * The headers to sent to the server with this HTTP request. * @returns {any} An object mapping header name to value * @url http://www.espruino.com/Reference#l_httpSRq_headers @@ -2384,7 +2805,8 @@ declare class httpSRq { url: any; /** - * Return how many bytes are available to read. If there is already a listener for data, this will always return 0. + * Return how many bytes are available to read. If there is already a listener for + * data, this will always return 0. * @returns {number} How many bytes are available * @url http://www.espruino.com/Reference#l_httpSRq_available */ @@ -2410,7 +2832,7 @@ declare class httpSRq { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_httpSRq_pipe */ - pipe(destination: any, options: any): any; + pipe(destination: any, options: any): void; } /** @@ -2419,7 +2841,8 @@ declare class httpSRq { */ declare class httpSRs { /** - * An event that is fired when the buffer is empty and it can accept more data to send. + * An event that is fired when the buffer is empty and it can accept more data to + * send. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_httpSRs_drain @@ -2432,7 +2855,9 @@ declare class httpSRs { * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_httpSRs_close */ - static on(event: "close", callback: () => void): void;/** + static on(event: "close", callback: () => void): void; + + /** * The headers to send back along with the HTTP response. * The default contents are: * ``` @@ -2448,7 +2873,8 @@ declare class httpSRs { /** * This function writes the `data` argument as a string. Data that is passed in * (including arrays) will be converted to a string with the normal JavaScript - * `toString` method. For more information about sending binary data see `Socket.write` + * `toString` method. For more information about sending binary data see + * `Socket.write` * * @param {any} data - A string containing data to send * @returns {boolean} For node.js compatibility, returns the boolean false. When the send buffer is empty, a `drain` event will be sent @@ -2462,30 +2888,31 @@ declare class httpSRs { * @param {any} data - A string containing data to send * @url http://www.espruino.com/Reference#l_httpSRs_end */ - end(data: any): any; + end(data: any): void; /** - * Send the given status code and headers. If not explicitly called - * this will be done automatically the first time data is written - * to the response. - * This cannot be called twice, or after data has already been sent - * in the response. + * Send the given status code and headers. If not explicitly called this will be + * done automatically the first time data is written to the response. + * This cannot be called twice, or after data has already been sent in the + * response. * * @param {number} statusCode - The HTTP status code * @param {any} headers - An object containing the headers * @url http://www.espruino.com/Reference#l_httpSRs_writeHead */ - writeHead(statusCode: number, headers: any): any; + writeHead(statusCode: number, headers: any): void; /** - * Set a value to send in the header of this HTTP response. This updates the `httpSRs.headers` property. - * Any headers supplied to `writeHead` will overwrite any headers with the same name. + * Set a value to send in the header of this HTTP response. This updates the + * `httpSRs.headers` property. + * Any headers supplied to `writeHead` will overwrite any headers with the same + * name. * * @param {any} name - The name of the header as a String * @param {any} value - The value of the header as a String * @url http://www.espruino.com/Reference#l_httpSRs_setHeader */ - setHeader(name: any, value: any): any; + setHeader(name: any, value: any): void; } /** @@ -2494,7 +2921,8 @@ declare class httpSRs { */ declare class httpCRq { /** - * An event that is fired when the buffer is empty and it can accept more data to send. + * An event that is fired when the buffer is empty and it can accept more data to + * send. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_httpCRq_drain @@ -2502,15 +2930,21 @@ declare class httpCRq { static on(event: "drain", callback: () => void): void; /** - * An event that is fired if there is an error making the request and the response callback has not been invoked. In this case the error event concludes the request attempt. The error event function receives an error object as parameter with a `code` field and a `message` field. + * An event that is fired if there is an error making the request and the response + * callback has not been invoked. In this case the error event concludes the + * request attempt. The error event function receives an error object as parameter + * with a `code` field and a `message` field. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_httpCRq_error */ - static on(event: "error", callback: () => void): void;/** + static on(event: "error", callback: () => void): void; + + /** * This function writes the `data` argument as a string. Data that is passed in * (including arrays) will be converted to a string with the normal JavaScript - * `toString` method. For more information about sending binary data see `Socket.write` + * `toString` method. For more information about sending binary data see + * `Socket.write` * * @param {any} data - A string containing data to send * @returns {boolean} For node.js compatibility, returns the boolean false. When the send buffer is empty, a `drain` event will be sent @@ -2525,16 +2959,19 @@ declare class httpCRq { * @param {any} data - A string containing data to send * @url http://www.espruino.com/Reference#l_httpCRq_end */ - end(data: any): any; + end(data: any): void; } /** - * The HTTP client response, passed to the callback of `http.request()` an `http.get()`. + * The HTTP client response, passed to the callback of `http.request()` an + * `http.get()`. * @url http://www.espruino.com/Reference#httpCRs */ declare class httpCRs { /** - * The 'data' event is called when data is received. If a handler is defined with `X.on('data', function(data) { ... })` then it will be called, otherwise data will be stored in an internal buffer, where it can be retrieved with `X.read()` + * The 'data' event is called when data is received. If a handler is defined with + * `X.on('data', function(data) { ... })` then it will be called, otherwise data + * will be stored in an internal buffer, where it can be retrieved with `X.read()` * @param {string} event - The event to listen to. * @param {(data: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `data` A string containing one or more characters of received data @@ -2543,7 +2980,8 @@ declare class httpCRs { static on(event: "data", callback: (data: any) => void): void; /** - * Called when the connection closes with one `hadError` boolean parameter, which indicates whether an error occurred. + * Called when the connection closes with one `hadError` boolean parameter, which + * indicates whether an error occurred. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_httpCRs_close @@ -2551,12 +2989,17 @@ declare class httpCRs { static on(event: "close", callback: () => void): void; /** - * An event that is fired if there is an error receiving the response. The error event function receives an error object as parameter with a `code` field and a `message` field. After the error event the close even will also be triggered to conclude the HTTP request/response. + * An event that is fired if there is an error receiving the response. The error + * event function receives an error object as parameter with a `code` field and a + * `message` field. After the error event the close even will also be triggered to + * conclude the HTTP request/response. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_httpCRs_error */ - static on(event: "error", callback: () => void): void;/** + static on(event: "error", callback: () => void): void; + + /** * The headers received along with the HTTP response * @returns {any} An object mapping header name to value * @url http://www.espruino.com/Reference#l_httpCRs_headers @@ -2585,7 +3028,8 @@ declare class httpCRs { httpVersion: any; /** - * Return how many bytes are available to read. If there is a 'data' event handler, this will always return 0. + * Return how many bytes are available to read. If there is a 'data' event handler, + * this will always return 0. * @returns {number} How many bytes are available * @url http://www.espruino.com/Reference#l_httpCRs_available */ @@ -2611,12 +3055,12 @@ declare class httpCRs { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_httpCRs_pipe */ - pipe(destination: any, options: any): any; + pipe(destination: any, options: any): void; } /** - * This class provides functionality to recognise gestures drawn - * on a touchscreen. It is only built into Bangle.js 2. + * This class provides functionality to recognise gestures drawn on a touchscreen. + * It is only built into Bangle.js 2. * Usage: * ``` * var strokes = { @@ -2648,11 +3092,14 @@ declare class Unistroke { * @url http://www.espruino.com/Reference#l_Unistroke_recognise */ static recognise(strokes: any, xy: any): any; + + } /** * The NRF class is for controlling functionality of the Nordic nRF51/nRF52 chips. - * Most functionality is related to Bluetooth Low Energy, however there are also some functions related to NFC that apply to NRF52-based devices. + * Most functionality is related to Bluetooth Low Energy, however there are also + * some functions related to NFC that apply to NRF52-based devices. * @url http://www.espruino.com/Reference#NRF */ declare class NRF { @@ -2674,7 +3121,7 @@ declare class NRF { * @param {any} options - Optional object containing options * @url http://www.espruino.com/Reference#l_NRF_setServices */ - static setServices(data: any, options: any): any; + static setServices(data: any, options: any): void; /** * @@ -2682,10 +3129,11 @@ declare class NRF { * @param {any} options - An optional object of options * @url http://www.espruino.com/Reference#l_NRF_setAdvertising */ - static setAdvertising(data: any, options: any): any; + static setAdvertising(data: any, options: any): void; /** - * Called when a host device connects to Espruino. The first argument contains the address. + * Called when a host device connects to Espruino. The first argument contains the + * address. * @param {string} event - The event to listen to. * @param {(addr: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `addr` The address of the device that has connected @@ -2716,10 +3164,9 @@ declare class NRF { static on(event: "security", callback: (status: any) => void): void; /** - * Called with a single byte value when Espruino is set up as - * a HID device and the computer it is connected to sends a - * HID report back to Espruino. This is usually used for handling - * indications such as the Caps Lock LED. + * Called with a single byte value when Espruino is set up as a HID device and the + * computer it is connected to sends a HID report back to Espruino. This is usually + * used for handling indications such as the Caps Lock LED. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_NRF_HID @@ -2759,9 +3206,9 @@ declare class NRF { static on(event: "NFCoff", callback: () => void): void; /** - * When NFC is started with `NRF.nfcStart`, this is fired - * when NFC data is received. It doesn't get called if - * NFC is started with `NRF.nfcURL` or `NRF.nfcRaw` + * When NFC is started with `NRF.nfcStart`, this is fired when NFC data is + * received. It doesn't get called if NFC is started with `NRF.nfcURL` or + * `NRF.nfcRaw` * @param {string} event - The event to listen to. * @param {(arr: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `arr` An ArrayBuffer containign the received data @@ -2773,43 +3220,43 @@ declare class NRF { * If a device is connected to Espruino, disconnect from it. * @url http://www.espruino.com/Reference#l_NRF_disconnect */ - static disconnect(): any; + static disconnect(): void; /** - * Disable Bluetooth advertising and disconnect from any device that - * connected to Puck.js as a peripheral (this won't affect any devices - * that Puck.js initiated connections to). + * Disable Bluetooth advertising and disconnect from any device that connected to + * Puck.js as a peripheral (this won't affect any devices that Puck.js initiated + * connections to). * This makes Puck.js undiscoverable, so it can't be connected to. * Use `NRF.wake()` to wake up and make Puck.js connectable again. * @url http://www.espruino.com/Reference#l_NRF_sleep */ - static sleep(): any; + static sleep(): void; /** - * Enable Bluetooth advertising (this is enabled by default), which - * allows other devices to discover and connect to Puck.js. + * Enable Bluetooth advertising (this is enabled by default), which allows other + * devices to discover and connect to Puck.js. * Use `NRF.sleep()` to disable advertising. * @url http://www.espruino.com/Reference#l_NRF_wake */ - static wake(): any; + static wake(): void; /** - * Restart the Bluetooth softdevice (if there is currently a BLE connection, - * it will queue a restart to be done when the connection closes). - * You shouldn't need to call this function in normal usage. However, Nordic's - * BLE softdevice has some settings that cannot be reset. For example there - * are only a certain number of unique UUIDs. Once these are all used the - * only option is to restart the softdevice to clear them all out. + * Restart the Bluetooth softdevice (if there is currently a BLE connection, it + * will queue a restart to be done when the connection closes). + * You shouldn't need to call this function in normal usage. However, Nordic's BLE + * softdevice has some settings that cannot be reset. For example there are only a + * certain number of unique UUIDs. Once these are all used the only option is to + * restart the softdevice to clear them all out. * * @param {any} callback - An optional function to be called while the softdevice is uninitialised. Use with caution - accessing console/bluetooth will almost certainly result in a crash. * @url http://www.espruino.com/Reference#l_NRF_restart */ - static restart(callback: any): any; + static restart(callback: any): void; /** * Get this device's default Bluetooth MAC address. - * For Puck.js, the last 5 characters of this (eg. `ee:ff`) - * are used in the device's advertised Bluetooth name. + * For Puck.js, the last 5 characters of this (eg. `ee:ff`) are used in the + * device's advertised Bluetooth name. * @returns {any} MAC address - a string of the form 'aa:bb:cc:dd:ee:ff' * @url http://www.espruino.com/Reference#l_NRF_getAddress */ @@ -2822,19 +3269,21 @@ declare class NRF { * ``` * Addresses take the form: * * `"ff:ee:dd:cc:bb:aa"` or `"ff:ee:dd:cc:bb:aa public"` for a public address - * * `"ff:ee:dd:cc:bb:aa random"` for a random static address (the default for Espruino) - * This may throw a `INVALID_BLE_ADDR` error if the upper two bits - * of the address don't match the address type. - * To change the address, Espruino must restart the softdevice. It will only do - * so when it is disconnected from other devices. + * * `"ff:ee:dd:cc:bb:aa random"` for a random static address (the default for + * Espruino) + * This may throw a `INVALID_BLE_ADDR` error if the upper two bits of the address + * don't match the address type. + * To change the address, Espruino must restart the softdevice. It will only do so + * when it is disconnected from other devices. * * @param {any} addr - The address to use (as a string) * @url http://www.espruino.com/Reference#l_NRF_setAddress */ - static setAddress(addr: any): any; + static setAddress(addr: any): void; /** - * Get the battery level in volts (the voltage that the NRF chip is running off of). + * Get the battery level in volts (the voltage that the NRF chip is running off + * of). * This is the battery level of the device itself - it has nothing to with any * device that might be connected. * @returns {number} Battery level in volts @@ -2844,8 +3293,9 @@ declare class NRF { /** * Change the data that Espruino advertises. - * Data can be of the form `{ UUID : data_as_byte_array }`. The UUID should be - * a [Bluetooth Service ID](https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx). + * Data can be of the form `{ UUID : data_as_byte_array }`. The UUID should be a + * [Bluetooth Service + * ID](https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx). * For example to return battery level at 95%, do: * ``` * NRF.setAdvertising({ @@ -2867,10 +3317,10 @@ declare class NRF { * 0x180D : undefined // Advertise service UUID 0x180D (HRM) * }); * ``` - * Service UUIDs can also be supplied in the second argument of - * `NRF.setServices`, but those go in the scan response packet. - * You can also supply the raw advertising data in an array. For example - * to advertise as an Eddystone beacon: + * Service UUIDs can also be supplied in the second argument of `NRF.setServices`, + * but those go in the scan response packet. + * You can also supply the raw advertising data in an array. For example to + * advertise as an Eddystone beacon: * ``` * NRF.setAdvertising([0x03, // Length of Service List * 0x03, // Param: Service List @@ -2884,15 +3334,16 @@ declare class NRF { * 'g','o','o','.','g','l','/','B','3','J','0','O','c'], * {interval:100}); * ``` - * (However for Eddystone we'd advise that you use the [Espruino Eddystone library](/Puck.js+Eddystone)) + * (However for Eddystone we'd advise that you use the [Espruino Eddystone + * library](/Puck.js+Eddystone)) * **Note:** When specifying data as an array, certain advertising options such as * `discoverable` and `showName` won't have any effect. - * **Note:** The size of Bluetooth LE advertising packets is limited to 31 bytes. If - * you want to advertise more data, consider using an array for `data` (See below), or - * `NRF.setScanResponse`. - * You can even specify an array of arrays or objects, in which case each advertising packet - * will be used in turn - for instance to make your device advertise battery level and its name - * as well as both Eddystone and iBeacon : + * **Note:** The size of Bluetooth LE advertising packets is limited to 31 bytes. + * If you want to advertise more data, consider using an array for `data` (See + * below), or `NRF.setScanResponse`. + * You can even specify an array of arrays or objects, in which case each + * advertising packet will be used in turn - for instance to make your device + * advertise battery level and its name as well as both Eddystone and iBeacon : * ``` * NRF.setAdvertising([ * {0x180F : [Puck.getBatteryPercentage()]}, // normal advertising, with battery % @@ -2914,21 +3365,21 @@ declare class NRF { * phy: "1mbps/2mbps/coded" // (NRF52840 only) use the long-range coded phy for transmission (1mbps default) * } * ``` - * Setting `connectable` and `scannable` to false gives the lowest power consumption - * as the BLE radio doesn't have to listen after sending advertising. - * **NOTE:** Non-`connectable` advertising can't have an advertising interval less than 100ms - * according to the BLE spec. - * So for instance to set the name of Puck.js without advertising any - * other data you can just use the command: + * Setting `connectable` and `scannable` to false gives the lowest power + * consumption as the BLE radio doesn't have to listen after sending advertising. + * **NOTE:** Non-`connectable` advertising can't have an advertising interval less + * than 100ms according to the BLE spec. + * So for instance to set the name of Puck.js without advertising any other data + * you can just use the command: * ``` * NRF.setAdvertising({},{name:"Hello"}); * ``` - * You can also specify 'manufacturer data', which is another form of advertising data. - * We've registered the Manufacturer ID 0x0590 (as Pur3 Ltd) for use with *Official - * Espruino devices* - use it to advertise whatever data you'd like, but we'd recommend - * using JSON. - * For example by not advertising a device name you can send up to 24 bytes of JSON on - * Espruino's manufacturer ID: + * You can also specify 'manufacturer data', which is another form of advertising + * data. We've registered the Manufacturer ID 0x0590 (as Pur3 Ltd) for use with + * *Official Espruino devices* - use it to advertise whatever data you'd like, but + * we'd recommend using JSON. + * For example by not advertising a device name you can send up to 24 bytes of JSON + * on Espruino's manufacturer ID: * ``` * var data = {a:1,b:2}; * NRF.setAdvertising({},{ @@ -2937,24 +3388,24 @@ declare class NRF { * manufacturerData:JSON.stringify(data) * }); * ``` - * If you're using [EspruinoHub](https://github.com/espruino/EspruinoHub) then it will - * automatically decode this into the folling MQTT topics: + * If you're using [EspruinoHub](https://github.com/espruino/EspruinoHub) then it + * will automatically decode this into the folling MQTT topics: * * `/ble/advertise/ma:c_:_a:dd:re:ss/espruino` -> `{"a":10,"b":15}` * * `/ble/advertise/ma:c_:_a:dd:re:ss/a` -> `1` * * `/ble/advertise/ma:c_:_a:dd:re:ss/b` -> `2` - * Note that **you only have 24 characters available for JSON**, so try to use - * the shortest field names possible and avoid floating point values that can - * be very long when converted to a String. + * Note that **you only have 24 characters available for JSON**, so try to use the + * shortest field names possible and avoid floating point values that can be very + * long when converted to a String. * * @param {any} data - The service data to advertise as an object - see below for more info * @param {any} options - An optional object of options * @url http://www.espruino.com/Reference#l_NRF_setAdvertising */ - static setAdvertising(data: any, options: any): any; + static setAdvertising(data: any, options: any): void; /** - * This is just like `NRF.setAdvertising`, except instead of advertising - * the data, it returns the packet that would be advertised as an array. + * This is just like `NRF.setAdvertising`, except instead of advertising the data, + * it returns the packet that would be advertised as an array. * * @param {any} data - The data to advertise as an object * @param {any} options - An optional object of options @@ -2964,26 +3415,28 @@ declare class NRF { static getAdvertisingData(data: any, options: any): any; /** - * The raw scan response data should be supplied as an array. For example to return "Sample" for the device name: + * The raw scan response data should be supplied as an array. For example to return + * "Sample" for the device name: * ``` * NRF.setScanResponse([0x07, // Length of Data * 0x09, // Param: Complete Local Name * 'S', 'a', 'm', 'p', 'l', 'e']); * ``` - * **Note:** `NRF.setServices(..., {advertise:[ ... ]})` writes advertised - * services into the scan response - so you can't use both `advertise` - * and `NRF.setServices` or one will overwrite the other. + * **Note:** `NRF.setServices(..., {advertise:[ ... ]})` writes advertised services + * into the scan response - so you can't use both `advertise` and `NRF.setServices` + * or one will overwrite the other. * * @param {any} data - The data to for the scan response * @url http://www.espruino.com/Reference#l_NRF_setScanResponse */ - static setScanResponse(data: any): any; + static setScanResponse(data: any): void; /** * Change the services and characteristics Espruino advertises. - * If you want to **change** the value of a characteristic, you need - * to use `NRF.updateServices()` instead - * To expose some information on Characteristic `ABCD` on service `BCDE` you could do: + * If you want to **change** the value of a characteristic, you need to use + * `NRF.updateServices()` instead + * To expose some information on Characteristic `ABCD` on service `BCDE` you could + * do: * ``` * NRF.setServices({ * 0xBCDE : { @@ -3048,8 +3501,8 @@ declare class NRF { * // more services allowed * }); * ``` - * **Note:** UUIDs can be integers between `0` and `0xFFFF`, strings of - * the form `"ABCD"`, or strings of the form `"ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD"` + * **Note:** UUIDs can be integers between `0` and `0xFFFF`, strings of the form + * `"ABCD"`, or strings of the form `"ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD"` * `options` can be of the form: * ``` * NRF.setServices(undefined, { @@ -3061,13 +3514,13 @@ declare class NRF { * }); * ``` * To enable BLE HID, you must set `hid` to an array which is the BLE report - * descriptor. The easiest way to do this is to use the `ble_hid_controls` - * or `ble_hid_keyboard` modules. - * **Note:** Just creating a service doesn't mean that the service will - * be advertised. It will only be available after a device connects. To - * advertise, specify the UUIDs you wish to advertise in the `advertise` - * field of the second `options` argument. For example this will create - * and advertise a heart rate service: + * descriptor. The easiest way to do this is to use the `ble_hid_controls` or + * `ble_hid_keyboard` modules. + * **Note:** Just creating a service doesn't mean that the service will be + * advertised. It will only be available after a device connects. To advertise, + * specify the UUIDs you wish to advertise in the `advertise` field of the second + * `options` argument. For example this will create and advertise a heart rate + * service: * ``` * NRF.setServices({ * 0x180D: { // heart_rate @@ -3080,29 +3533,31 @@ declare class NRF { * ``` * You may specify 128 bit UUIDs to advertise, however you may get a `DATA_SIZE` * exception because there is insufficient space in the Bluetooth LE advertising - * packet for the 128 bit UART UUID as well as the UUID you specified. In this - * case you can add `uart:false` after the `advertise` element to disable the - * UART, however you then be unable to connect to Puck.js's console via Bluetooth. + * packet for the 128 bit UART UUID as well as the UUID you specified. In this case + * you can add `uart:false` after the `advertise` element to disable the UART, + * however you then be unable to connect to Puck.js's console via Bluetooth. * If you absolutely require two or more 128 bit UUIDs then you will have to * specify your own raw advertising data packets with `NRF.setAdvertising` - * **Note:** The services on Espruino can only be modified when there is - * no device connected to it as it requires a restart of the Bluetooth stack. - * **iOS devices will 'cache' the list of services** so apps like - * NRF Connect may incorrectly display the old services even after you - * have modified them. To fix this, disable and re-enable Bluetooth on your - * iOS device, or use an Android device to run NRF Connect. - * **Note:** Not all combinations of security configuration values are valid, the valid combinations are: encrypted, - * encrypted + mitm, lesc, signed, signed + mitm. See `NRF.setSecurity` for more information. + * **Note:** The services on Espruino can only be modified when there is no device + * connected to it as it requires a restart of the Bluetooth stack. **iOS devices + * will 'cache' the list of services** so apps like NRF Connect may incorrectly + * display the old services even after you have modified them. To fix this, disable + * and re-enable Bluetooth on your iOS device, or use an Android device to run NRF + * Connect. + * **Note:** Not all combinations of security configuration values are valid, the + * valid combinations are: encrypted, encrypted + mitm, lesc, signed, signed + + * mitm. See `NRF.setSecurity` for more information. * * @param {any} data - The service (and characteristics) to advertise * @param {any} options - Optional object containing options * @url http://www.espruino.com/Reference#l_NRF_setServices */ - static setServices(data: any, options: any): any; + static setServices(data: any, options: any): void; /** - * Update values for the services and characteristics Espruino advertises. - * Only services and characteristics previously declared using `NRF.setServices` are affected. + * Update values for the services and characteristics Espruino advertises. Only + * services and characteristics previously declared using `NRF.setServices` are + * affected. * To update the '0xABCD' characteristic in the '0xBCDE' service: * ``` * NRF.updateServices({ @@ -3113,7 +3568,8 @@ declare class NRF { * } * }); * ``` - * You can also use 128 bit UUIDs, for example `"b7920001-3c1b-4b40-869f-3c0db9be80c6"`. + * You can also use 128 bit UUIDs, for example + * `"b7920001-3c1b-4b40-869f-3c0db9be80c6"`. * To define a service and characteristic and then notify connected clients of a * change to it when a button is pressed: * ``` @@ -3137,11 +3593,13 @@ declare class NRF { * }); * }, BTN, { repeat:true, edge:"rising", debounce: 50 }); * ``` - * This only works if the characteristic was created with `notify: true` using `NRF.setServices`, - * otherwise the characteristic will be updated but no notification will be sent. + * This only works if the characteristic was created with `notify: true` using + * `NRF.setServices`, otherwise the characteristic will be updated but no + * notification will be sent. * Also note that `maxLen` was specified. If it wasn't then the maximum length of * the characteristic would have been 5 - the length of `"Hello"`. - * To indicate (i.e. notify with ACK) connected clients of a change to the '0xABCD' characteristic in the '0xBCDE' service: + * To indicate (i.e. notify with ACK) connected clients of a change to the '0xABCD' + * characteristic in the '0xBCDE' service: * ``` * NRF.updateServices({ * 0xBCDE : { @@ -3152,19 +3610,20 @@ declare class NRF { * } * }); * ``` - * This only works if the characteristic was created with `indicate: true` using `NRF.setServices`, - * otherwise the characteristic will be updated but no notification will be sent. + * This only works if the characteristic was created with `indicate: true` using + * `NRF.setServices`, otherwise the characteristic will be updated but no + * notification will be sent. * **Note:** See `NRF.setServices` for more information * * @param {any} data - The service (and characteristics) to update * @url http://www.espruino.com/Reference#l_NRF_updateServices */ - static updateServices(data: any): any; + static updateServices(data: any): void; /** * Start/stop listening for BLE advertising packets within range. Returns a - * `BluetoothDevice` for each advertsing packet. **By default this is not an active scan, so - * Scan Response advertising data is not included (see below)** + * `BluetoothDevice` for each advertsing packet. **By default this is not an active + * scan, so Scan Response advertising data is not included (see below)** * ``` * // Start scanning * packets=10; @@ -3185,46 +3644,47 @@ declare class NRF { * "data": new Uint8Array([ ... ]).buffer, // ArrayBuffer of returned data * "serviceData" : { "0123" : [ 1 ] }, // if service data is in 'data', it's extracted here * "manufacturer" : 0x1234, // if manufacturer data is in 'data', the 16 bit manufacturer ID is extracted here - * "manufacturerData" : [...], // if manufacturer data is in 'data', the data is extracted here + * "manufacturerData" : new Uint8Array([...]).buffer, // if manufacturer data is in 'data', the data is extracted here as an ArrayBuffer * "name": "DeviceName" // the advertised device name * } * ``` - * You can also supply a set of filters (as described in `NRF.requestDevice`) as a second argument, which will - * allow you to filter the devices you get a callback for. This helps - * to cut down on the time spent processing JavaScript code in areas with - * a lot of Bluetooth advertisements. For example to find only devices + * You can also supply a set of filters (as described in `NRF.requestDevice`) as a + * second argument, which will allow you to filter the devices you get a callback + * for. This helps to cut down on the time spent processing JavaScript code in + * areas with a lot of Bluetooth advertisements. For example to find only devices * with the manufacturer data `0x0590` (Espruino's ID) you could do: * ``` * NRF.setScan(function(d) { * console.log(d.manufacturerData); * }, { filters: [{ manufacturerData:{0x0590:{}} }] }); * ``` - * You can also specify `active:true` in the second argument to perform - * active scanning (this requests scan response packets) from any - * devices it finds. - * **Note:** Using a filter in `setScan` filters each advertising packet individually. As - * a result, if you filter based on a service UUID and a device advertises with multiple packets - * (or a scan response when `active:true`) only the packets matching the filter are returned. To - * aggregate multiple packets you can use `NRF.findDevices`. - * **Note:** BLE advertising packets can arrive quickly - faster than you'll - * be able to print them to the console. It's best only to print a few, or - * to use a function like `NRF.findDevices(..)` which will collate a list - * of available devices. - * **Note:** Using setScan turns the radio's receive mode on constantly. This - * can draw a *lot* of power (12mA or so), so you should use it sparingly or - * you can run your battery down quickly. + * You can also specify `active:true` in the second argument to perform active + * scanning (this requests scan response packets) from any devices it finds. + * **Note:** Using a filter in `setScan` filters each advertising packet + * individually. As a result, if you filter based on a service UUID and a device + * advertises with multiple packets (or a scan response when `active:true`) only + * the packets matching the filter are returned. To aggregate multiple packets you + * can use `NRF.findDevices`. + * **Note:** BLE advertising packets can arrive quickly - faster than you'll be + * able to print them to the console. It's best only to print a few, or to use a + * function like `NRF.findDevices(..)` which will collate a list of available + * devices. + * **Note:** Using setScan turns the radio's receive mode on constantly. This can + * draw a *lot* of power (12mA or so), so you should use it sparingly or you can + * run your battery down quickly. * * @param {any} callback - The callback to call with received advertising packets, or undefined to stop * @param {any} options - An optional object `{filters: ...}` (as would be passed to `NRF.requestDevice`) to filter devices by * @url http://www.espruino.com/Reference#l_NRF_setScan */ - static setScan(callback: any, options: any): any; + static setScan(callback: any, options: any): void; /** * This function can be used to quickly filter through Bluetooth devices. - * For instance if you wish to scan for multiple different types of device at the same time - * then you could use `NRF.findDevices` with all the filters you're interested in. When scanning - * is finished you can then use `NRF.filterDevices` to pick out just the devices of interest. + * For instance if you wish to scan for multiple different types of device at the + * same time then you could use `NRF.findDevices` with all the filters you're + * interested in. When scanning is finished you can then use `NRF.filterDevices` to + * pick out just the devices of interest. * ``` * // the two types of device we're interested in * var filter1 = [{serviceData:{"fe95":{}}}]; @@ -3247,8 +3707,8 @@ declare class NRF { static filterDevices(devices: any, filters: any): any; /** - * Utility function to return a list of BLE devices detected in range. Behind the scenes, - * this uses `NRF.setScan(...)` and collates the results. + * Utility function to return a list of BLE devices detected in range. Behind the + * scenes, this uses `NRF.setScan(...)` and collates the results. * ``` * NRF.findDevices(function(devices) { * console.log(devices); @@ -3258,12 +3718,13 @@ declare class NRF { * ``` * [ * BluetoothDevice { - * "id": "e7:e0:57:ad:36:a2 random", + * "id" : "e7:e0:57:ad:36:a2 random", * "rssi": -45, * "services": [ "4567" ], * "serviceData" : { "0123" : [ 1 ] }, - * "manufacturerData" : [...], - * "data": new ArrayBuffer([ ... ]), + * "manufacturer" : 1424, + * "manufacturerData" : new Uint8Array([ ... ]).buffer, + * "data": new ArrayBuffer([ ... ]).buffer, * "name": "Puck.js 36a2" * }, * BluetoothDevice { @@ -3275,32 +3736,37 @@ declare class NRF { * ] * ``` * For more information on the structure returned, see `NRF.setScan`. - * If you want to scan only for specific devices you can replace the timeout with an object - * of the form `{filters: ..., timeout : ..., active: bool}` using the filters - * described in `NRF.requestDevice`. For example to search for devices with Espruino's `manufacturerData`: + * If you want to scan only for specific devices you can replace the timeout with + * an object of the form `{filters: ..., timeout : ..., active: bool}` using the + * filters described in `NRF.requestDevice`. For example to search for devices with + * Espruino's `manufacturerData`: * ``` * NRF.findDevices(function(devices) { * ... * }, {timeout : 2000, filters : [{ manufacturerData:{0x0590:{}} }] }); * ``` - * You could then use [`BluetoothDevice.gatt.connect(...)`](/Reference#l_BluetoothRemoteGATTServer_connect) on - * the device returned to make a connection. - * You can also use [`NRF.connect(...)`](/Reference#l_NRF_connect) on just the `id` string returned, which - * may be useful if you always want to connect to a specific device. - * **Note:** Using findDevices turns the radio's receive mode on for 2000ms (or however long you specify). This - * can draw a *lot* of power (12mA or so), so you should use it sparingly or you can run your battery down quickly. - * **Note:** The 'data' field contains the data of *the last packet received*. There may have been more - * packets. To get data for each packet individually use `NRF.setScan` instead. + * You could then use + * [`BluetoothDevice.gatt.connect(...)`](/Reference#l_BluetoothRemoteGATTServer_connect) + * on the device returned to make a connection. + * You can also use [`NRF.connect(...)`](/Reference#l_NRF_connect) on just the `id` + * string returned, which may be useful if you always want to connect to a specific + * device. + * **Note:** Using findDevices turns the radio's receive mode on for 2000ms (or + * however long you specify). This can draw a *lot* of power (12mA or so), so you + * should use it sparingly or you can run your battery down quickly. + * **Note:** The 'data' field contains the data of *the last packet received*. + * There may have been more packets. To get data for each packet individually use + * `NRF.setScan` instead. * * @param {any} callback - The callback to call with received advertising packets (as `BluetoothDevice`), or undefined to stop - * @param {any} options - A time in milliseconds to scan for (defaults to 2000), Or an optional object `{filters: ..., timeout : ..., active: bool}` (as would be passed to `NRF.requestDevice`) to filter devices by + * @param {any} [options] - [optional] A time in milliseconds to scan for (defaults to 2000), Or an optional object `{filters: ..., timeout : ..., active: bool}` (as would be passed to `NRF.requestDevice`) to filter devices by * @url http://www.espruino.com/Reference#l_NRF_findDevices */ - static findDevices(callback: any, options: any): any; + static findDevices(callback: (devices: BluetoothDevice[]) => void, options?: number | { filters?: NRFFilters, timeout?: number, active?: boolean }): void; /** - * Start/stop listening for RSSI values on the currently active connection - * (where This device is a peripheral and is being connected to by a 'central' device) + * Start/stop listening for RSSI values on the currently active connection (where + * This device is a peripheral and is being connected to by a 'central' device) * ``` * // Start scanning * NRF.setRSSIHandler(function(rssi) { @@ -3314,7 +3780,7 @@ declare class NRF { * @param {any} callback - The callback to call with the RSSI value, or undefined to stop * @url http://www.espruino.com/Reference#l_NRF_setRSSIHandler */ - static setRSSIHandler(callback: any): any; + static setRSSIHandler(callback: any): void; /** * Set the BLE radio transmit power. The default TX power is 0 dBm, and @@ -3322,26 +3788,25 @@ declare class NRF { * @param {number} power - Transmit power. Accepted values are -40(nRF52 only), -30(nRF51 only), -20, -16, -12, -8, -4, 0, and 4 dBm. On nRF52840 (eg Bangle.js 2) 5/6/7/8 dBm are available too. Others will give an error code. * @url http://www.espruino.com/Reference#l_NRF_setTxPower */ - static setTxPower(power: number): any; + static setTxPower(power: number): void; /** - * **THIS IS DEPRECATED** - please use `NRF.setConnectionInterval` for - * peripheral and `NRF.connect(addr, options)`/`BluetoothRemoteGATTServer.connect(options)` + * **THIS IS DEPRECATED** - please use `NRF.setConnectionInterval` for peripheral + * and `NRF.connect(addr, options)`/`BluetoothRemoteGATTServer.connect(options)` * for central connections. - * This sets the connection parameters - these affect the transfer speed and - * power usage when the device is connected. + * This sets the connection parameters - these affect the transfer speed and power + * usage when the device is connected. * * When not low power, the connection interval is between 7.5 and 20ms * * When low power, the connection interval is between 500 and 1000ms - * When low power connection is enabled, transfers of data over Bluetooth - * will be very slow, however power usage while connected will be drastically - * decreased. + * When low power connection is enabled, transfers of data over Bluetooth will be + * very slow, however power usage while connected will be drastically decreased. * This will only take effect after the connection is disconnected and * re-established. * * @param {boolean} lowPower - Whether the connection is low power or not * @url http://www.espruino.com/Reference#l_NRF_setLowPowerConnection */ - static setLowPowerConnection(lowPower: boolean): any; + static setLowPowerConnection(lowPower: boolean): void; /** * Enables NFC and starts advertising the given URL. For example: @@ -3352,12 +3817,12 @@ declare class NRF { * @param {any} url - The URL string to expose on NFC, or `undefined` to disable NFC * @url http://www.espruino.com/Reference#l_NRF_nfcURL */ - static nfcURL(url: any): any; + static nfcURL(url: any): void; /** * Enables NFC and with an out of band 16 byte pairing key. - * For example the following will enable out of band pairing on BLE - * such that the device will pair when you tap the phone against it: + * For example the following will enable out of band pairing on BLE such that the + * device will pair when you tap the phone against it: * ``` * var bleKey = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00]; * NRF.on('security',s=>print("security",JSON.stringify(s))); @@ -3368,7 +3833,7 @@ declare class NRF { * @param {any} key - 16 byte out of band key * @url http://www.espruino.com/Reference#l_NRF_nfcPair */ - static nfcPair(key: any): any; + static nfcPair(key: any): void; /** * Enables NFC with a record that will launch the given android app. @@ -3380,7 +3845,7 @@ declare class NRF { * @param {any} app - The unique identifier of the given Android App * @url http://www.espruino.com/Reference#l_NRF_nfcAndroidApp */ - static nfcAndroidApp(app: any): any; + static nfcAndroidApp(app: any): void; /** * Enables NFC and starts advertising with Raw data. For example: @@ -3392,12 +3857,13 @@ declare class NRF { * @param {any} payload - The NFC NDEF message to deliver to the reader * @url http://www.espruino.com/Reference#l_NRF_nfcRaw */ - static nfcRaw(payload: any): any; + static nfcRaw(payload: any): void; /** - * **Advanced NFC Functionality.** If you just want to advertise a URL, use `NRF.nfcURL` instead. - * Enables NFC and starts advertising. `NFCrx` events will be - * fired when data is received. + * **Advanced NFC Functionality.** If you just want to advertise a URL, use + * `NRF.nfcURL` instead. + * Enables NFC and starts advertising. `NFCrx` events will be fired when data is + * received. * ``` * NRF.nfcStart(); * ``` @@ -3409,7 +3875,8 @@ declare class NRF { static nfcStart(payload: any): any; /** - * **Advanced NFC Functionality.** If you just want to advertise a URL, use `NRF.nfcURL` instead. + * **Advanced NFC Functionality.** If you just want to advertise a URL, use + * `NRF.nfcURL` instead. * Disables NFC. * ``` * NRF.nfcStop(); @@ -3417,14 +3884,15 @@ declare class NRF { * * @url http://www.espruino.com/Reference#l_NRF_nfcStop */ - static nfcStop(): any; + static nfcStop(): void; /** - * **Advanced NFC Functionality.** If you just want to advertise a URL, use `NRF.nfcURL` instead. - * Acknowledges the last frame and optionally transmits a response. - * If payload is an array, then a array.length byte nfc frame is sent. - * If payload is a int, then a 4bit ACK/NACK is sent. - * **Note:** ```nfcSend``` should always be called after an ```NFCrx``` event. + * **Advanced NFC Functionality.** If you just want to advertise a URL, use + * `NRF.nfcURL` instead. + * Acknowledges the last frame and optionally transmits a response. If payload is + * an array, then a array.length byte nfc frame is sent. If payload is a int, then + * a 4bit ACK/NACK is sent. **Note:** ```nfcSend``` should always be called after + * an ```NFCrx``` event. * ``` * NRF.nfcSend(new Uint8Array([0x01, 0x02, ...])); * // or @@ -3436,19 +3904,21 @@ declare class NRF { * @param {any} payload - Optional tx data * @url http://www.espruino.com/Reference#l_NRF_nfcSend */ - static nfcSend(payload: any): any; + static nfcSend(payload: any): void; /** - * Send a USB HID report. HID must first be enabled with `NRF.setServices({}, {hid: hid_report})` + * Send a USB HID report. HID must first be enabled with `NRF.setServices({}, {hid: + * hid_report})` * * @param {any} data - Input report data as an array * @param {any} callback - A callback function to be called when the data is sent * @url http://www.espruino.com/Reference#l_NRF_sendHIDReport */ - static sendHIDReport(data: any, callback: any): any; + static sendHIDReport(data: any, callback: any): void; /** - * Check if Apple Notification Center Service (ANCS) is currently active on the BLE connection + * Check if Apple Notification Center Service (ANCS) is currently active on the BLE + * connection * * @returns {boolean} True if Apple Notification Center Service (ANCS) has been initialised and is active * @url http://www.espruino.com/Reference#l_NRF_ancsIsActive @@ -3456,13 +3926,14 @@ declare class NRF { static ancsIsActive(): boolean; /** - * Send an ANCS action for a specific Notification UID. Corresponds to posaction/negaction in the 'ANCS' event that was received + * Send an ANCS action for a specific Notification UID. Corresponds to + * posaction/negaction in the 'ANCS' event that was received * * @param {number} uid - The UID of the notification to respond to * @param {boolean} positive - `true` for positive action, `false` for negative * @url http://www.espruino.com/Reference#l_NRF_ancsAction */ - static ancsAction(uid: number, positive: boolean): any; + static ancsAction(uid: number, positive: boolean): void; /** * Get ANCS info for a notification, eg: @@ -3471,7 +3942,7 @@ declare class NRF { * @returns {any} A `Promise` that is resolved (or rejected) when the connection is complete * @url http://www.espruino.com/Reference#l_NRF_ancsGetNotificationInfo */ - static ancsGetNotificationInfo(uid: number): Promise; + static ancsGetNotificationInfo(uid: number): Promise; /** * Get ANCS info for an app (add id is available via `ancsGetNotificationInfo`) @@ -3495,7 +3966,7 @@ declare class NRF { * @returns {any} A `Promise` that is resolved (or rejected) when the connection is complete * @url http://www.espruino.com/Reference#l_NRF_ancsGetAppInfo */ - static ancsGetAppInfo(id: any): Promise; + static ancsGetAppInfo(id: any): Promise; /** * Check if Apple Media Service (AMS) is currently active on the BLE connection @@ -3506,21 +3977,24 @@ declare class NRF { static amsIsActive(): boolean; /** - * Get Apple Media Service (AMS) info for the current media player. - * "playbackinfo" returns a concatenation of three comma-separated values: - * - PlaybackState: a string that represents the integer value of the playback state: + * Get Apple Media Service (AMS) info for the current media player. "playbackinfo" + * returns a concatenation of three comma-separated values: + * - PlaybackState: a string that represents the integer value of the playback + * state: * - PlaybackStatePaused = 0 * - PlaybackStatePlaying = 1 * - PlaybackStateRewinding = 2 * - PlaybackStateFastForwarding = 3 - * - PlaybackRate: a string that represents the floating point value of the playback rate. - * - ElapsedTime: a string that represents the floating point value of the elapsed time of the current track, in seconds + * - PlaybackRate: a string that represents the floating point value of the + * playback rate. + * - ElapsedTime: a string that represents the floating point value of the elapsed + * time of the current track, in seconds * * @param {any} id - Either 'name', 'playbackinfo' or 'volume' * @returns {any} A `Promise` that is resolved (or rejected) when the connection is complete * @url http://www.espruino.com/Reference#l_NRF_amsGetPlayerInfo */ - static amsGetPlayerInfo(id: any): Promise; + static amsGetPlayerInfo(id: any): Promise; /** * Get Apple Media Service (AMS) info for the currently-playing track @@ -3529,36 +4003,47 @@ declare class NRF { * @returns {any} A `Promise` that is resolved (or rejected) when the connection is complete * @url http://www.espruino.com/Reference#l_NRF_amsGetTrackInfo */ - static amsGetTrackInfo(id: any): Promise; + static amsGetTrackInfo(id: any): Promise; /** * Send an AMS command to an Apple Media Service device to control music playback - * Command is one of play, pause, playpause, next, prev, volup, voldown, repeat, shuffle, skipforward, skipback, like, dislike, bookmark + * Command is one of play, pause, playpause, next, prev, volup, voldown, repeat, + * shuffle, skipforward, skipback, like, dislike, bookmark * * @param {any} id - For example, 'play', 'pause', 'volup' or 'voldown' * @url http://www.espruino.com/Reference#l_NRF_amsCommand */ - static amsCommand(id: any): any; + static amsCommand(id: any): void; /** - * Search for available devices matching the given filters. Since we have no UI here, - * Espruino will pick the FIRST device it finds, or it'll call `catch`. + * Search for available devices matching the given filters. Since we have no UI + * here, Espruino will pick the FIRST device it finds, or it'll call `catch`. * `options` can have the following fields: - * * `filters` - a list of filters that a device must match before it is returned (see below) - * * `timeout` - the maximum time to scan for in milliseconds (scanning stops when a match - * is found. eg. `NRF.requestDevice({ timeout:2000, filters: [ ... ] })` - * * `active` - whether to perform active scanning (requesting 'scan response' packets from any - * devices that are found). eg. `NRF.requestDevice({ active:true, filters: [ ... ] })` - * * `phy` - (NRF52840 only) use the long-range coded phy (`"1mbps"` default, can be `"1mbps/2mbps/both/coded"`) - * * `extended` - (NRF52840 only) support receiving extended-length advertising packets (default=true if phy isn't `"1mbps"`) + * * `filters` - a list of filters that a device must match before it is returned + * (see below) + * * `timeout` - the maximum time to scan for in milliseconds (scanning stops when + * a match is found. eg. `NRF.requestDevice({ timeout:2000, filters: [ ... ] })` + * * `active` - whether to perform active scanning (requesting 'scan response' + * packets from any devices that are found). eg. `NRF.requestDevice({ active:true, + * filters: [ ... ] })` + * * `phy` - (NRF52840 only) use the long-range coded phy (`"1mbps"` default, can + * be `"1mbps/2mbps/both/coded"`) + * * `extended` - (NRF52840 only) support receiving extended-length advertising + * packets (default=true if phy isn't `"1mbps"`) * **NOTE:** `timeout` and `active` are not part of the Web Bluetooth standard. * The following filter types are implemented: - * * `services` - list of services as strings (all of which must match). 128 bit services must be in the form '01230123-0123-0123-0123-012301230123' + * * `services` - list of services as strings (all of which must match). 128 bit + * services must be in the form '01230123-0123-0123-0123-012301230123' * * `name` - exact device name * * `namePrefix` - starting characters of device name - * * `id` - exact device address (`id:"e9:53:86:09:89:99 random"`) (this is Espruino-specific, and is not part of the Web Bluetooth spec) - * * `serviceData` - an object containing service characteristics which must all match (`serviceData:{"1809":{}}`). Matching of actual service data is not supported yet. - * * `manufacturerData` - an object containing manufacturer UUIDs which must all match (`manufacturerData:{0x0590:{}}`). Matching of actual manufacturer data is not supported yet. + * * `id` - exact device address (`id:"e9:53:86:09:89:99 random"`) (this is + * Espruino-specific, and is not part of the Web Bluetooth spec) + * * `serviceData` - an object containing service characteristics which must all + * match (`serviceData:{"1809":{}}`). Matching of actual service data is not + * supported yet. + * * `manufacturerData` - an object containing manufacturer UUIDs which must all + * match (`manufacturerData:{0x0590:{}}`). Matching of actual manufacturer data + * is not supported yet. * ``` * NRF.requestDevice({ filters: [{ namePrefix: 'Puck.js' }] }).then(function(device) { ... }); * // or @@ -3595,29 +4080,33 @@ declare class NRF { * ``` * Note that you have to keep track of the `gatt` variable so that you can * disconnect the Bluetooth connection when you're done. - * **Note:** Using a filter in `NRF.requestDevice` filters each advertising packet individually. As - * soon as a matching advertisement is received, `NRF.requestDevice` resolves the promise and stops - * scanning. This means that if you filter based on a service UUID and a device advertises with multiple packets - * (or a scan response when `active:true`) only the packet matching the filter is returned - you may not - * get the device's name is that was in a separate packet. To aggregate multiple packets you can use `NRF.findDevices`. + * **Note:** Using a filter in `NRF.requestDevice` filters each advertising packet + * individually. As soon as a matching advertisement is received, + * `NRF.requestDevice` resolves the promise and stops scanning. This means that if + * you filter based on a service UUID and a device advertises with multiple packets + * (or a scan response when `active:true`) only the packet matching the filter is + * returned - you may not get the device's name is that was in a separate packet. + * To aggregate multiple packets you can use `NRF.findDevices`. * * @param {any} options - Options used to filter the device to use * @returns {any} A `Promise` that is resolved (or rejected) when the connection is complete * @url http://www.espruino.com/Reference#l_NRF_requestDevice */ - static requestDevice(options: any): Promise; + static requestDevice(options?: { filters?: NRFFilters, timeout?: number, active?: boolean, phy?: string, extended?: boolean }): Promise; /** - * Connect to a BLE device by MAC address. Returns a promise, - * the argument of which is the `BluetoothRemoteGATTServer` connection. + * Connect to a BLE device by MAC address. Returns a promise, the argument of which + * is the `BluetoothRemoteGATTServer` connection. * ``` * NRF.connect("aa:bb:cc:dd:ee").then(function(server) { * // ... * }); * ``` - * This has the same effect as calling `BluetoothDevice.gatt.connect` on a `BluetoothDevice` requested - * using `NRF.requestDevice`. It just allows you to specify the address directly (without having to scan). - * You can use it as follows - this would connect to another Puck device and turn its LED on: + * This has the same effect as calling `BluetoothDevice.gatt.connect` on a + * `BluetoothDevice` requested using `NRF.requestDevice`. It just allows you to + * specify the address directly (without having to scan). + * You can use it as follows - this would connect to another Puck device and turn + * its LED on: * ``` * var gatt; * NRF.connect("aa:bb:cc:dd:ee random").then(function(g) { @@ -3632,59 +4121,62 @@ declare class NRF { * console.log("Done!"); * }); * ``` - * **Note:** Espruino Bluetooth devices use a type of BLE address known as 'random static', - * which is different to a 'public' address. To connect to an Espruino device you'll need - * to use an address string of the form `"aa:bb:cc:dd:ee random"` rather than just - * `"aa:bb:cc:dd:ee"`. If you scan for devices with `NRF.findDevices`/`NRF.setScan` then - * addresses are already reported in the correct format. + * **Note:** Espruino Bluetooth devices use a type of BLE address known as 'random + * static', which is different to a 'public' address. To connect to an Espruino + * device you'll need to use an address string of the form `"aa:bb:cc:dd:ee + * random"` rather than just `"aa:bb:cc:dd:ee"`. If you scan for devices with + * `NRF.findDevices`/`NRF.setScan` then addresses are already reported in the + * correct format. * * @param {any} mac - The MAC address to connect to * @param {any} options - (Espruino-specific) An object of connection options (see `BluetoothRemoteGATTServer.connect` for full details) * @returns {any} A `Promise` that is resolved (or rejected) when the connection is complete * @url http://www.espruino.com/Reference#l_NRF_connect */ - static connect(mac: any, options: any): Promise; + static connect(mac: any, options: any): Promise; /** - * If set to true, whenever a device bonds it will be added to the - * whitelist. - * When set to false, the whitelist is cleared and newly bonded - * devices will not be added to the whitelist. - * **Note:** This is remembered between `reset()`s but isn't - * remembered after power-on (you'll have to add it to `onInit()`. + * If set to true, whenever a device bonds it will be added to the whitelist. + * When set to false, the whitelist is cleared and newly bonded devices will not be + * added to the whitelist. + * **Note:** This is remembered between `reset()`s but isn't remembered after + * power-on (you'll have to add it to `onInit()`. * * @param {boolean} whitelisting - Are we using a whitelist? (default false) * @url http://www.espruino.com/Reference#l_NRF_setWhitelist */ - static setWhitelist(whitelisting: boolean): any; + static setWhitelist(whitelisting: boolean): void; /** - * When connected, Bluetooth LE devices communicate at a set interval. - * Lowering the interval (eg. more packets/second) means a lower delay when - * sending data, higher bandwidth, but also more power consumption. + * When connected, Bluetooth LE devices communicate at a set interval. Lowering the + * interval (eg. more packets/second) means a lower delay when sending data, higher + * bandwidth, but also more power consumption. * By default, when connected as a peripheral Espruino automatically adjusts the - * connection interval. When connected it's as fast as possible (7.5ms) but when idle - * for over a minute it drops to 200ms. On continued activity (>1 BLE operation) the - * interval is raised to 7.5ms again. + * connection interval. When connected it's as fast as possible (7.5ms) but when + * idle for over a minute it drops to 200ms. On continued activity (>1 BLE + * operation) the interval is raised to 7.5ms again. * The options for `interval` are: * * `undefined` / `"auto"` : (default) automatically adjust connection interval - * * `100` : set min and max connection interval to the same number (between 7.5ms and 4000ms) - * * `{minInterval:20, maxInterval:100}` : set min and max connection interval as a range - * This configuration is not remembered during a `save()` - you will have to - * re-set it via `onInit`. - * **Note:** If connecting to another device (as Central), you can use - * an extra argument to `NRF.connect` or `BluetoothRemoteGATTServer.connect` - * to specify a connection interval. - * **Note:** This overwrites any changes imposed by the deprecated `NRF.setLowPowerConnection` + * * `100` : set min and max connection interval to the same number (between 7.5ms + * and 4000ms) + * * `{minInterval:20, maxInterval:100}` : set min and max connection interval as a + * range + * This configuration is not remembered during a `save()` - you will have to re-set + * it via `onInit`. + * **Note:** If connecting to another device (as Central), you can use an extra + * argument to `NRF.connect` or `BluetoothRemoteGATTServer.connect` to specify a + * connection interval. + * **Note:** This overwrites any changes imposed by the deprecated + * `NRF.setLowPowerConnection` * * @param {any} interval - The connection interval to use (see below) * @url http://www.espruino.com/Reference#l_NRF_setConnectionInterval */ - static setConnectionInterval(interval: any): any; + static setConnectionInterval(interval: any): void; /** - * Sets the security options used when connecting/pairing. This applies to both central - * *and* peripheral mode. + * Sets the security options used when connecting/pairing. This applies to both + * central *and* peripheral mode. * ``` * NRF.setSecurity({ * display : bool // default false, can this device display a passkey @@ -3704,20 +4196,19 @@ declare class NRF { * ``` * **NOTE:** Some combinations of arguments will cause an error. For example * supplying a passkey without `display:1` is not allowed. If `display:1` is set - * you do not require a physical display, the user just needs to know - * the passkey you supplied. + * you do not require a physical display, the user just needs to know the passkey + * you supplied. * For instance, to require pairing and to specify a passkey, use: * ``` * NRF.setSecurity({passkey:"123456", mitm:1, display:1}); * ``` - * However, while most devices will request a passkey for pairing at - * this point it is still possible for a device to connect without - * requiring one (eg. using the 'NRF Connect' app). - * To force a passkey you need to protect each characteristic - * you define with `NRF.setSecurity`. For instance the following - * code will *require* that the passkey `123456` is entered - * before the characteristic `9d020002-bf5f-1d1a-b52a-fe52091d5b12` - * can be read. + * However, while most devices will request a passkey for pairing at this point it + * is still possible for a device to connect without requiring one (eg. using the + * 'NRF Connect' app). + * To force a passkey you need to protect each characteristic you define with + * `NRF.setSecurity`. For instance the following code will *require* that the + * passkey `123456` is entered before the characteristic + * `9d020002-bf5f-1d1a-b52a-fe52091d5b12` can be read. * ``` * NRF.setSecurity({passkey:"123456", mitm:1, display:1}); * NRF.setServices({ @@ -3756,17 +4247,18 @@ declare class NRF { * } * }); * ``` - * **Note:** If `passkey` or `oob` is specified, the Nordic UART service (if enabled) - * will automatically be set to require encryption, but otherwise it is open. + * **Note:** If `passkey` or `oob` is specified, the Nordic UART service (if + * enabled) will automatically be set to require encryption, but otherwise it is + * open. * * @param {any} options - An object containing security-related options (see below) * @url http://www.espruino.com/Reference#l_NRF_setSecurity */ - static setSecurity(options: any): any; + static setSecurity(options: any): void; /** - * Return an object with information about the security - * state of the current peripheral connection: + * Return an object with information about the security state of the current + * peripheral connection: * ``` * { * connected // The connection is active (not disconnected). @@ -3790,6 +4282,8 @@ declare class NRF { * @url http://www.espruino.com/Reference#l_NRF_startBonding */ static startBonding(forceRepair: boolean): any; + + } /** @@ -3799,11 +4293,14 @@ declare class Bluetooth { /** * @url http://www.espruino.com/Reference#l_Bluetooth_setConsole */ - static setConsole(): any; + static setConsole(): void; + + } /** - * A Web Bluetooth-style device - you can request one using `NRF.requestDevice(address)` + * A Web Bluetooth-style device - you can request one using + * `NRF.requestDevice(address)` * For example: * ``` * var gatt; @@ -3826,8 +4323,8 @@ declare class Bluetooth { declare class BluetoothDevice { /** * Called when the device gets disconnected. - * To connect and then print `Disconnected` when the device is - * disconnected, just do the following: + * To connect and then print `Disconnected` when the device is disconnected, just + * do the following: * ``` * var gatt; * NRF.connect("aa:bb:cc:dd:ee:ff").then(function(gatt) { @@ -3854,7 +4351,8 @@ declare class BluetoothDevice { /** * Called when the device pairs and sends a passkey that Espruino should display. - * For this to be used, you'll have to specify that there's a display using `NRF.setSecurity` + * For this to be used, you'll have to specify that there's a display using + * `NRF.setSecurity` * **This is not part of the Web Bluetooth Specification.** It has been added * specifically for Espruino. * @param {string} event - The event to listen to. @@ -3865,16 +4363,21 @@ declare class BluetoothDevice { static on(event: "passkey", callback: (passkey: any) => void): void; /** - * Called when the device pairs, displays a passkey, and wants Espruino to tell it what the passkey was. - * Respond with `BluetoothDevice.sendPasskey()` with a 6 character string containing only `0..9`. - * For this to be used, you'll have to specify that there's a keyboard using `NRF.setSecurity` + * Called when the device pairs, displays a passkey, and wants Espruino to tell it + * what the passkey was. + * Respond with `BluetoothDevice.sendPasskey()` with a 6 character string + * containing only `0..9`. + * For this to be used, you'll have to specify that there's a keyboard using + * `NRF.setSecurity` * **This is not part of the Web Bluetooth Specification.** It has been added * specifically for Espruino. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_BluetoothDevice_passkeyRequest */ - static on(event: "passkeyRequest", callback: () => void): void;/** + static on(event: "passkeyRequest", callback: () => void): void; + + /** * @returns {any} A `BluetoothRemoteGATTServer` for this device * @url http://www.espruino.com/Reference#l_BluetoothDevice_gatt */ @@ -3887,26 +4390,29 @@ declare class BluetoothDevice { rssi: boolean; /** - * To be used as a response when the event `BluetoothDevice.sendPasskey` has been received. + * To be used as a response when the event `BluetoothDevice.sendPasskey` has been + * received. * **This is not part of the Web Bluetooth Specification.** It has been added * specifically for Espruino. * * @param {any} passkey - A 6 character numeric String to be returned to the device * @url http://www.espruino.com/Reference#l_BluetoothDevice_sendPasskey */ - sendPasskey(passkey: any): any; + sendPasskey(passkey: any): void; } /** - * Web Bluetooth-style GATT server - get this using `NRF.connect(address)` - * or `NRF.requestDevice(options)` and `response.gatt.connect` + * Web Bluetooth-style GATT server - get this using `NRF.connect(address)` or + * `NRF.requestDevice(options)` and `response.gatt.connect` * https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver * @url http://www.espruino.com/Reference#BluetoothRemoteGATTServer */ declare class BluetoothRemoteGATTServer { + + /** - * Connect to a BLE device - returns a promise, - * the argument of which is the `BluetoothRemoteGATTServer` connection. + * Connect to a BLE device - returns a promise, the argument of which is the + * `BluetoothRemoteGATTServer` connection. * See [`NRF.requestDevice`](/Reference#l_NRF_requestDevice) for usage examples. * `options` is an optional object containing: * ``` @@ -3915,26 +4421,27 @@ declare class BluetoothRemoteGATTServer { * maxInterval // max connection interval in milliseconds, 7.5 ms to 4 s * } * ``` - * By default the interval is 20-200ms (or 500-1000ms if `NRF.setLowPowerConnection(true)` was called. - * During connection Espruino negotiates with the other device to find a common interval that can be - * used. + * By default the interval is 20-200ms (or 500-1000ms if + * `NRF.setLowPowerConnection(true)` was called. During connection Espruino + * negotiates with the other device to find a common interval that can be used. * For instance calling: * ``` * NRF.requestDevice({ filters: [{ namePrefix: 'Pixl.js' }] }).then(function(device) { * return device.gatt.connect({minInterval:7.5, maxInterval:7.5}); * }).then(function(g) { * ``` - * will force the connection to use the fastest connection interval possible (as long as the device - * at the other end supports it). - * **Note:** The Web Bluetooth spec states that if a device hasn't advertised its name, when connected - * to a device the central (in this case Espruino) should automatically retrieve the name from the - * corresponding characteristic (`0x2a00` on service `0x1800`). Espruino does not automatically do this. + * will force the connection to use the fastest connection interval possible (as + * long as the device at the other end supports it). + * **Note:** The Web Bluetooth spec states that if a device hasn't advertised its + * name, when connected to a device the central (in this case Espruino) should + * automatically retrieve the name from the corresponding characteristic (`0x2a00` + * on service `0x1800`). Espruino does not automatically do this. * * @param {any} options - (Espruino-specific) An object of connection options (see below) * @returns {any} A `Promise` that is resolved (or rejected) when the connection is complete * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTServer_connect */ - connect(options: any): Promise; + connect(options: any): Promise; /** * @returns {boolean} Whether the device is connected or not @@ -3950,20 +4457,20 @@ declare class BluetoothRemoteGATTServer { /** * Disconnect from a previously connected BLE device connected with - * `BluetoothRemoteGATTServer.connect` - this does not disconnect from something that has - * connected to the Espruino. - * **Note:** While `.disconnect` is standard Web Bluetooth, in the spec it - * returns undefined not a `Promise` for implementation reasons. In Espruino - * we return a `Promise` to make it easier to detect when Espruino is free - * to connect to something else. + * `BluetoothRemoteGATTServer.connect` - this does not disconnect from something + * that has connected to the Espruino. + * **Note:** While `.disconnect` is standard Web Bluetooth, in the spec it returns + * undefined not a `Promise` for implementation reasons. In Espruino we return a + * `Promise` to make it easier to detect when Espruino is free to connect to + * something else. * @returns {any} A `Promise` that is resolved (or rejected) when the disconnection is complete (non-standard) * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTServer_disconnect */ - disconnect(): Promise; + disconnect(): Promise; /** - * Start negotiating bonding (secure communications) with the connected device, - * and return a Promise that is completed on success or failure. + * Start negotiating bonding (secure communications) with the connected device, and + * return a Promise that is completed on success or failure. * ``` * var gatt; * NRF.requestDevice({ filters: [{ name: 'Puck.js abcd' }] }).then(function(device) { @@ -3987,11 +4494,11 @@ declare class BluetoothRemoteGATTServer { * @returns {any} A `Promise` that is resolved (or rejected) when the bonding is complete * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTServer_startBonding */ - startBonding(forceRePair: boolean): Promise; + startBonding(forceRePair: boolean): Promise; /** - * Return an object with information about the security - * state of the current connection: + * Return an object with information about the security state of the current + * connection: * ``` * { * connected // The connection is active (not disconnected). @@ -4000,8 +4507,8 @@ declare class BluetoothRemoteGATTServer { * bonded // The peer is bonded with us * } * ``` - * See `BluetoothRemoteGATTServer.startBonding` for information about - * negotiating a secure connection. + * See `BluetoothRemoteGATTServer.startBonding` for information about negotiating a + * secure connection. * **This is not part of the Web Bluetooth Specification.** It has been added * specifically for Puck.js. * @returns {any} An object @@ -4016,13 +4523,13 @@ declare class BluetoothRemoteGATTServer { * @returns {any} A `Promise` that is resolved (or rejected) when the primary service is found (the argument contains a `BluetoothRemoteGATTService`) * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTServer_getPrimaryService */ - getPrimaryService(service: any): Promise; + getPrimaryService(service: any): Promise; /** * @returns {any} A `Promise` that is resolved (or rejected) when the primary services are found (the argument contains an array of `BluetoothRemoteGATTService`) * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTServer_getPrimaryServices */ - getPrimaryServices(): Promise; + getPrimaryServices(): Promise; /** * Start/stop listening for RSSI values on the active GATT connection @@ -4039,15 +4546,18 @@ declare class BluetoothRemoteGATTServer { * @param {any} callback - The callback to call with the RSSI value, or undefined to stop * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTServer_setRSSIHandler */ - setRSSIHandler(callback: any): any; + setRSSIHandler(callback: any): void; } /** - * Web Bluetooth-style GATT service - get this using `BluetoothRemoteGATTServer.getPrimaryService(s)` + * Web Bluetooth-style GATT service - get this using + * `BluetoothRemoteGATTServer.getPrimaryService(s)` * https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice * @url http://www.espruino.com/Reference#BluetoothRemoteGATTService */ declare class BluetoothRemoteGATTService { + + /** * @returns {any} The `BluetoothDevice` this Service came from * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTService_device @@ -4061,23 +4571,25 @@ declare class BluetoothRemoteGATTService { * @returns {any} A `Promise` that is resolved (or rejected) when the characteristic is found (the argument contains a `BluetoothRemoteGATTCharacteristic`) * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTService_getCharacteristic */ - getCharacteristic(characteristic: any): Promise; + getCharacteristic(characteristic: any): Promise; /** * @returns {any} A `Promise` that is resolved (or rejected) when the characteristic is found (the argument contains an array of `BluetoothRemoteGATTCharacteristic`) * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTService_getCharacteristics */ - getCharacteristics(): Promise; + getCharacteristics(): Promise; } /** - * Web Bluetooth-style GATT characteristic - get this using `BluetoothRemoteGATTService.getCharacteristic(s)` + * Web Bluetooth-style GATT characteristic - get this using + * `BluetoothRemoteGATTService.getCharacteristic(s)` * https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic * @url http://www.espruino.com/Reference#BluetoothRemoteGATTCharacteristic */ declare class BluetoothRemoteGATTCharacteristic { /** - * Called when a characteristic's value changes, *after* `BluetoothRemoteGATTCharacteristic.startNotifications` has been called. + * Called when a characteristic's value changes, *after* + * `BluetoothRemoteGATTCharacteristic.startNotifications` has been called. * ``` * ... * return service.getCharacteristic("characteristic_uuid"); @@ -4088,13 +4600,17 @@ declare class BluetoothRemoteGATTCharacteristic { * return c.startNotifications(); * }).then(... * ``` - * The first argument is of the form `{target : BluetoothRemoteGATTCharacteristic}`, and `BluetoothRemoteGATTCharacteristic.value` - * will then contain the new value (as a DataView). + * The first argument is of the form `{target : + * BluetoothRemoteGATTCharacteristic}`, and + * `BluetoothRemoteGATTCharacteristic.value` will then contain the new value (as a + * DataView). * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTCharacteristic_characteristicvaluechanged */ - static on(event: "characteristicvaluechanged", callback: () => void): void;/** + static on(event: "characteristicvaluechanged", callback: () => void): void; + + /** * @returns {any} The `BluetoothRemoteGATTService` this Service came from * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTCharacteristic_service */ @@ -4123,7 +4639,7 @@ declare class BluetoothRemoteGATTCharacteristic { * @returns {any} A `Promise` that is resolved (or rejected) when the characteristic is written * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTCharacteristic_writeValue */ - writeValue(data: any): Promise; + writeValue(data: any): Promise; /** * Read a characteristic's value, return a promise containing a `DataView` @@ -4147,11 +4663,12 @@ declare class BluetoothRemoteGATTCharacteristic { * @returns {any} A `Promise` that is resolved (or rejected) with a `DataView` when the characteristic is read * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTCharacteristic_readValue */ - readValue(): Promise; + readValue(): Promise; /** - * Starts notifications - whenever this characteristic's value changes, a `characteristicvaluechanged` event is fired - * and `characteristic.value` will then contain the new value as a `DataView`. + * Starts notifications - whenever this characteristic's value changes, a + * `characteristicvaluechanged` event is fired and `characteristic.value` will then + * contain the new value as a `DataView`. * ``` * var device; * NRF.connect(device_address).then(function(d) { @@ -4171,8 +4688,8 @@ declare class BluetoothRemoteGATTCharacteristic { * console.log("Something's broken."); * }); * ``` - * For example, to listen to the output of another Puck.js's Nordic - * Serial port service, you can use: + * For example, to listen to the output of another Puck.js's Nordic Serial port + * service, you can use: * ``` * var gatt; * NRF.connect("pu:ck:js:ad:dr:es random").then(function(g) { @@ -4192,18 +4709,20 @@ declare class BluetoothRemoteGATTCharacteristic { * @returns {any} A `Promise` that is resolved (or rejected) with data when notifications have been added * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTCharacteristic_startNotifications */ - startNotifications(): Promise; + startNotifications(): Promise; /** - * Stop notifications (that were requested with `BluetoothRemoteGATTCharacteristic.startNotifications`) + * Stop notifications (that were requested with + * `BluetoothRemoteGATTCharacteristic.startNotifications`) * @returns {any} A `Promise` that is resolved (or rejected) with data when notifications have been removed * @url http://www.espruino.com/Reference#l_BluetoothRemoteGATTCharacteristic_stopNotifications */ - stopNotifications(): Promise; + stopNotifications(): Promise; } /** - * Class containing utility functions for the [Bangle.js Smart Watch](http://www.espruino.com/Bangle.js) + * Class containing utility functions for the [Bangle.js Smart + * Watch](http://www.espruino.com/Bangle.js) * @url http://www.espruino.com/Reference#Bangle */ declare class Bangle { @@ -4220,7 +4739,7 @@ declare class Bangle { * * `xyz` * @url http://www.espruino.com/Reference#l_Bangle_accel */ - static on(event: "accel", callback: (xyz: any) => void): void; + static on(event: "accel", callback: (xyz: AccelData) => void): void; /** * Called whenever a step is detected by Bangle.js's pedometer. @@ -4232,14 +4751,14 @@ declare class Bangle { static on(event: "step", callback: (up: number) => void): void; /** - * See `Bangle.getHealthStatus()` for more information. This is used for health tracking to - * allow Bangle.js to record historical exercise data. + * See `Bangle.getHealthStatus()` for more information. This is used for health + * tracking to allow Bangle.js to record historical exercise data. * @param {string} event - The event to listen to. * @param {(info: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `info` An object containing the last 10 minutes health data * @url http://www.espruino.com/Reference#l_Bangle_health */ - static on(event: "health", callback: (info: any) => void): void; + static on(event: "health", callback: (info: HealthStatus) => void): void; /** * Has the watch been moved so that it is face-up, or not face up? @@ -4251,7 +4770,8 @@ declare class Bangle { static on(event: "faceUp", callback: (up: boolean) => void): void; /** - * This event happens when the watch has been twisted around it's axis - for instance as if it was rotated so someone could look at the time. + * This event happens when the watch has been twisted around it's axis - for + * instance as if it was rotated so someone could look at the time. * To tweak when this happens, see the `twist*` options in `Bangle.setOptions()` * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. @@ -4269,31 +4789,31 @@ declare class Bangle { static on(event: "charging", callback: (charging: boolean) => void): void; /** - * Magnetometer/Compass data available with `{x,y,z,dx,dy,dz,heading}` object as a parameter + * Magnetometer/Compass data available with `{x,y,z,dx,dy,dz,heading}` object as a + * parameter * * `x/y/z` raw x,y,z magnetometer readings * * `dx/dy/dz` readings based on calibration since magnetometer turned on - * * `heading` in degrees based on calibrated readings (will be NaN if magnetometer hasn't been rotated around 360 degrees) - * To get this event you must turn the compass on - * with `Bangle.setCompassPower(1)`. + * * `heading` in degrees based on calibrated readings (will be NaN if magnetometer + * hasn't been rotated around 360 degrees) + * To get this event you must turn the compass on with `Bangle.setCompassPower(1)`. * You can also retrieve the most recent reading with `Bangle.getCompass()`. * @param {string} event - The event to listen to. * @param {(xyz: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `xyz` * @url http://www.espruino.com/Reference#l_Bangle_mag */ - static on(event: "mag", callback: (xyz: any) => void): void; + static on(event: "mag", callback: (xyz: CompassData) => void): void; /** * Raw NMEA GPS / u-blox data messages received as a string - * To get this event you must turn the GPS on - * with `Bangle.setGPSPower(1)`. + * To get this event you must turn the GPS on with `Bangle.setGPSPower(1)`. * @param {string} event - The event to listen to. * @param {(nmea: any, dataLoss: boolean) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `nmea` A string containing the raw NMEA data from the GPS * * `dataLoss` This is set to true if some lines of GPS data have previously been lost (eg because system was too busy to queue up a GPS-raw event) * @url http://www.espruino.com/Reference#l_Bangle_GPS-raw */ - static on(event: "GPS-raw", callback: (nmea: any, dataLoss: boolean) => void): void; + static on(event: "GPS-raw", callback: (nmea: string, dataLoss: boolean) => void): void; /** * GPS data, as an object. Contains: @@ -4310,18 +4830,17 @@ declare class Bangle { * } * ``` * If a value such as `lat` is not known because there is no fix, it'll be `NaN`. - * `hdop` is a value from the GPS receiver that gives a rough idea of accuracy - * of lat/lon based on the geometry of the satellites in range. Multiply by 5 to - * get a value in meters. This is just a ballpark estimation and should - * not be considered remotely accurate. - * To get this event you must turn the GPS on - * with `Bangle.setGPSPower(1)`. + * `hdop` is a value from the GPS receiver that gives a rough idea of accuracy of + * lat/lon based on the geometry of the satellites in range. Multiply by 5 to get a + * value in meters. This is just a ballpark estimation and should not be considered + * remotely accurate. + * To get this event you must turn the GPS on with `Bangle.setGPSPower(1)`. * @param {string} event - The event to listen to. * @param {(fix: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `fix` An object with fix info (see below) * @url http://www.espruino.com/Reference#l_Bangle_GPS */ - static on(event: "GPS", callback: (fix: any) => void): void; + static on(event: "GPS", callback: (fix: GPSFix) => void): void; /** * Heat rate data, as an object. Contains: @@ -4331,14 +4850,14 @@ declare class Bangle { * "raw": Uint8Array, // raw samples from heart rate monitor * } * ``` - * To get this event you must turn the heart rate monitor on - * with `Bangle.setHRMPower(1)`. + * To get this event you must turn the heart rate monitor on with + * `Bangle.setHRMPower(1)`. * @param {string} event - The event to listen to. * @param {(hrm: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `hrm` An object with heart rate info (see below) * @url http://www.espruino.com/Reference#l_Bangle_HRM */ - static on(event: "HRM", callback: (hrm: any) => void): void; + static on(event: "HRM", callback: (hrm: { bpm: number, confidence: number, raw: Uint8Array }) => void): void; /** * Called when heart rate sensor data is available - see `Bangle.setHRMPower(1)`. @@ -4355,20 +4874,22 @@ declare class Bangle { * * `hrm` A object containing instant readings from the heart rate sensor * @url http://www.espruino.com/Reference#l_Bangle_HRM-raw */ - static on(event: "HRM-raw", callback: (hrm: any) => void): void; + static on(event: "HRM-raw", callback: (hrm: { raw: number, filt: number, bpm: number, confidence: number }) => void): void; /** - * When `Bangle.setBarometerPower(true)` is called, this event is fired containing barometer readings. + * When `Bangle.setBarometerPower(true)` is called, this event is fired containing + * barometer readings. * Same format as `Bangle.getPressure()` * @param {string} event - The event to listen to. * @param {(e: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `e` An object containing `{temperature,pressure,altitude}` * @url http://www.espruino.com/Reference#l_Bangle_pressure */ - static on(event: "pressure", callback: (e: any) => void): void; + static on(event: "pressure", callback: (e: PressureData) => void): void; /** - * Has the screen been turned on or off? Can be used to stop tasks that are no longer useful if nothing is displayed. Also see `Bangle.isLCDOn()` + * Has the screen been turned on or off? Can be used to stop tasks that are no + * longer useful if nothing is displayed. Also see `Bangle.isLCDOn()` * @param {string} event - The event to listen to. * @param {(on: boolean) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `on` `true` if screen is on @@ -4386,8 +4907,10 @@ declare class Bangle { static on(event: "lock", callback: (on: boolean) => void): void; /** - * If the watch is tapped, this event contains information on the way it was tapped. - * `dir` reports the side of the watch that was tapped (not the direction it was tapped in). + * If the watch is tapped, this event contains information on the way it was + * tapped. + * `dir` reports the side of the watch that was tapped (not the direction it was + * tapped in). * ``` * { * dir : "left/right/top/bottom/front/back", @@ -4401,7 +4924,7 @@ declare class Bangle { * * `data` `{dir, double, x, y, z}` * @url http://www.espruino.com/Reference#l_Bangle_tap */ - static on(event: "tap", callback: (data: any) => void): void; + static on(event: "tap", callback: (data: { dir: "left" | "right" | "top" | "bottom" | "front" | "back", double: boolean, x: TapAxis, y: TapAxis, z: TapAxis }) => void): void; /** * Emitted when a 'gesture' (fast movement) is detected @@ -4410,31 +4933,33 @@ declare class Bangle { * * `xyz` An Int8Array of XYZXYZXYZ data * @url http://www.espruino.com/Reference#l_Bangle_gesture */ - static on(event: "gesture", callback: (xyz: any) => void): void; + static on(event: "gesture", callback: (xyz: Int8Array) => void): void; /** - * Emitted when a 'gesture' (fast movement) is detected, and a Tensorflow model is in - * storage in the `".tfmodel"` file. - * If a `".tfnames"` file is specified as a comma-separated list of names, it will be used - * to decode `gesture` from a number into a string. + * Emitted when a 'gesture' (fast movement) is detected, and a Tensorflow model is + * in storage in the `".tfmodel"` file. + * If a `".tfnames"` file is specified as a comma-separated list of names, it will + * be used to decode `gesture` from a number into a string. * @param {string} event - The event to listen to. * @param {(gesture: any, weights: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `gesture` The name of the gesture (if '.tfnames' exists, or the index. 'undefined' if not matching * * `weights` An array of floating point values output by the model * @url http://www.espruino.com/Reference#l_Bangle_aiGesture */ - static on(event: "aiGesture", callback: (gesture: any, weights: any) => void): void; + static on(event: "aiGesture", callback: (gesture: string | undefined, weights: number[]) => void): void; /** - * Emitted when a swipe on the touchscreen is detected (a movement from left->right, right->left, down->up or up->down) - * Bangle.js 1 is only capable of detecting left/right swipes as it only contains a 2 zone touchscreen. + * Emitted when a swipe on the touchscreen is detected (a movement from + * left->right, right->left, down->up or up->down) + * Bangle.js 1 is only capable of detecting left/right swipes as it only contains a + * 2 zone touchscreen. * @param {string} event - The event to listen to. * @param {(directionLR: number, directionUD: number) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `directionLR` `-1` for left, `1` for right, `0` for up/down * * `directionUD` `-1` for up, `1` for down, `0` for left/right (Bangle.js 2 only) * @url http://www.espruino.com/Reference#l_Bangle_swipe */ - static on(event: "swipe", callback: (directionLR: number, directionUD: number) => void): void; + static on(event: "swipe", callback: SwipeCallback): void; /** * Emitted when the touchscreen is pressed @@ -4444,26 +4969,28 @@ declare class Bangle { * * `xy` Object of form `{x,y}` containing touch coordinates (if the device supports full touch). Clipped to 0..175 (LCD pixel coordinates) on firmware 2v13 and later. * @url http://www.espruino.com/Reference#l_Bangle_touch */ - static on(event: "touch", callback: (button: number, xy: any) => void): void; + static on(event: "touch", callback: TouchCallback): void; /** * Emitted when the touchscreen is dragged or released - * The touchscreen extends past the edge of the screen and while - * `x` and `y` coordinates are arranged such that they align with - * the LCD's pixels, if your finger goes towards the edge of the - * screen, `x` and `y` could end up larger than 175 (the screen's maximum pixel coordinates) - * or smaller than 0. Coordinates from the `touch` event are clipped. + * The touchscreen extends past the edge of the screen and while `x` and `y` + * coordinates are arranged such that they align with the LCD's pixels, if your + * finger goes towards the edge of the screen, `x` and `y` could end up larger than + * 175 (the screen's maximum pixel coordinates) or smaller than 0. Coordinates from + * the `touch` event are clipped. * @param {string} event - The event to listen to. * @param {(event: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `event` Object of form `{x,y,dx,dy,b}` containing touch coordinates, difference in touch coordinates, and an integer `b` containing number of touch points (currently 1 or 0) * @url http://www.espruino.com/Reference#l_Bangle_drag */ - static on(event: "drag", callback: (event: any) => void): void; + static on(event: "drag", callback: DragCallback): void; /** - * Emitted when the touchscreen is dragged for a large enough distance to count as a gesture. - * If Bangle.strokes is defined and populated with data from `Unistroke.new`, the `event` argument will also - * contain a `stroke` field containing the most closely matching stroke name. + * Emitted when the touchscreen is dragged for a large enough distance to count as + * a gesture. + * If Bangle.strokes is defined and populated with data from `Unistroke.new`, the + * `event` argument will also contain a `stroke` field containing the most closely + * matching stroke name. * For example: * ``` * Bangle.strokes = { @@ -4485,7 +5012,7 @@ declare class Bangle { * * `event` Object of form `{xy:Uint8Array([x1,y1,x2,y2...])}` containing touch coordinates * @url http://www.espruino.com/Reference#l_Bangle_stroke */ - static on(event: "stroke", callback: (event: any) => void): void; + static on(event: "stroke", callback: (event: { xy: Uint8Array, stroke?: string }) => void): void; /** * Emitted at midnight (at the point the `day` health info is reset to 0). @@ -4498,30 +5025,29 @@ declare class Bangle { /** * This function can be used to turn Bangle.js's LCD off or on. - * This function resets the Bangle's 'activity timer' (like - * pressing a button or the screen would) so after a time period - * of inactivity set by `Bangle.setLCDTimeout` the screen will - * turn off. - * If you want to keep the screen on permanently (until apps - * are changed) you can do: + * This function resets the Bangle's 'activity timer' (like pressing a button or + * the screen would) so after a time period of inactivity set by + * `Bangle.setLCDTimeout` the screen will turn off. + * If you want to keep the screen on permanently (until apps are changed) you can + * do: * ``` * Bangle.setLCDTimeout(0); // turn off the timeout * Bangle.setLCDPower(1); // keep screen on * ``` - * **When on full, the LCD draws roughly 40mA.** You can adjust - * When brightness using `Bange.setLCDBrightness`. + * **When on full, the LCD draws roughly 40mA.** You can adjust When brightness + * using `Bangle.setLCDBrightness`. * * @param {boolean} isOn - True if the LCD should be on, false if not * @url http://www.espruino.com/Reference#l_Bangle_setLCDPower */ - static setLCDPower(isOn: boolean): any; + static setLCDPower(isOn: boolean): void; /** * This function can be used to adjust the brightness of Bangle.js's display, and * hence prolong its battery life. - * Due to hardware design constraints, software PWM has to be used which - * means that the display may flicker slightly when Bluetooth is active - * and the display is not at full power. + * Due to hardware design constraints, software PWM has to be used which means that + * the display may flicker slightly when Bluetooth is active and the display is not + * at full power. * **Power consumption** * * 0 = 7mA * * 0.1 = 12mA @@ -4533,21 +5059,32 @@ declare class Bangle { * @param {number} brightness - The brightness of Bangle.js's display - from 0(off) to 1(on full) * @url http://www.espruino.com/Reference#l_Bangle_setLCDBrightness */ - static setLCDBrightness(brightness: number): any; + static setLCDBrightness(brightness: number): void; /** * This function can be used to change the way graphics is handled on Bangle.js. * Available options for `Bangle.setLCDMode` are: - * * `Bangle.setLCDMode()` or `Bangle.setLCDMode("direct")` (the default) - The drawable area is 240x240 16 bit. Unbuffered, so draw calls take effect immediately. Terminal and vertical scrolling work (horizontal scrolling doesn't). - * * `Bangle.setLCDMode("doublebuffered")` - The drawable area is 240x160 16 bit, terminal and scrolling will not work. `g.flip()` must be called for draw operations to take effect. - * * `Bangle.setLCDMode("120x120")` - The drawable area is 120x120 8 bit, `g.getPixel`, terminal, and full scrolling work. Uses an offscreen buffer stored on Bangle.js, `g.flip()` must be called for draw operations to take effect. - * * `Bangle.setLCDMode("80x80")` - The drawable area is 80x80 8 bit, `g.getPixel`, terminal, and full scrolling work. Uses an offscreen buffer stored on Bangle.js, `g.flip()` must be called for draw operations to take effect. - * You can also call `Bangle.setLCDMode()` to return to normal, unbuffered `"direct"` mode. + * * `Bangle.setLCDMode()` or `Bangle.setLCDMode("direct")` (the default) - The + * drawable area is 240x240 16 bit. Unbuffered, so draw calls take effect + * immediately. Terminal and vertical scrolling work (horizontal scrolling + * doesn't). + * * `Bangle.setLCDMode("doublebuffered")` - The drawable area is 240x160 16 bit, + * terminal and scrolling will not work. `g.flip()` must be called for draw + * operations to take effect. + * * `Bangle.setLCDMode("120x120")` - The drawable area is 120x120 8 bit, + * `g.getPixel`, terminal, and full scrolling work. Uses an offscreen buffer + * stored on Bangle.js, `g.flip()` must be called for draw operations to take + * effect. + * * `Bangle.setLCDMode("80x80")` - The drawable area is 80x80 8 bit, `g.getPixel`, + * terminal, and full scrolling work. Uses an offscreen buffer stored on + * Bangle.js, `g.flip()` must be called for draw operations to take effect. + * You can also call `Bangle.setLCDMode()` to return to normal, unbuffered + * `"direct"` mode. * * @param {any} mode - The LCD mode (See below) * @url http://www.espruino.com/Reference#l_Bangle_setLCDMode */ - static setLCDMode(mode: any): any; + static setLCDMode(mode?: LCDMode): void; /** * The current LCD mode. @@ -4555,7 +5092,7 @@ declare class Bangle { * @returns {any} The LCD mode as a String * @url http://www.espruino.com/Reference#l_Bangle_getLCDMode */ - static getLCDMode(): any; + static getLCDMode(): LCDMode; /** * This can be used to move the displayed memory area up or down temporarily. It's @@ -4565,68 +5102,97 @@ declare class Bangle { * @param {number} y - The amount of pixels to shift the LCD up or down * @url http://www.espruino.com/Reference#l_Bangle_setLCDOffset */ - static setLCDOffset(y: number): any; + static setLCDOffset(y: number): void; /** * This function can be used to turn Bangle.js's LCD power saving on or off. - * With power saving off, the display will remain in the state you set it with `Bangle.setLCDPower`. - * With power saving on, the display will turn on if a button is pressed, the watch is turned face up, or the screen is updated (see `Bangle.setOptions` for configuration). It'll turn off automatically after the given timeout. - * **Note:** This function also sets the Backlight and Lock timeout (the time at which the touchscreen/buttons start being ignored). To set both separately, use `Bangle.setOptions` + * With power saving off, the display will remain in the state you set it with + * `Bangle.setLCDPower`. + * With power saving on, the display will turn on if a button is pressed, the watch + * is turned face up, or the screen is updated (see `Bangle.setOptions` for + * configuration). It'll turn off automatically after the given timeout. + * **Note:** This function also sets the Backlight and Lock timeout (the time at + * which the touchscreen/buttons start being ignored). To set both separately, use + * `Bangle.setOptions` * * @param {number} isOn - The timeout of the display in seconds, or `0`/`undefined` to turn power saving off. Default is 10 seconds. * @url http://www.espruino.com/Reference#l_Bangle_setLCDTimeout */ - static setLCDTimeout(isOn: number): any; + static setLCDTimeout(isOn: number): void; /** - * Set how often the watch should poll for new acceleration/gyro data and kick the Watchdog timer. It isn't - * recommended that you make this interval much larger than 1000ms, but values up to 4000ms are allowed. - * Calling this will set `Bangle.setOptions({powerSave: false})` - disabling the dynamic adjustment of - * poll interval to save battery power when Bangle.js is stationary. + * Set how often the watch should poll for new acceleration/gyro data and kick the + * Watchdog timer. It isn't recommended that you make this interval much larger + * than 1000ms, but values up to 4000ms are allowed. + * Calling this will set `Bangle.setOptions({powerSave: false})` - disabling the + * dynamic adjustment of poll interval to save battery power when Bangle.js is + * stationary. * * @param {number} interval - Polling interval in milliseconds (Default is 80ms - 12.5Hz to match accelerometer) * @url http://www.espruino.com/Reference#l_Bangle_setPollInterval */ - static setPollInterval(interval: number): any; + static setPollInterval(interval: number): void; /** * Set internal options used for gestures, etc... * * `wakeOnBTN1` should the LCD turn on when BTN1 is pressed? default = `true` - * * `wakeOnBTN2` (Bangle.js 1) should the LCD turn on when BTN2 is pressed? default = `true` - * * `wakeOnBTN3` (Bangle.js 1) should the LCD turn on when BTN3 is pressed? default = `true` - * * `wakeOnFaceUp` should the LCD turn on when the watch is turned face up? default = `false` - * * `wakeOnTouch` should the LCD turn on when the touchscreen is pressed? default = `false` - * * `wakeOnTwist` should the LCD turn on when the watch is twisted? default = `true` - * * `twistThreshold` How much acceleration to register a twist of the watch strap? Can be negative for oppsite direction. default = `800` - * * `twistMaxY` Maximum acceleration in Y to trigger a twist (low Y means watch is facing the right way up). default = `-800` - * * `twistTimeout` How little time (in ms) must a twist take from low->high acceleration? default = `1000` - * * `gestureStartThresh` how big a difference before we consider a gesture started? default = `sqr(800)` - * * `gestureEndThresh` how small a difference before we consider a gesture ended? default = `sqr(2000)` - * * `gestureInactiveCount` how many samples do we keep after a gesture has ended? default = `4` - * * `gestureMinLength` how many samples must a gesture have before we notify about it? default = `10` - * * `powerSave` after a minute of not being moved, Bangle.js will change the accelerometer poll interval down to 800ms (10x accelerometer samples). - * On movement it'll be raised to the default 80ms. If `Bangle.setPollInterval` is used this is disabled, and for it to work the poll interval - * must be either 80ms or 800ms. default = `true`. Setting `powerSave:false` will disable this automatic power saving, but will **not** change - * the poll interval from its current value. If you desire a specific interval (eg the default 80ms) you must set it manually with `Bangle.setPollInterval(80)` - * after setting `powerSave:false`. + * * `wakeOnBTN2` (Bangle.js 1) should the LCD turn on when BTN2 is pressed? + * default = `true` + * * `wakeOnBTN3` (Bangle.js 1) should the LCD turn on when BTN3 is pressed? + * default = `true` + * * `wakeOnFaceUp` should the LCD turn on when the watch is turned face up? + * default = `false` + * * `wakeOnTouch` should the LCD turn on when the touchscreen is pressed? default + * = `false` + * * `wakeOnTwist` should the LCD turn on when the watch is twisted? default = + * `true` + * * `twistThreshold` How much acceleration to register a twist of the watch strap? + * Can be negative for opposite direction. default = `800` + * * `twistMaxY` Maximum acceleration in Y to trigger a twist (low Y means watch is + * facing the right way up). default = `-800` + * * `twistTimeout` How little time (in ms) must a twist take from low->high + * acceleration? default = `1000` + * * `gestureStartThresh` how big a difference before we consider a gesture + * started? default = `sqr(800)` + * * `gestureEndThresh` how small a difference before we consider a gesture ended? + * default = `sqr(2000)` + * * `gestureInactiveCount` how many samples do we keep after a gesture has ended? + * default = `4` + * * `gestureMinLength` how many samples must a gesture have before we notify about + * it? default = `10` + * * `powerSave` after a minute of not being moved, Bangle.js will change the + * accelerometer poll interval down to 800ms (10x accelerometer samples). On + * movement it'll be raised to the default 80ms. If `Bangle.setPollInterval` is + * used this is disabled, and for it to work the poll interval must be either + * 80ms or 800ms. default = `true`. Setting `powerSave:false` will disable this + * automatic power saving, but will **not** change the poll interval from its + * current value. If you desire a specific interval (e.g. the default 80ms) you + * must set it manually with `Bangle.setPollInterval(80)` after setting + * `powerSave:false`. * * `lockTimeout` how many milliseconds before the screen locks * * `lcdPowerTimeout` how many milliseconds before the screen turns off - * * `backlightTimeout` how many milliseconds before the screen's backlight turns off - * * `hrmPollInterval` set the requested poll interval (in milliseconds) for the heart rate monitor. On Bangle.js 2 only 10,20,40,80,160,200 ms are supported, and polling rate may not be exact. The algorithm's filtering is tuned for 20-40ms poll intervals, so higher/lower intervals may effect the reliability of the BPM reading. - * * `seaLevelPressure` (Bangle.js 2) Normally 1013.25 millibars - this is used for calculating altitude with the pressure sensor + * * `backlightTimeout` how many milliseconds before the screen's backlight turns + * off + * * `hrmPollInterval` set the requested poll interval (in milliseconds) for the + * heart rate monitor. On Bangle.js 2 only 10,20,40,80,160,200 ms are supported, + * and polling rate may not be exact. The algorithm's filtering is tuned for + * 20-40ms poll intervals, so higher/lower intervals may effect the reliability + * of the BPM reading. + * * `seaLevelPressure` (Bangle.js 2) Normally 1013.25 millibars - this is used for + * calculating altitude with the pressure sensor * Where accelerations are used they are in internal units, where `8192 = 1g` * * @param {any} options * @url http://www.espruino.com/Reference#l_Bangle_setOptions */ - static setOptions(options: any): any; + static setOptions(options: { [key in keyof BangleOptions]?: BangleOptions[key] }): void; /** * Return the current state of options as set by `Bangle.setOptions` * @returns {any} The current state of all options * @url http://www.espruino.com/Reference#l_Bangle_getOptions */ - static getOptions(): any; + static getOptions(): BangleOptions; /** * Also see the `Bangle.lcdPower` event @@ -4636,13 +5202,13 @@ declare class Bangle { static isLCDOn(): boolean; /** - * This function can be used to lock or unlock Bangle.js - * (eg whether buttons and touchscreen work or not) + * This function can be used to lock or unlock Bangle.js (e.g. whether buttons and + * touchscreen work or not) * * @param {boolean} isLocked - `true` if the Bangle is locked (no user input allowed) * @url http://www.espruino.com/Reference#l_Bangle_setLocked */ - static setLocked(isLocked: boolean): any; + static setLocked(isLocked: boolean): void; /** * Also see the `Bangle.lock` event @@ -4664,7 +5230,7 @@ declare class Bangle { * @param {any} data * @url http://www.espruino.com/Reference#l_Bangle_lcdWr */ - static lcdWr(cmd: number, data: any): any; + static lcdWr(cmd: number, data: any): void; /** * Set the power to the Heart rate monitor @@ -4680,7 +5246,7 @@ declare class Bangle { * @returns {boolean} Is HRM on? * @url http://www.espruino.com/Reference#l_Bangle_setHRMPower */ - static setHRMPower(isOn: boolean, appID: any): boolean; + static setHRMPower(isOn: boolean, appID: string): boolean; /** * Is the Heart rate monitor powered? @@ -4704,7 +5270,7 @@ declare class Bangle { * @returns {boolean} Is the GPS on? * @url http://www.espruino.com/Reference#l_Bangle_setGPSPower */ - static setGPSPower(isOn: boolean, appID: any): boolean; + static setGPSPower(isOn: boolean, appID: string): boolean; /** * Is the GPS powered? @@ -4720,7 +5286,7 @@ declare class Bangle { * @returns {any} A GPS fix object with `{lat,lon,...}` * @url http://www.espruino.com/Reference#l_Bangle_getGPSFix */ - static getGPSFix(): any; + static getGPSFix(): GPSFix; /** * Set the power to the Compass @@ -4736,7 +5302,7 @@ declare class Bangle { * @returns {boolean} Is the Compass on? * @url http://www.espruino.com/Reference#l_Bangle_setCompassPower */ - static setCompassPower(isOn: boolean, appID: any): boolean; + static setCompassPower(isOn: boolean, appID: string): boolean; /** * Is the compass powered? @@ -4752,11 +5318,11 @@ declare class Bangle { * * @url http://www.espruino.com/Reference#l_Bangle_resetCompass */ - static resetCompass(): any; + static resetCompass(): void; /** - * Set the power to the barometer IC. Once enbled, `Bangle.pressure` events - * are fired each time a new barometer reading is available. + * Set the power to the barometer IC. Once enabled, `Bangle.pressure` events are + * fired each time a new barometer reading is available. * When on, the barometer draws roughly 50uA * * @param {boolean} isOn - True if the barometer IC should be on, false if not @@ -4764,7 +5330,7 @@ declare class Bangle { * @returns {boolean} Is the Barometer on? * @url http://www.espruino.com/Reference#l_Bangle_setBarometerPower */ - static setBarometerPower(isOn: boolean, appID: any): boolean; + static setBarometerPower(isOn: boolean, appID: string): boolean; /** * Is the Barometer powered? @@ -4787,41 +5353,46 @@ declare class Bangle { * @param {number} count - The value with which to reload the step counter * @url http://www.espruino.com/Reference#l_Bangle_setStepCount */ - static setStepCount(count: number): any; + static setStepCount(count: number): void; /** - * Get the most recent Magnetometer/Compass reading. Data is in the same format as the `Bangle.on('mag',` event. + * Get the most recent Magnetometer/Compass reading. Data is in the same format as + * the `Bangle.on('mag',` event. * Returns an `{x,y,z,dx,dy,dz,heading}` object * * `x/y/z` raw x,y,z magnetometer readings * * `dx/dy/dz` readings based on calibration since magnetometer turned on - * * `heading` in degrees based on calibrated readings (will be NaN if magnetometer hasn't been rotated around 360 degrees) - * To get this event you must turn the compass on - * with `Bangle.setCompassPower(1)`. + * * `heading` in degrees based on calibrated readings (will be NaN if magnetometer + * hasn't been rotated around 360 degrees) + * To get this event you must turn the compass on with `Bangle.setCompassPower(1)`. * @returns {any} An object containing magnetometer readings (as below) * @url http://www.espruino.com/Reference#l_Bangle_getCompass */ - static getCompass(): any; + static getCompass(): CompassData; /** - * Get the most recent accelerometer reading. Data is in the same format as the `Bangle.on('accel',` event. + * Get the most recent accelerometer reading. Data is in the same format as the + * `Bangle.on('accel',` event. * * `x` is X axis (left-right) in `g` * * `y` is Y axis (up-down) in `g` * * `z` is Z axis (in-out) in `g` - * * `diff` is difference between this and the last reading in `g` (calculated by comparing vectors, not magnitudes) + * * `diff` is difference between this and the last reading in `g` (calculated by + * comparing vectors, not magnitudes) * * `td` is the elapsed * * `mag` is the magnitude of the acceleration in `g` * @returns {any} An object containing accelerometer readings (as below) * @url http://www.espruino.com/Reference#l_Bangle_getAccel */ - static getAccel(): any; + static getAccel(): AccelData & { td: number }; /** * `range` is one of: - * * `undefined` or `'current'` - health data so far in the last 10 minutes is returned, + * * `undefined` or `'current'` - health data so far in the last 10 minutes is + * returned, * * `'last'` - health data during the last 10 minutes * * `'day'` - the health data so far for the day * `getHealthStatus` returns an object containing: - * * `movement` is the 32 bit sum of all `acc.diff` readings since power on (and rolls over). It is the difference in accelerometer values as `g*8192` + * * `movement` is the 32 bit sum of all `acc.diff` readings since power on (and + * rolls over). It is the difference in accelerometer values as `g*8192` * * `steps` is the number of steps during this period * * `bpm` the best BPM reading from HRM sensor during this period * * `bpmConfidence` best BPM confidence (0-100%) during this period @@ -4830,12 +5401,12 @@ declare class Bangle { * @returns {any} Returns an object containing various health info * @url http://www.espruino.com/Reference#l_Bangle_getHealthStatus */ - static getHealthStatus(range: any): any; + static getHealthStatus(range?: "current" | "last" | "day"): HealthStatus; /** * Feature flag - If true, this Bangle.js firmware reads `setting.json` and - * modifies beep & buzz behaviour accordingly (the bootloader - * doesn't need to do it). + * modifies beep & buzz behaviour accordingly (the bootloader doesn't need to do + * it). * @returns {boolean} * @url http://www.espruino.com/Reference#l_Bangle_F_BEEPSET */ @@ -4855,18 +5426,20 @@ declare class Bangle { * @param {number} data * @url http://www.espruino.com/Reference#l_Bangle_accelWr */ - static accelWr(reg: number, data: number): any; + static accelWr(reg: number, data: number): void; /** * Reads a register from the accelerometer - * **Note:** On Espruino 2v06 and before this function only returns a number (`cnt` is ignored). + * **Note:** On Espruino 2v06 and before this function only returns a number (`cnt` + * is ignored). * * @param {number} reg * @param {number} cnt - If specified, returns an array of the given length (max 128). If not (or 0) it returns a number * @returns {any} * @url http://www.espruino.com/Reference#l_Bangle_accelRd */ - static accelRd(reg: number, cnt: number): any; + static accelRd(reg: number, cnt?: 0): number; + static accelRd(reg: number, cnt: number): number[]; /** * Writes a register on the barometer IC @@ -4875,7 +5448,7 @@ declare class Bangle { * @param {number} data * @url http://www.espruino.com/Reference#l_Bangle_barometerWr */ - static barometerWr(reg: number, data: number): any; + static barometerWr(reg: number, data: number): void; /** * Reads a register from the barometer IC @@ -4885,7 +5458,8 @@ declare class Bangle { * @returns {any} * @url http://www.espruino.com/Reference#l_Bangle_barometerRd */ - static barometerRd(reg: number, cnt: number): any; + static barometerRd(reg: number, cnt?: 0): number; + static barometerRd(reg: number, cnt: number): number[]; /** * Writes a register on the Magnetometer/Compass @@ -4894,7 +5468,7 @@ declare class Bangle { * @param {number} data * @url http://www.espruino.com/Reference#l_Bangle_compassWr */ - static compassWr(reg: number, data: number): any; + static compassWr(reg: number, data: number): void; /** * Read a register on the Magnetometer/Compass @@ -4904,7 +5478,8 @@ declare class Bangle { * @returns {any} * @url http://www.espruino.com/Reference#l_Bangle_compassRd */ - static compassRd(reg: number, cnt: number): any; + static compassRd(reg: number, cnt?: 0): number; + static compassRd(reg: number, cnt: number): number[]; /** * Writes a register on the Heart rate monitor @@ -4913,7 +5488,7 @@ declare class Bangle { * @param {number} data * @url http://www.espruino.com/Reference#l_Bangle_hrmWr */ - static hrmWr(reg: number, data: number): any; + static hrmWr(reg: number, data: number): void; /** * Read a register on the Heart rate monitor @@ -4923,7 +5498,8 @@ declare class Bangle { * @returns {any} * @url http://www.espruino.com/Reference#l_Bangle_hrmRd */ - static hrmRd(reg: number, cnt: number): any; + static hrmRd(reg: number, cnt?: 0): number; + static hrmRd(reg: number, cnt: number): number[]; /** * Changes a pin state on the IO expander @@ -4932,14 +5508,14 @@ declare class Bangle { * @param {number} isOn * @url http://www.espruino.com/Reference#l_Bangle_ioWr */ - static ioWr(mask: number, isOn: number): any; + static ioWr(mask: number, isOn: number): void; /** - * Read temperature, pressure and altitude data. A promise is returned - * which will be resolved with `{temperature, pressure, altitude}`. - * If the Barometer has been turned on with `Bangle.setBarometerPower` then this will - * return almost immediately with the reading. If the Barometer is off, conversions take - * between 500-750ms. + * Read temperature, pressure and altitude data. A promise is returned which will + * be resolved with `{temperature, pressure, altitude}`. + * If the Barometer has been turned on with `Bangle.setBarometerPower` then this + * will return almost immediately with the reading. If the Barometer is off, + * conversions take between 500-750ms. * Altitude assumes a sea-level pressure of 1013.25 hPa * ``` * Bangle.getPressure().then(d=>{ @@ -4950,30 +5526,31 @@ declare class Bangle { * @returns {any} A promise that will be resolved with `{temperature, pressure, altitude}` * @url http://www.espruino.com/Reference#l_Bangle_getPressure */ - static getPressure(): any; + static getPressure(): PressureData; /** - * Perform a Spherical [Web Mercator projection](https://en.wikipedia.org/wiki/Web_Mercator_projection) - * of latitude and longitude into `x` and `y` coordinates, which are roughly - * equivalent to meters from `{lat:0,lon:0}`. - * This is the formula used for most online mapping and is a good way - * to compare GPS coordinates to work out the distance between them. + * Perform a Spherical [Web Mercator + * projection](https://en.wikipedia.org/wiki/Web_Mercator_projection) of latitude + * and longitude into `x` and `y` coordinates, which are roughly equivalent to + * meters from `{lat:0,lon:0}`. + * This is the formula used for most online mapping and is a good way to compare + * GPS coordinates to work out the distance between them. * * @param {any} latlong - `{lat:..., lon:...}` * @returns {any} {x:..., y:...} * @url http://www.espruino.com/Reference#l_Bangle_project */ - static project(latlong: any): any; + static project(latlong: { lat: number, lon: number }): { x: number, y: number }; /** * Use the piezo speaker to Beep for a certain time period and frequency * - * @param {number} time - Time in ms (default 200) - * @param {number} freq - Frequency in hz (default 4000) + * @param {number} [time] - [optional] Time in ms (default 200) + * @param {number} [freq] - [optional] Frequency in hz (default 4000) * @returns {any} A promise, completed when beep is finished * @url http://www.espruino.com/Reference#l_Bangle_beep */ - static beep(time: number, freq: number): Promise; + static beep(time?: number, freq?: number): Promise; /** * Use the vibration motor to buzz for a certain time period @@ -4983,20 +5560,20 @@ declare class Bangle { * @returns {any} A promise, completed when vibration is finished * @url http://www.espruino.com/Reference#l_Bangle_buzz */ - static buzz(time?: number, strength?: number): Promise; + static buzz(time?: number, strength?: number): Promise; /** * Turn Bangle.js off. It can only be woken by pressing BTN1. * @url http://www.espruino.com/Reference#l_Bangle_off */ - static off(): any; + static off(): void; /** - * Turn Bangle.js (mostly) off, but keep the CPU in sleep - * mode until BTN1 is pressed to preserve the RTC (current time). + * Turn Bangle.js (mostly) off, but keep the CPU in sleep mode until BTN1 is + * pressed to preserve the RTC (current time). * @url http://www.espruino.com/Reference#l_Bangle_softOff */ - static softOff(): any; + static softOff(): void; /** * * On platforms with an LCD of >=8bpp this is 222 x 104 x 2 bits @@ -5004,59 +5581,67 @@ declare class Bangle { * @returns {any} An image to be used with `g.drawImage` (as a String) * @url http://www.espruino.com/Reference#l_Bangle_getLogo */ - static getLogo(): any; + static getLogo(): string; /** - * Load all widgets from flash Storage. Call this once at the beginning - * of your application if you want any on-screen widgets to be loaded. - * They will be loaded into a global `WIDGETS` array, and - * can be rendered with `Bangle.drawWidgets`. + * Load all widgets from flash Storage. Call this once at the beginning of your + * application if you want any on-screen widgets to be loaded. + * They will be loaded into a global `WIDGETS` array, and can be rendered with + * `Bangle.drawWidgets`. * @url http://www.espruino.com/Reference#l_Bangle_loadWidgets */ - static loadWidgets(): any; + static loadWidgets(): void; /** * Draw any onscreen widgets that were loaded with `Bangle.loadWidgets()`. - * Widgets should redraw themselves when something changes - you'll only - * need to call drawWidgets if you decide to clear the entire screen - * with `g.clear()`. + * Widgets should redraw themselves when something changes - you'll only need to + * call drawWidgets if you decide to clear the entire screen with `g.clear()`. * @url http://www.espruino.com/Reference#l_Bangle_drawWidgets */ - static drawWidgets(): any; + static drawWidgets(): void; /** * @url http://www.espruino.com/Reference#l_Bangle_drawWidgets */ - static drawWidgets(): any; + static drawWidgets(): void; /** - * Load the Bangle.js app launcher, which will allow the user - * to select an application to launch. + * Load the Bangle.js app launcher, which will allow the user to select an + * application to launch. * @url http://www.espruino.com/Reference#l_Bangle_showLauncher */ - static showLauncher(): any; + static showLauncher(): void; /** - * This puts Bangle.js into the specified UI input mode, and calls the callback provided when there is user input. + * This puts Bangle.js into the specified UI input mode, and calls the callback + * provided when there is user input. * Currently supported interface types are: - * * 'updown' - UI input with upwards motion `cb(-1)`, downwards motion `cb(1)`, and select `cb()` + * * 'updown' - UI input with upwards motion `cb(-1)`, downwards motion `cb(1)`, + * and select `cb()` * * Bangle.js 1 uses BTN1/3 for up/down and BTN2 for select * * Bangle.js 2 uses touchscreen swipe up/down and tap - * * 'leftright' - UI input with left motion `cb(-1)`, right motion `cb(1)`, and select `cb()` + * * 'leftright' - UI input with left motion `cb(-1)`, right motion `cb(1)`, and + * select `cb()` * * Bangle.js 1 uses BTN1/3 for left/right and BTN2 for select * * Bangle.js 2 uses touchscreen swipe left/right and tap/BTN1 for select - * * 'clock' - called for clocks. Sets `Bangle.CLOCK=1` and allows a button to start the launcher + * * 'clock' - called for clocks. Sets `Bangle.CLOCK=1` and allows a button to + * start the launcher * * Bangle.js 1 BTN2 starts the launcher * * Bangle.js 2 BTN1 starts the launcher - * * 'clockupdown' - called for clocks. Sets `Bangle.CLOCK=1`, allows a button to start the launcher, but also provides up/down functionality + * * 'clockupdown' - called for clocks. Sets `Bangle.CLOCK=1`, allows a button to + * start the launcher, but also provides up/down functionality * * Bangle.js 1 BTN2 starts the launcher, BTN1/BTN3 call `cb(-1)` and `cb(1)` - * * Bangle.js 2 BTN1 starts the launcher, touchscreen tap in top/bottom right hand side calls `cb(-1)` and `cb(1)` - * * `{mode:"custom", ...}` allows you to specify custom handlers for different interations. See below. + * * Bangle.js 2 BTN1 starts the launcher, touchscreen tap in top/bottom right + * hand side calls `cb(-1)` and `cb(1)` + * * `{mode:"custom", ...}` allows you to specify custom handlers for different + * interactions. See below. * * `undefined` removes all user interaction code - * While you could use setWatch/etc manually, the benefit here is that you don't end up with multiple `setWatch` instances, and - * the actual input method (touch, or buttons) is implemented dependent on the watch (Bangle.js 1 or 2) - * **Note:** You can override this function in boot code to change the interaction mode with the watch. For instance - * you could make all clocks start the launcher with a swipe by using: + * While you could use setWatch/etc manually, the benefit here is that you don't + * end up with multiple `setWatch` instances, and the actual input method (touch, + * or buttons) is implemented dependent on the watch (Bangle.js 1 or 2) + * **Note:** You can override this function in boot code to change the interaction + * mode with the watch. For instance you could make all clocks start the launcher + * with a swipe by using: * ``` * (function() { * var sui = Bangle.setUI; @@ -5069,7 +5654,8 @@ declare class Bangle { * }; * })(); * ``` - * The first argument can also be an object, in which case more options can be specified: + * The first argument can also be an object, in which case more options can be + * specified: * ``` * Bangle.setUI({ * mode : "custom", @@ -5086,48 +5672,50 @@ declare class Bangle { * @param {any} callback - A function with one argument which is the direction * @url http://www.espruino.com/Reference#l_Bangle_setUI */ - static setUI(type: any, callback: any): any; + static setUI(type?: "updown" | "leftright" | "clock" | "clockupdown" | { mode: "custom"; back?: () => void; touch?: TouchCallback; swipe?: SwipeCallback; drag?: DragCallback; btn?: (n: number) => void, clock?: boolean }, callback?: (direction?: -1 | 1) => void): void; /** * @url http://www.espruino.com/Reference#l_Bangle_setUI */ - static setUI(): any; + static setUI(): void; /** - * Erase all storage and reload it with the default - * contents. - * This is only available on Bangle.js 2.0. On Bangle.js 1.0 - * you need to use `Install Default Apps` under the `More...` tab - * of http://banglejs.com/apps + * Erase all storage and reload it with the default contents. + * This is only available on Bangle.js 2.0. On Bangle.js 1.0 you need to use + * `Install Default Apps` under the `More...` tab of http://banglejs.com/apps * @url http://www.espruino.com/Reference#l_Bangle_factoryReset */ - static factoryReset(): any; + static factoryReset(): void; /** - * Returns the rectangle on the screen that is currently - * reserved for the app. + * Returns the rectangle on the screen that is currently reserved for the app. * @returns {any} An object of the form `{x,y,w,h,x2,y2}` * @url http://www.espruino.com/Reference#l_Bangle_appRect */ - static appRect: any; + static appRect: { x: number, y: number, w: number, h: number, x2: number, y2: number }; + + static CLOCK: boolean; + static strokes: undefined | { [key: string]: Unistroke }; } interface DateConstructor { /** - * Get the number of milliseconds elapsed since 1970 (or on embedded platforms, since startup) + * Get the number of milliseconds elapsed since 1970 (or on embedded platforms, + * since startup) * @returns {number} * @url http://www.espruino.com/Reference#l_Date_now */ now(): number; /** - * Parse a date string and return milliseconds since 1970. Data can be either '2011-10-20T14:48:00', '2011-10-20' or 'Mon, 25 Dec 1995 13:30:00 +0430' + * Parse a date string and return milliseconds since 1970. Data can be either + * '2011-10-20T14:48:00', '2011-10-20' or 'Mon, 25 Dec 1995 13:30:00 +0430' * * @param {any} str - A String * @returns {number} The number of milliseconds since 1970 * @url http://www.espruino.com/Reference#l_Date_parse */ - parse(str: any): number; + parse(str: string): number; /** * Creates a date object @@ -5137,7 +5725,9 @@ interface DateConstructor { * @returns {any} A Date object * @url http://www.espruino.com/Reference#l_Date_Date */ - new(...args: any[]): Date; + new(): Date; + new(value: number | string): Date; + new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date; } interface Date { @@ -5153,7 +5743,7 @@ interface Date { * @returns {number} true if daylight savings time is in effect * @url http://www.espruino.com/Reference#l_Date_getIsDST */ - getIsDST(): number; + getIsDST(): boolean /** * Return the number of milliseconds since 1970 @@ -5244,7 +5834,7 @@ interface Date { * @returns {number} The number of milliseconds since 1970 * @url http://www.espruino.com/Reference#l_Date_setHours */ - setHours(hoursValue: number, minutesValue: any, secondsValue: any, millisecondsValue: any): number; + setHours(hoursValue: number, minutesValue?: number, secondsValue?: number, millisecondsValue?: number): number; /** * 0..59 @@ -5255,7 +5845,7 @@ interface Date { * @returns {number} The number of milliseconds since 1970 * @url http://www.espruino.com/Reference#l_Date_setMinutes */ - setMinutes(minutesValue: number, secondsValue: any, millisecondsValue: any): number; + setMinutes(minutesValue: number, secondsValue?: number, millisecondsValue?: number): number; /** * 0..59 @@ -5265,7 +5855,7 @@ interface Date { * @returns {number} The number of milliseconds since 1970 * @url http://www.espruino.com/Reference#l_Date_setSeconds */ - setSeconds(secondsValue: number, millisecondsValue: any): number; + setSeconds(secondsValue: number, millisecondsValue?: number): number; /** * @@ -5292,7 +5882,7 @@ interface Date { * @returns {number} The number of milliseconds since 1970 * @url http://www.espruino.com/Reference#l_Date_setMonth */ - setMonth(yearValue: number, dayValue: any): number; + setMonth(yearValue: number, dayValue?: number): number; /** * @@ -5302,15 +5892,16 @@ interface Date { * @returns {number} The number of milliseconds since 1970 * @url http://www.espruino.com/Reference#l_Date_setFullYear */ - setFullYear(yearValue: number, monthValue: any, dayValue: any): number; + setFullYear(yearValue: number, monthValue?: number, dayValue?: number): number; /** * Converts to a String, eg: `Fri Jun 20 2014 14:52:20 GMT+0000` - * **Note:** This uses whatever timezone was set with `E.setTimeZone()` or `E.setDST()` + * **Note:** This uses whatever timezone was set with `E.setTimeZone()` or + * `E.setDST()` * @returns {any} A String * @url http://www.espruino.com/Reference#l_Date_toString */ - toString(): any; + toString(): string; /** * Converts to a String, eg: `Fri, 20 Jun 2014 14:52:20 GMT` @@ -5318,7 +5909,7 @@ interface Date { * @returns {any} A String * @url http://www.espruino.com/Reference#l_Date_toUTCString */ - toUTCString(): any; + toUTCString(): string; /** * Converts to a ISO 8601 String, eg: `2014-06-20T14:52:20.123Z` @@ -5326,36 +5917,38 @@ interface Date { * @returns {any} A String * @url http://www.espruino.com/Reference#l_Date_toISOString */ - toISOString(): any; + toISOString(): string; /** * Calls `Date.toISOString` to output this date to JSON * @returns {any} A String * @url http://www.espruino.com/Reference#l_Date_toJSON */ - toJSON(): any; + toJSON(): string; /** - * Converts to a ISO 8601 String (with timezone information), eg: `2014-06-20T14:52:20.123-0500` + * Converts to a ISO 8601 String (with timezone information), eg: + * `2014-06-20T14:52:20.123-0500` * @returns {any} A String * @url http://www.espruino.com/Reference#l_Date_toLocalISOString */ - toLocalISOString(): any; + toLocalISOString(): string; } /** * The built-in class for handling Dates. - * **Note:** By default the time zone is GMT+0, however you can change the - * timezone using the `E.setTimeZone(...)` function. + * **Note:** By default the time zone is GMT+0, however you can change the timezone + * using the `E.setTimeZone(...)` function. * For example `E.setTimeZone(1)` will be GMT+0100 - * *However* if you have daylight savings time set with `E.setDST(...)` then the timezone set - * by `E.setTimeZone(...)` will be _ignored_. + * *However* if you have daylight savings time set with `E.setDST(...)` then the + * timezone set by `E.setTimeZone(...)` will be _ignored_. * @url http://www.espruino.com/Reference#Date */ declare const Date: DateConstructor /** - * This class provides a software-defined OneWire master. It is designed to be similar to Arduino's OneWire library. + * This class provides a software-defined OneWire master. It is designed to be + * similar to Arduino's OneWire library. * @url http://www.espruino.com/Reference#OneWire */ declare class OneWire { @@ -5367,7 +5960,9 @@ declare class OneWire { * @returns {any} A OneWire object * @url http://www.espruino.com/Reference#l_OneWire_OneWire */ - static new(pin: Pin): any;/** + static new(pin: Pin): any; + + /** * Perform a reset cycle * @returns {boolean} True is a device was present (it held the bus low) * @url http://www.espruino.com/Reference#l_OneWire_reset @@ -5380,13 +5975,13 @@ declare class OneWire { * @param {any} rom - The device to select (get this using `OneWire.search()`) * @url http://www.espruino.com/Reference#l_OneWire_select */ - select(rom: any): any; + select(rom: any): void; /** * Skip a ROM * @url http://www.espruino.com/Reference#l_OneWire_skip */ - skip(): any; + skip(): void; /** * Write one or more bytes @@ -5395,7 +5990,7 @@ declare class OneWire { * @param {boolean} power - Whether to leave power on after write (default is false) * @url http://www.espruino.com/Reference#l_OneWire_write */ - write(data: any, power: boolean): any; + write(data: any, power: boolean): void; /** * Read a byte @@ -5484,7 +6079,7 @@ interface ArrayBufferConstructor { * @returns {any} An ArrayBuffer object * @url http://www.espruino.com/Reference#l_ArrayBuffer_ArrayBuffer */ - new(byteLength: number): any; + new(byteLength: number): ArrayBuffer; } interface ArrayBuffer { @@ -5498,8 +6093,8 @@ interface ArrayBuffer { /** * This is the built-in JavaScript class for array buffers. - * If you want to access arrays of differing types of data - * you may also find `DataView` useful. + * If you want to access arrays of differing types of data you may also find + * `DataView` useful. * @url http://www.espruino.com/Reference#ArrayBuffer */ declare const ArrayBuffer: ArrayBufferConstructor @@ -5516,31 +6111,34 @@ declare const ArrayBuffer: ArrayBufferConstructor * * [Int32Array](/Reference#Int32Array) * * [Float32Array](/Reference#Float32Array) * * [Float64Array](/Reference#Float64Array) - * If you want to access arrays of differing types of data - * you may also find `DataView` useful. + * If you want to access arrays of differing types of data you may also find + * `DataView` useful. * @url http://www.espruino.com/Reference#ArrayBufferView */ -declare class ArrayBufferView { +declare class ArrayBufferView { + + /** * The buffer this view references * @returns {any} An ArrayBuffer object * @url http://www.espruino.com/Reference#l_ArrayBufferView_buffer */ - buffer: ArrayBuffer; + readonly buffer: T; /** * The length, in bytes, of the `ArrayBufferView` * @returns {number} The Length * @url http://www.espruino.com/Reference#l_ArrayBufferView_byteLength */ - byteLength: number; + readonly byteLength: number; /** - * The offset, in bytes, to the first byte of the view within the backing `ArrayBuffer` + * The offset, in bytes, to the first byte of the view within the backing + * `ArrayBuffer` * @returns {number} The byte Offset * @url http://www.espruino.com/Reference#l_ArrayBufferView_byteOffset */ - byteOffset: number; + readonly byteOffset: number; /** * Copy the contents of `array` into this one, mapping `this[x+offset]=array[x];` @@ -5549,28 +6147,31 @@ declare class ArrayBufferView { * @param {number} offset - The offset in this array at which to write the values (optional) * @url http://www.espruino.com/Reference#l_ArrayBufferView_set */ - set(arr: any, offset: number): any; + set(arr: ArrayLike, offset: number): void /** - * Return an array which is made from the following: ```A.map(function) = [function(A[0]), function(A[1]), ...]``` - * **Note:** This returns an `ArrayBuffer` of the same type it was called on. To get an `Array`, use `Array.map`, eg. `[].map.call(myArray, x=>x+1)` + * Return an array which is made from the following: ```A.map(function) = + * [function(A[0]), function(A[1]), ...]``` + * **Note:** This returns an `ArrayBuffer` of the same type it was called on. To + * get an `Array`, use `Array.map`, e.g. `[].map.call(myArray, x=>x+1)` * * @param {any} function - Function used to map one item to another * @param {any} thisArg - if specified, the function is called with 'this' set to thisArg (optional) * @returns {any} An array containing the results * @url http://www.espruino.com/Reference#l_ArrayBufferView_map */ - map(func: any, thisArg: any): ArrayBufferView; + map(callbackfn: (value: number, index: number, array: T) => number, thisArg?: any): T; /** - * Returns a smaller part of this array which references the same data (it doesn't copy it). + * Returns a smaller part of this array which references the same data (it doesn't + * copy it). * * @param {number} begin - Element to begin at, inclusive. If negative, this is from the end of the array. The entire array is included if this isn't specified * @param {any} end - Element to end at, exclusive. If negative, it is relative to the end of the array. If not specified the whole array is included * @returns {any} An `ArrayBufferView` of the same type as this one, referencing the same data * @url http://www.espruino.com/Reference#l_ArrayBufferView_subarray */ - subarray(begin: number, end: any): ArrayBufferView; + subarray(begin?: number, end?: number): T; /** * Return the index of the value in the array, or `-1` @@ -5580,7 +6181,7 @@ declare class ArrayBufferView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_ArrayBufferView_indexOf */ - indexOf(value: any, startIndex: number): any; + indexOf(value: number, startIndex?: number): number; /** * Return `true` if the array includes the value, `false` otherwise @@ -5590,16 +6191,17 @@ declare class ArrayBufferView { * @returns {boolean} `true` if the array includes the value, `false` otherwise * @url http://www.espruino.com/Reference#l_ArrayBufferView_includes */ - includes(value: any, startIndex: number): boolean; + includes(value: number, startIndex?: number): boolean; /** - * Join all elements of this array together into one string, using 'separator' between them. eg. ```[1,2,3].join(' ')=='1 2 3'``` + * Join all elements of this array together into one string, using 'separator' + * between them. e.g. ```[1,2,3].join(' ')=='1 2 3'``` * * @param {any} separator - The separator * @returns {any} A String representing the Joined array * @url http://www.espruino.com/Reference#l_ArrayBufferView_join */ - join(separator: any): any; + join(separator?: string): string; /** * Do an in-place quicksort of the array @@ -5608,7 +6210,7 @@ declare class ArrayBufferView { * @returns {any} This array object * @url http://www.espruino.com/Reference#l_ArrayBufferView_sort */ - sort(variable: any): ArrayBufferView; + sort(compareFn?: (a: number, b: number) => number): this; /** * Executes a provided function once per array element. @@ -5617,17 +6219,19 @@ declare class ArrayBufferView { * @param {any} thisArg - if specified, the function is called with 'this' set to thisArg (optional) * @url http://www.espruino.com/Reference#l_ArrayBufferView_forEach */ - forEach(func: any, thisArg: any): any; + forEach(callbackfn: (value: number, index: number, array: T) => void, thisArg?: any): void; /** - * Execute `previousValue=initialValue` and then `previousValue = callback(previousValue, currentValue, index, array)` for each element in the array, and finally return previousValue. + * Execute `previousValue=initialValue` and then `previousValue = + * callback(previousValue, currentValue, index, array)` for each element in the + * array, and finally return previousValue. * * @param {any} callback - Function used to reduce the array * @param {any} initialValue - if specified, the initial value to pass to the function * @returns {any} The value returned by the last function called * @url http://www.espruino.com/Reference#l_ArrayBufferView_reduce */ - reduce(callback: any, initialValue: any): any; + reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: T) => number, initialValue?: number): number; /** * Fill this array with the given value, for every index `>= start` and `< end` @@ -5638,42 +6242,45 @@ declare class ArrayBufferView { * @returns {any} This array * @url http://www.espruino.com/Reference#l_ArrayBufferView_fill */ - fill(value: any, start: number, end: any): ArrayBufferView; + fill(value: number, start?: number, end?: number): T; /** - * Return an array which contains only those elements for which the callback function returns 'true' + * Return an array which contains only those elements for which the callback + * function returns 'true' * * @param {any} function - Function to be executed * @param {any} thisArg - if specified, the function is called with 'this' set to thisArg (optional) * @returns {any} An array containing the results * @url http://www.espruino.com/Reference#l_ArrayBufferView_filter */ - filter(func: any, thisArg: any): any; + filter(predicate: (value: number, index: number, array: T) => any, thisArg?: any): T; /** - * Return the array element where `function` returns `true`, or `undefined` if it doesn't returns `true` for any element. + * Return the array element where `function` returns `true`, or `undefined` if it + * doesn't returns `true` for any element. * * @param {any} function - Function to be executed * @returns {any} The array element where `function` returns `true`, or `undefined` * @url http://www.espruino.com/Reference#l_ArrayBufferView_find */ - find(func: any): any; + find(predicate: (value: number, index: number, obj: T) => boolean, thisArg?: any): number | undefined; /** - * Return the array element's index where `function` returns `true`, or `-1` if it doesn't returns `true` for any element. + * Return the array element's index where `function` returns `true`, or `-1` if it + * doesn't returns `true` for any element. * * @param {any} function - Function to be executed * @returns {any} The array element's index where `function` returns `true`, or `-1` * @url http://www.espruino.com/Reference#l_ArrayBufferView_findIndex */ - findIndex(func: any): any; + findIndex(predicate: (value: number, index: number, obj: T) => boolean, thisArg?: any): number; /** * Reverse the contents of this `ArrayBufferView` in-place * @returns {any} This array * @url http://www.espruino.com/Reference#l_ArrayBufferView_reverse */ - reverse(): ArrayBufferView; + reverse(): T /** * Return a copy of a portion of this array (in a new array). @@ -5684,12 +6291,17 @@ declare class ArrayBufferView { * @returns {any} A new array * @url http://www.espruino.com/Reference#l_ArrayBufferView_slice */ - slice(start: number, end: any): any[]; + slice(start?: number, end?: number): number[]; + + [index: number]: number } interface Uint8ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5698,25 +6310,23 @@ interface Uint8ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Uint8Array_Uint8Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Uint8Array; + new(array: ArrayLike): Uint8Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint8Array; } -interface Uint8Array { +type Uint8Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 8 bit unsigned integers. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Uint8Array - */ declare const Uint8Array: Uint8ArrayConstructor interface Uint8ClampedArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. - * Clamped arrays clamp their values to the allowed range, rather than 'wrapping'. e.g. after `a[0]=12345;`, `a[0]==255`. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. + * Clamped arrays clamp their values to the allowed range, rather than 'wrapping'. + * e.g. after `a[0]=12345;`, `a[0]==255`. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5725,24 +6335,21 @@ interface Uint8ClampedArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Uint8ClampedArray_Uint8ClampedArray */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Uint8ClampedArray; + new(array: ArrayLike): Uint8ClampedArray; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint8ClampedArray; } -interface Uint8ClampedArray { +type Uint8ClampedArray = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 8 bit unsigned integers that are automatically clamped to the range 0 to 255. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Uint8ClampedArray - */ declare const Uint8ClampedArray: Uint8ClampedArrayConstructor interface Int8ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5751,24 +6358,21 @@ interface Int8ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Int8Array_Int8Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Int8Array; + new(array: ArrayLike): Int8Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Int8Array; } -interface Int8Array { +type Int8Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 8 bit signed integers. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Int8Array - */ declare const Int8Array: Int8ArrayConstructor interface Uint16ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5777,24 +6381,21 @@ interface Uint16ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Uint16Array_Uint16Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Uint16Array; + new(array: ArrayLike): Uint16Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint16Array; } -interface Uint16Array { +type Uint16Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 16 bit unsigned integers. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Uint16Array - */ declare const Uint16Array: Uint16ArrayConstructor interface Int16ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5803,30 +6404,30 @@ interface Int16ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Int16Array_Int16Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Int16Array; + new(array: ArrayLike): Int16Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Int16Array; } -interface Int16Array { +type Int16Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 16 bit signed integers. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Int16Array - */ declare const Int16Array: Int16ArrayConstructor /** - * This is the built-in JavaScript class for a typed array of 24 bit unsigned integers. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) + * This is the built-in JavaScript class for a typed array of 24 bit unsigned + * integers. + * Instantiate this in order to efficiently store arrays of data (Espruino's normal + * arrays store data in a map, which is inefficient for non-sparse arrays). + * Arrays of this type include all the methods from + * [ArrayBufferView](/Reference#ArrayBufferView) * @url http://www.espruino.com/Reference#Uint24Array */ declare class Uint24Array { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5835,12 +6436,19 @@ declare class Uint24Array { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Uint24Array_Uint24Array */ - static new(arr: any, byteOffset: number, length: number): ArrayBufferView; + static new(length: number): Uint24Array; + static new(array: ArrayLike): Uint24Array; + static new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint24Array; + + } interface Uint32ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5849,24 +6457,21 @@ interface Uint32ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Uint32Array_Uint32Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Uint32Array; + new(array: ArrayLike): Uint32Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint32Array; } -interface Uint32Array { +type Uint32Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 32 bit unsigned integers. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Uint32Array - */ declare const Uint32Array: Uint32ArrayConstructor interface Int32ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5875,24 +6480,21 @@ interface Int32ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Int32Array_Int32Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Int32Array; + new(array: ArrayLike): Int32Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Int32Array; } -interface Int32Array { +type Int32Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 32 bit signed integers. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Int32Array - */ declare const Int32Array: Int32ArrayConstructor interface Float32ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5901,24 +6503,21 @@ interface Float32ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Float32Array_Float32Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Float32Array; + new(array: ArrayLike): Float32Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Float32Array; } -interface Float32Array { +type Float32Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 32 bit floating point values. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Float32Array - */ declare const Float32Array: Float32ArrayConstructor interface Float64ArrayConstructor { /** - * Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array. If an `ArrayBufferView` (eg. `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied rather than referenced. + * Create a typed array based on the given input. Either an existing Array Buffer, + * an Integer as a Length, or a simple array. If an `ArrayBufferView` (e.g. + * `Uint8Array` rather than `ArrayBuffer`) is given, it will be completely copied + * rather than referenced. * @constructor * * @param {any} arr - The array or typed array to base this off, or an integer which is the array length @@ -5927,45 +6526,37 @@ interface Float64ArrayConstructor { * @returns {any} A typed array * @url http://www.espruino.com/Reference#l_Float64Array_Float64Array */ - new(arr: any, byteOffset: number, length: number): ArrayBufferView; + new(length: number): Float64Array; + new(array: ArrayLike): Float64Array; + new(buffer: ArrayBuffer, byteOffset?: number, length?: number): Float64Array; } -interface Float64Array { +type Float64Array = ArrayBufferView; -} - -/** - * This is the built-in JavaScript class for a typed array of 64 bit floating point values. - * Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). - * Arrays of this type include all the methods from [ArrayBufferView](/Reference#ArrayBufferView) - * @url http://www.espruino.com/Reference#Float64Array - */ declare const Float64Array: Float64ArrayConstructor interface PromiseConstructor { /** - * Return a new promise that is resolved when all promises in the supplied - * array are resolved. + * Return a new promise that is resolved when all promises in the supplied array + * are resolved. * * @param {any} promises - An array of promises * @returns {any} A new Promise * @url http://www.espruino.com/Reference#l_Promise_all */ - all(promises: any): any; + all(promises: Promise[]): Promise; /** - * Return a new promise that is already resolved (at idle it'll - * call `.then`) + * Return a new promise that is already resolved (at idle it'll call `.then`) * * @param {any} promises - Data to pass to the `.then` handler * @returns {any} A new Promise * @url http://www.espruino.com/Reference#l_Promise_resolve */ - resolve(promises: any): any; + resolve(promises: T): Promise; /** - * Return a new promise that is already rejected (at idle it'll - * call `.catch`) + * Return a new promise that is already rejected (at idle it'll call `.catch`) * * @param {any} promises - Data to pass to the `.catch` handler * @returns {any} A new Promise @@ -5974,26 +6565,26 @@ interface PromiseConstructor { reject(promises: any): any; /** - * Create a new Promise. The executor function is executed immediately (before the constructor even returns) - * and + * Create a new Promise. The executor function is executed immediately (before the + * constructor even returns) and * @constructor * * @param {any} executor - A function of the form `function (resolve, reject)` * @returns {any} A Promise * @url http://www.espruino.com/Reference#l_Promise_Promise */ - new(executor: any): any; + new(executor: (resolve: (value: T) => void, reject: (reason?: any) => void) => void): Promise; } -interface Promise { +interface Promise { /** * * @param {any} onFulfilled - A callback that is called when this promise is resolved - * @param {any} onRejected - A callback that is called when this promise is rejected (or nothing) + * @param {any} [onRejected] - [optional] A callback that is called when this promise is rejected (or nothing) * @returns {any} The original Promise * @url http://www.espruino.com/Reference#l_Promise_then */ - then(onFulfilled: any, onRejected: any): any; + then(onfulfilled?: ((value: T) => TResult1 | Promise) | undefined | null, onrejected?: ((reason: any) => TResult2 | Promise) | undefined | null): Promise; /** * @@ -6011,7 +6602,8 @@ interface Promise { declare const Promise: PromiseConstructor /** - * This class allows use of the built-in SPI ports. Currently it is SPI master only. + * This class allows use of the built-in SPI ports. Currently it is SPI master + * only. * @url http://www.espruino.com/Reference#SPI */ declare class SPI { @@ -6026,13 +6618,16 @@ declare class SPI { static find(pin: Pin): any; /** - * Create a software SPI port. This has limited functionality (no baud rate), but it can work on any pins. + * Create a software SPI port. This has limited functionality (no baud rate), but + * it can work on any pins. * Use `SPI.setup` to configure this port. * @constructor * @returns {any} A SPI object * @url http://www.espruino.com/Reference#l_SPI_SPI */ - static new(): any;/** + static new(): any; + + /** * Set up this SPI port as an SPI Master. * Options can contain the following (defaults are shown where relevant): * ``` @@ -6046,20 +6641,33 @@ declare class SPI { * bits:8 // only available for software SPI * } * ``` - * If `sck`,`miso` and `mosi` are left out, they will automatically be chosen. However if one or more is specified then the unspecified pins will not be set up. - * You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `SPI` marker. Some boards such as those based on `nRF52` chips can have SPI on any pins, so don't have specific markings. - * The SPI `mode` is between 0 and 3 - see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase - * On STM32F1-based parts, you cannot mix AF and non-AF pins (SPI pins are usually grouped on the chip - and you can't mix pins from two groups). Espruino will not warn you about this. + * If `sck`,`miso` and `mosi` are left out, they will automatically be chosen. + * However if one or more is specified then the unspecified pins will not be set + * up. + * You can find out which pins to use by looking at [your board's reference + * page](#boards) and searching for pins with the `SPI` marker. Some boards such as + * those based on `nRF52` chips can have SPI on any pins, so don't have specific + * markings. + * The SPI `mode` is between 0 and 3 - see + * http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase + * On STM32F1-based parts, you cannot mix AF and non-AF pins (SPI pins are usually + * grouped on the chip - and you can't mix pins from two groups). Espruino will not + * warn you about this. * * @param {any} options - An Object containing extra information on initialising the SPI port * @url http://www.espruino.com/Reference#l_SPI_setup */ - setup(options: any): any; + setup(options: any): void; /** - * Send data down SPI, and return the result. Sending an integer will return an integer, a String will return a String, and anything else will return a Uint8Array. - * Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds. - * For maximum speeds, please pass either Strings or Typed Arrays as arguments. Note that you can even pass arrays of arrays, like `[1,[2,3,4],5]` + * Send data down SPI, and return the result. Sending an integer will return an + * integer, a String will return a String, and anything else will return a + * Uint8Array. + * Sending multiple bytes in one call to send is preferable as they can then be + * transmitted end to end. Using multiple calls to send() will result in + * significantly slower transmission speeds. + * For maximum speeds, please pass either Strings or Typed Arrays as arguments. + * Note that you can even pass arrays of arrays, like `[1,[2,3,4],5]` * * @param {any} data - The data to send - either an Integer, Array, String, or Object of the form `{data: ..., count:#}` * @param {Pin} nss_pin - An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised. @@ -6069,7 +6677,8 @@ declare class SPI { send(data: any, nss_pin: Pin): any; /** - * Write a character or array of characters to SPI - without reading the result back. + * Write a character or array of characters to SPI - without reading the result + * back. * For maximum speeds, please pass either Strings or Typed Arrays as arguments. * * @param {any} data @@ -6077,11 +6686,14 @@ declare class SPI { * If the last argument is a pin, it is taken to be the NSS pin * @url http://www.espruino.com/Reference#l_SPI_write */ - write(...data: any[]): any; + write(...data: any[]): void; /** - * Send data down SPI, using 4 bits for each 'real' bit (MSB first). This can be useful for faking one-wire style protocols - * Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds. + * Send data down SPI, using 4 bits for each 'real' bit (MSB first). This can be + * useful for faking one-wire style protocols + * Sending multiple bytes in one call to send is preferable as they can then be + * transmitted end to end. Using multiple calls to send() will result in + * significantly slower transmission speeds. * * @param {any} data - The data to send - either an integer, array, or string * @param {number} bit0 - The 4 bits to send for a 0 (MSB first) @@ -6089,11 +6701,14 @@ declare class SPI { * @param {Pin} nss_pin - An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised. * @url http://www.espruino.com/Reference#l_SPI_send4bit */ - send4bit(data: any, bit0: number, bit1: number, nss_pin: Pin): any; + send4bit(data: any, bit0: number, bit1: number, nss_pin: Pin): void; /** - * Send data down SPI, using 8 bits for each 'real' bit (MSB first). This can be useful for faking one-wire style protocols - * Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds. + * Send data down SPI, using 8 bits for each 'real' bit (MSB first). This can be + * useful for faking one-wire style protocols + * Sending multiple bytes in one call to send is preferable as they can then be + * transmitted end to end. Using multiple calls to send() will result in + * significantly slower transmission speeds. * * @param {any} data - The data to send - either an integer, array, or string * @param {number} bit0 - The 8 bits to send for a 0 (MSB first) @@ -6101,12 +6716,14 @@ declare class SPI { * @param {Pin} nss_pin - An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised * @url http://www.espruino.com/Reference#l_SPI_send8bit */ - send8bit(data: any, bit0: number, bit1: number, nss_pin: Pin): any; + send8bit(data: any, bit0: number, bit1: number, nss_pin: Pin): void; } /** - * This class allows use of the built-in I2C ports. Currently it allows I2C Master mode only. - * All addresses are in 7 bit format. If you have an 8 bit address then you need to shift it one bit to the right. + * This class allows use of the built-in I2C ports. Currently it allows I2C Master + * mode only. + * All addresses are in 7 bit format. If you have an 8 bit address then you need to + * shift it one bit to the right. * @url http://www.espruino.com/Reference#I2C */ declare class I2C { @@ -6121,15 +6738,19 @@ declare class I2C { static find(pin: Pin): any; /** - * Create a software I2C port. This has limited functionality (no baud rate), but it can work on any pins. + * Create a software I2C port. This has limited functionality (no baud rate), but + * it can work on any pins. * Use `I2C.setup` to configure this port. * @constructor * @returns {any} An I2C object * @url http://www.espruino.com/Reference#l_I2C_I2C */ - static new(): any;/** + static new(): any; + + /** * Set up this I2C port - * If not specified in options, the default pins are used (usually the lowest numbered pins on the lowest port that supports this peripheral) + * If not specified in options, the default pins are used (usually the lowest + * numbered pins on the lowest port that supports this peripheral) * * @param {any} options * An optional structure containing extra information on initialising the I2C port @@ -6137,19 +6758,22 @@ declare class I2C { * You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `I2C` marker. Note that 400kHz is the maximum bitrate for most parts. * @url http://www.espruino.com/Reference#l_I2C_setup */ - setup(options: any): any; + setup(options: any): void; /** - * Transmit to the slave device with the given address. This is like Arduino's beginTransmission, write, and endTransmission rolled up into one. + * Transmit to the slave device with the given address. This is like Arduino's + * beginTransmission, write, and endTransmission rolled up into one. * * @param {any} address - The 7 bit address of the device to transmit to, or an object of the form `{address:12, stop:false}` to send this data without a STOP signal. * @param {any} data - One or more items to write. May be ints, strings, arrays, or special objects (see `E.toUint8Array` for more info). * @url http://www.espruino.com/Reference#l_I2C_writeTo */ - writeTo(address: any, ...data: any[]): any; + writeTo(address: any, ...data: any[]): void; /** - * Request bytes from the given slave device, and return them as a Uint8Array (packed array of bytes). This is like using Arduino Wire's requestFrom, available and read functions. Sends a STOP + * Request bytes from the given slave device, and return them as a Uint8Array + * (packed array of bytes). This is like using Arduino Wire's requestFrom, + * available and read functions. Sends a STOP * * @param {any} address - The 7 bit address of the device to request bytes from, or an object of the form `{address:12, stop:false}` to send this data without a STOP signal. * @param {number} quantity - The number of bytes to request @@ -6160,13 +6784,18 @@ declare class I2C { } /** - * This class handles waveforms. In Espruino, a Waveform is a set of data that you want to input or output. + * This class handles waveforms. In Espruino, a Waveform is a set of data that you + * want to input or output. * @url http://www.espruino.com/Reference#Waveform */ declare class Waveform { /** - * Create a waveform class. This allows high speed input and output of waveforms. It has an internal variable called `buffer` (as well as `buffer2` when double-buffered - see `options` below) which contains the data to input/output. - * When double-buffered, a 'buffer' event will be emitted each time a buffer is finished with (the argument is that buffer). When the recording stops, a 'finish' event will be emitted (with the first argument as the buffer). + * Create a waveform class. This allows high speed input and output of waveforms. + * It has an internal variable called `buffer` (as well as `buffer2` when + * double-buffered - see `options` below) which contains the data to input/output. + * When double-buffered, a 'buffer' event will be emitted each time a buffer is + * finished with (the argument is that buffer). When the recording stops, a + * 'finish' event will be emitted (with the first argument as the buffer). * @constructor * * @param {number} samples - The number of samples @@ -6174,36 +6803,42 @@ declare class Waveform { * @returns {any} An Waveform object * @url http://www.espruino.com/Reference#l_Waveform_Waveform */ - static new(samples: number, options: any): any;/** - * Will start outputting the waveform on the given pin - the pin must have previously been initialised with analogWrite. If not repeating, it'll emit a `finish` event when it is done. + static new(samples: number, options: any): any; + + /** + * Will start outputting the waveform on the given pin - the pin must have + * previously been initialised with analogWrite. If not repeating, it'll emit a + * `finish` event when it is done. * * @param {Pin} output - The pin to output on * @param {number} freq - The frequency to output each sample at * @param {any} options - Optional options struct `{time:float,repeat:bool}` where: `time` is the that the waveform with start output at, e.g. `getTime()+1` (otherwise it is immediate), `repeat` is a boolean specifying whether to repeat the give sample * @url http://www.espruino.com/Reference#l_Waveform_startOutput */ - startOutput(output: Pin, freq: number, options: any): any; + startOutput(output: Pin, freq: number, options: any): void; /** - * Will start inputting the waveform on the given pin that supports analog. If not repeating, it'll emit a `finish` event when it is done. + * Will start inputting the waveform on the given pin that supports analog. If not + * repeating, it'll emit a `finish` event when it is done. * * @param {Pin} output - The pin to output on * @param {number} freq - The frequency to output each sample at * @param {any} options - Optional options struct `{time:float,repeat:bool}` where: `time` is the that the waveform with start output at, e.g. `getTime()+1` (otherwise it is immediate), `repeat` is a boolean specifying whether to repeat the give sample * @url http://www.espruino.com/Reference#l_Waveform_startInput */ - startInput(output: Pin, freq: number, options: any): any; + startInput(output: Pin, freq: number, options: any): void; /** * Stop a waveform that is currently outputting * @url http://www.espruino.com/Reference#l_Waveform_stop */ - stop(): any; + stop(): void; } /** * This is the built-in class for Pins, such as D0,D1,LED1, or BTN - * You can call the methods on Pin, or you can use Wiring-style functions such as digitalWrite + * You can call the methods on Pin, or you can use Wiring-style functions such as + * digitalWrite * @url http://www.espruino.com/Reference#Pin */ declare class Pin { @@ -6215,9 +6850,12 @@ declare class Pin { * @returns {any} A Pin object * @url http://www.espruino.com/Reference#l_Pin_Pin */ - static new(value: any): any;/** + static new(value: any): any; + + /** * Returns the input state of the pin as a boolean. - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset the pin's state to `"input"` + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset the pin's state to `"input"` * @returns {boolean} Whether pin is a logical 1 or 0 * @url http://www.espruino.com/Reference#l_Pin_read */ @@ -6225,36 +6863,40 @@ declare class Pin { /** * Sets the output state of the pin to a 1 - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset the pin's state to `"output"` + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset the pin's state to `"output"` * @url http://www.espruino.com/Reference#l_Pin_set */ - set(): any; + set(): void; /** * Sets the output state of the pin to a 0 - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset the pin's state to `"output"` + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset the pin's state to `"output"` * @url http://www.espruino.com/Reference#l_Pin_reset */ - reset(): any; + reset(): void; /** * Sets the output state of the pin to the parameter given - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset the pin's state to `"output"` + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset the pin's state to `"output"` * * @param {boolean} value - Whether to set output high (true/1) or low (false/0) * @url http://www.espruino.com/Reference#l_Pin_write */ - write(value: boolean): any; + write(value: boolean): void; /** * Sets the output state of the pin to the parameter given at the specified time. - * **Note:** this **doesn't** change the mode of the pin to an output. To do that, you need to use `pin.write(0)` or `pinMode(pin, 'output')` first. + * **Note:** this **doesn't** change the mode of the pin to an output. To do that, + * you need to use `pin.write(0)` or `pinMode(pin, 'output')` first. * * @param {boolean} value - Whether to set output high (true/1) or low (false/0) * @param {number} time - Time at which to write * @url http://www.espruino.com/Reference#l_Pin_writeAtTime */ - writeAtTime(value: boolean, time: number): any; + writeAtTime(value: boolean, time: number): void; /** * Return the current mode of the given pin. See `pinMode` for more information. @@ -6264,17 +6906,19 @@ declare class Pin { getMode(): any; /** - * Set the mode of the given pin. See [`pinMode`](#l__global_pinMode) for more information on pin modes. + * Set the mode of the given pin. See [`pinMode`](#l__global_pinMode) for more + * information on pin modes. * * @param {any} mode - The mode - a string that is either 'analog', 'input', 'input_pullup', 'input_pulldown', 'output', 'opendrain', 'af_output' or 'af_opendrain'. Do not include this argument if you want to revert to automatic pin mode setting. * @url http://www.espruino.com/Reference#l_Pin_mode */ - mode(mode: any): any; + mode(mode: any): void; /** * Toggles the state of the pin from off to on, or from on to off. * **Note:** This method doesn't currently work on the ESP8266 port of Espruino. - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset the pin's state to `"output"` + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset the pin's state to `"output"` * @returns {boolean} True if the pin is high after calling the function * @url http://www.espruino.com/Reference#l_Pin_toggle */ @@ -6304,7 +6948,8 @@ declare class Pin { interface DataViewConstructor { /** - * Create a `DataView` object that can be used to access the data in an `ArrayBuffer`. + * Create a `DataView` object that can be used to access the data in an + * `ArrayBuffer`. * ``` * var b = new ArrayBuffer(8) * var v = new DataView(b) @@ -6321,7 +6966,7 @@ interface DataViewConstructor { * @returns {any} A `DataView` object * @url http://www.espruino.com/Reference#l_DataView_DataView */ - new(buffer: any, byteOffset: number, byteLength: number): DataView; + new(buffer: ArrayBuffer, byteOffset?: number, byteLength?: number): DataView; } interface DataView { @@ -6332,7 +6977,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getFloat32 */ - getFloat32(byteOffset: number, littleEndian: boolean): any; + getFloat32(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6341,7 +6986,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getFloat64 */ - getFloat64(byteOffset: number, littleEndian: boolean): any; + getFloat64(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6350,7 +6995,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getInt8 */ - getInt8(byteOffset: number, littleEndian: boolean): any; + getInt8(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6359,7 +7004,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getInt16 */ - getInt16(byteOffset: number, littleEndian: boolean): any; + getInt16(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6368,7 +7013,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getInt32 */ - getInt32(byteOffset: number, littleEndian: boolean): any; + getInt32(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6377,7 +7022,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getUint8 */ - getUint8(byteOffset: number, littleEndian: boolean): any; + getUint8(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6386,7 +7031,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getUint16 */ - getUint16(byteOffset: number, littleEndian: boolean): any; + getUint16(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6395,7 +7040,7 @@ interface DataView { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_DataView_getUint32 */ - getUint32(byteOffset: number, littleEndian: boolean): any; + getUint32(byteOffset: number, littleEndian?: boolean): number; /** * @@ -6404,7 +7049,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setFloat32 */ - setFloat32(byteOffset: number, value: any, littleEndian: boolean): any; + setFloat32(byteOffset: number, value: number, littleEndian?: boolean): void; /** * @@ -6413,7 +7058,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setFloat64 */ - setFloat64(byteOffset: number, value: any, littleEndian: boolean): any; + setFloat64(byteOffset: number, value: number, littleEndian?: boolean): void; /** * @@ -6422,7 +7067,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setInt8 */ - setInt8(byteOffset: number, value: any, littleEndian: boolean): any; + setInt8(byteOffset: number, value: number, littleEndian?: boolean): void; /** * @@ -6431,7 +7076,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setInt16 */ - setInt16(byteOffset: number, value: any, littleEndian: boolean): any; + setInt16(byteOffset: number, value: number, littleEndian?: boolean): void; /** * @@ -6440,7 +7085,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setInt32 */ - setInt32(byteOffset: number, value: any, littleEndian: boolean): any; + setInt32(byteOffset: number, value: number, littleEndian?: boolean): void; /** * @@ -6449,7 +7094,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setUint8 */ - setUint8(byteOffset: number, value: any, littleEndian: boolean): any; + setUint8(byteOffset: number, value: number, littleEndian?: boolean): void; /** * @@ -6458,7 +7103,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setUint16 */ - setUint16(byteOffset: number, value: any, littleEndian: boolean): any; + setUint16(byteOffset: number, value: number, littleEndian?: boolean): void; /** * @@ -6467,7 +7112,7 @@ interface DataView { * @param {boolean} littleEndian - (optional) Whether to read in little endian - if false or undefined data is read as big endian * @url http://www.espruino.com/Reference#l_DataView_setUint32 */ - setUint32(byteOffset: number, value: any, littleEndian: boolean): any; + setUint32(byteOffset: number, value: number, littleEndian?: boolean): void; } /** @@ -6478,12 +7123,17 @@ declare const DataView: DataViewConstructor /** * This class allows use of the built-in USARTs - * Methods may be called on the `USB`, `Serial1`, `Serial2`, `Serial3`, `Serial4`, `Serial5` and `Serial6` objects. While different processors provide different numbers of USARTs, on official Espruino boards you can always rely on at least `Serial1` being available + * Methods may be called on the `USB`, `Serial1`, `Serial2`, `Serial3`, `Serial4`, + * `Serial5` and `Serial6` objects. While different processors provide different + * numbers of USARTs, on official Espruino boards you can always rely on at least + * `Serial1` being available * @url http://www.espruino.com/Reference#Serial */ declare class Serial { /** - * The `data` event is called when data is received. If a handler is defined with `X.on('data', function(data) { ... })` then it will be called, otherwise data will be stored in an internal buffer, where it can be retrieved with `X.read()` + * The `data` event is called when data is received. If a handler is defined with + * `X.on('data', function(data) { ... })` then it will be called, otherwise data + * will be stored in an internal buffer, where it can be retrieved with `X.read()` * @param {string} event - The event to listen to. * @param {(data: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `data` A string containing one or more characters of received data @@ -6493,13 +7143,14 @@ declare class Serial { /** * The `framing` event is called when there was activity on the input to the UART - * but the `STOP` bit wasn't in the correct place. This is either because there - * was noise on the line, or the line has been pulled to 0 for a long period - * of time. - * To enable this, you must initialise Serial with `SerialX.setup(..., { ..., errors:true });` + * but the `STOP` bit wasn't in the correct place. This is either because there was + * noise on the line, or the line has been pulled to 0 for a long period of time. + * To enable this, you must initialise Serial with `SerialX.setup(..., { ..., + * errors:true });` * **Note:** Even though there was an error, the byte will still be received and * passed to the `data` handler. - * **Note:** This only works on STM32 and NRF52 based devices (eg. all official Espruino boards) + * **Note:** This only works on STM32 and NRF52 based devices (eg. all official + * Espruino boards) * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_Serial_framing @@ -6507,12 +7158,14 @@ declare class Serial { static on(event: "framing", callback: () => void): void; /** - * The `parity` event is called when the UART was configured with a parity bit, - * and this doesn't match the bits that have actually been received. - * To enable this, you must initialise Serial with `SerialX.setup(..., { ..., errors:true });` + * The `parity` event is called when the UART was configured with a parity bit, and + * this doesn't match the bits that have actually been received. + * To enable this, you must initialise Serial with `SerialX.setup(..., { ..., + * errors:true });` * **Note:** Even though there was an error, the byte will still be received and * passed to the `data` handler. - * **Note:** This only works on STM32 and NRF52 based devices (eg. all official Espruino boards) + * **Note:** This only works on STM32 and NRF52 based devices (eg. all official + * Espruino boards) * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_Serial_parity @@ -6520,7 +7173,8 @@ declare class Serial { static on(event: "parity", callback: () => void): void; /** - * Try and find a USART (Serial) hardware device that will work on this pin (eg. `Serial1`) + * Try and find a USART (Serial) hardware device that will work on this pin (eg. + * `Serial1`) * May return undefined if no device can be found. * * @param {Pin} pin - A pin to search with @@ -6530,22 +7184,25 @@ declare class Serial { static find(pin: Pin): any; /** - * Create a software Serial port. This has limited functionality (only low baud rates), but it can work on any pins. + * Create a software Serial port. This has limited functionality (only low baud + * rates), but it can work on any pins. * Use `Serial.setup` to configure this port. * @constructor * @returns {any} A Serial object * @url http://www.espruino.com/Reference#l_Serial_Serial */ - static new(): any;/** + static new(): any; + + /** * Set this Serial port as the port for the JavaScript console (REPL). - * Unless `force` is set to true, changes in the connection state of the board - * (for instance plugging in USB) will cause the console to change. + * Unless `force` is set to true, changes in the connection state of the board (for + * instance plugging in USB) will cause the console to change. * See `E.setConsole` for a more flexible version of this function. * * @param {boolean} force - Whether to force the console to this port * @url http://www.espruino.com/Reference#l_Serial_setConsole */ - setConsole(force: boolean): any; + setConsole(force: boolean): void; /** * Setup this Serial port with the given baud rate and options. @@ -6569,72 +7226,77 @@ declare class Serial { * errors:false // (default false) whether to forward framing/parity errors * } * ``` - * You can find out which pins to use by looking at [your board's reference page](#boards) - * and searching for pins with the `UART`/`USART` markers. - * If not specified in options, the default pins are used for rx and tx - * (usually the lowest numbered pins on the lowest port that supports - * this peripheral). `ck` and `cts` are not used unless specified. + * You can find out which pins to use by looking at [your board's reference + * page](#boards) and searching for pins with the `UART`/`USART` markers. + * If not specified in options, the default pins are used for rx and tx (usually + * the lowest numbered pins on the lowest port that supports this peripheral). `ck` + * and `cts` are not used unless specified. * Note that even after changing the RX and TX pins, if you have called setup * before then the previous RX and TX pins will still be connected to the Serial * port as well - until you set them to something else using `digitalWrite` or * `pinMode`. - * Flow control can be xOn/xOff (`flow:'xon'`) or hardware flow control - * (receive only) if `cts` is specified. If `cts` is set to a pin, the - * pin's value will be 0 when Espruino is ready for data and 1 when it isn't. + * Flow control can be xOn/xOff (`flow:'xon'`) or hardware flow control (receive + * only) if `cts` is specified. If `cts` is set to a pin, the pin's value will be 0 + * when Espruino is ready for data and 1 when it isn't. * By default, framing or parity errors don't create `framing` or `parity` events - * on the `Serial` object because storing these errors uses up additional - * storage in the queue. If you're intending to receive a lot of malformed - * data then the queue might overflow `E.getErrorFlags()` would return `FIFO_FULL`. - * However if you need to respond to `framing` or `parity` errors then - * you'll need to use `errors:true` when initialising serial. - * On Linux builds there is no default Serial device, so you must specify - * a path to a device - for instance: `Serial1.setup(9600,{path:"/dev/ttyACM0"})` + * on the `Serial` object because storing these errors uses up additional storage + * in the queue. If you're intending to receive a lot of malformed data then the + * queue might overflow `E.getErrorFlags()` would return `FIFO_FULL`. However if + * you need to respond to `framing` or `parity` errors then you'll need to use + * `errors:true` when initialising serial. + * On Linux builds there is no default Serial device, so you must specify a path to + * a device - for instance: `Serial1.setup(9600,{path:"/dev/ttyACM0"})` * You can also set up 'software serial' using code like: * ``` * var s = new Serial(); * s.setup(9600,{rx:a_pin, tx:a_pin}); * ``` - * However software serial doesn't use `ck`, `cts`, `parity`, `flow` or `errors` parts of the initialisation object. + * However software serial doesn't use `ck`, `cts`, `parity`, `flow` or `errors` + * parts of the initialisation object. * * @param {any} baudrate - The baud rate - the default is 9600 * @param {any} options - An optional structure containing extra information on initialising the serial port - see below. * @url http://www.espruino.com/Reference#l_Serial_setup */ - setup(baudrate: any, options: any): any; + setup(baudrate: any, options: any): void; /** - * If the serial (or software serial) device was set up, - * uninitialise it. + * If the serial (or software serial) device was set up, uninitialise it. * @url http://www.espruino.com/Reference#l_Serial_unsetup */ - unsetup(): any; + unsetup(): void; /** * Print a string to the serial port - without a line feed - * **Note:** This function replaces any occurances of `\n` in the string with `\r\n`. To avoid this, use `Serial.write`. + * **Note:** This function replaces any occurances of `\n` in the string with + * `\r\n`. To avoid this, use `Serial.write`. * * @param {any} string - A String to print * @url http://www.espruino.com/Reference#l_Serial_print */ - print(string: any): any; + print(string: any): void; /** * Print a line to the serial port with a newline (`\r\n`) at the end of it. - * **Note:** This function converts data to a string first, eg `Serial.print([1,2,3])` is equivalent to `Serial.print("1,2,3"). If you'd like to write raw bytes, use `Serial.write`. + * **Note:** This function converts data to a string first, eg + * `Serial.print([1,2,3])` is equivalent to `Serial.print("1,2,3"). If you'd like + * to write raw bytes, use `Serial.write`. * * @param {any} string - A String to print * @url http://www.espruino.com/Reference#l_Serial_println */ - println(string: any): any; + println(string: any): void; /** * Write a character or array of data to the serial port - * This method writes unmodified data, eg `Serial.write([1,2,3])` is equivalent to `Serial.write("\1\2\3")`. If you'd like data converted to a string first, use `Serial.print`. + * This method writes unmodified data, eg `Serial.write([1,2,3])` is equivalent to + * `Serial.write("\1\2\3")`. If you'd like data converted to a string first, use + * `Serial.print`. * * @param {any} data - One or more items to write. May be ints, strings, arrays, or special objects (see `E.toUint8Array` for more info). * @url http://www.espruino.com/Reference#l_Serial_write */ - write(...data: any[]): any; + write(...data: any[]): void; /** * Add data to this device as if it came directly from the input - it will be @@ -6644,16 +7306,17 @@ declare class Serial { * Serial1.inject('Hello World'); * // prints "Got Hel","Got lo World" (characters can be split over multiple callbacks) * ``` - * This is most useful if you wish to send characters to Espruino's - * REPL (console) while it is on another device. + * This is most useful if you wish to send characters to Espruino's REPL (console) + * while it is on another device. * * @param {any} data - One or more items to write. May be ints, strings, arrays, or special objects (see `E.toUint8Array` for more info). * @url http://www.espruino.com/Reference#l_Serial_inject */ - inject(...data: any[]): any; + inject(...data: any[]): void; /** - * Return how many bytes are available to read. If there is already a listener for data, this will always return 0. + * Return how many bytes are available to read. If there is already a listener for + * data, this will always return 0. * @returns {number} How many bytes are available * @url http://www.espruino.com/Reference#l_Serial_available */ @@ -6679,23 +7342,21 @@ declare class Serial { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_Serial_pipe */ - pipe(destination: any, options: any): any; + pipe(destination: any, options: any): void; } /** - * These objects are created from `require("Storage").open` - * and allow Storage items to be read/written. - * The `Storage` library writes into Flash memory (which - * can only be erased in chunks), and unlike a normal filesystem - * it allocates files in one long contiguous area to allow them - * to be accessed easily from Espruino. - * This presents a challenge for `StorageFile` which allows you - * to append to a file, so instead `StorageFile` stores files - * in chunks. It uses the last character of the filename - * to denote the chunk number (eg `"foobar\1"`, `"foobar\2"`, etc). - * This means that while `StorageFile` files exist in the same - * area as those from `Storage`, they should be - * read using `Storage.open` (and not `Storage.read`). + * These objects are created from `require("Storage").open` and allow Storage items + * to be read/written. + * The `Storage` library writes into Flash memory (which can only be erased in + * chunks), and unlike a normal filesystem it allocates files in one long + * contiguous area to allow them to be accessed easily from Espruino. + * This presents a challenge for `StorageFile` which allows you to append to a + * file, so instead `StorageFile` stores files in chunks. It uses the last + * character of the filename to denote the chunk number (eg `"foobar\1"`, + * `"foobar\2"`, etc). + * This means that while `StorageFile` files exist in the same area as those from + * `Storage`, they should be read using `Storage.open` (and not `Storage.read`). * ``` * f = s.open("foobar","w"); * f.write("Hell"); @@ -6720,59 +7381,65 @@ declare class Serial { * // now get rid of file * f.erase(); * ``` - * **Note:** `StorageFile` uses the fact that all bits of erased flash memory - * are 1 to detect the end of a file. As such you should not write character - * code 255 (`"\xFF"`) to these files. + * **Note:** `StorageFile` uses the fact that all bits of erased flash memory are 1 + * to detect the end of a file. As such you should not write character code 255 + * (`"\xFF"`) to these files. * @url http://www.espruino.com/Reference#StorageFile */ declare class StorageFile { + + /** - * Read 'len' bytes of data from the file, and return a String containing those bytes. - * If the end of the file is reached, the String may be smaller than the amount of bytes - * requested, or if the file is already at the end, `undefined` is returned. + * Read 'len' bytes of data from the file, and return a String containing those + * bytes. + * If the end of the file is reached, the String may be smaller than the amount of + * bytes requested, or if the file is already at the end, `undefined` is returned. * * @param {number} len - How many bytes to read * @returns {any} A String, or undefined * @url http://www.espruino.com/Reference#l_StorageFile_read */ - read(len: number): String; + read(len: number): string; /** * Read a line of data from the file (up to and including `"\n"`) * @returns {any} A line of data * @url http://www.espruino.com/Reference#l_StorageFile_readLine */ - readLine(): String; + readLine(): string; /** * Return the length of the current file. - * This requires Espruino to read the file from scratch, - * which is not a fast operation. + * This requires Espruino to read the file from scratch, which is not a fast + * operation. * @returns {number} The current length in bytes of the file * @url http://www.espruino.com/Reference#l_StorageFile_getLength */ getLength(): number; /** - * Append the given data to a file. You should not attempt to append `"\xFF"` (character code 255). + * Append the given data to a file. You should not attempt to append `"\xFF"` + * (character code 255). * * @param {any} data - The data to write. This should not include `'\xFF'` (character code 255) * @url http://www.espruino.com/Reference#l_StorageFile_write */ - write(data: any): any; + write(data: string): void; /** * Erase this file * @url http://www.espruino.com/Reference#l_StorageFile_erase */ - erase(): any; + erase(): void; } interface processConstructor { /** - * This event is called when an exception gets thrown and isn't caught (eg. it gets all the way back to the event loop). - * You can use this for logging potential problems that might occur during execution when you - * might not be able to see what is written to the console, for example: + * This event is called when an exception gets thrown and isn't caught (eg. it gets + * all the way back to the event loop). + * You can use this for logging potential problems that might occur during + * execution when you might not be able to see what is written to the console, for + * example: * ``` * var lastError; * process.on('uncaughtException', function(e) { @@ -6784,8 +7451,8 @@ interface processConstructor { * print(lastError,lastError.stack?"\n"+lastError.stack:"") * } * ``` - * **Note:** When this is used, exceptions will cease to be reported on the console - which - * may make debugging difficult! + * **Note:** When this is used, exceptions will cease to be reported on the + * console - which may make debugging difficult! * @param {string} event - The event to listen to. * @param {(exception: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `exception` The uncaught exception @@ -6808,34 +7475,51 @@ interface processConstructor { * * `RAM` - total amount of on-chip RAM in bytes * * `FLASH` - total amount of on-chip flash memory in bytes * * `SPIFLASH` - (on Bangle.js) total amount of off-chip flash memory in bytes - * * `HWVERSION` - For Puck.js this is the board revision (1, 2, 2.1), or for Bangle.js it's 1 or 2 + * * `HWVERSION` - For Puck.js this is the board revision (1, 2, 2.1), or for + * Bangle.js it's 1 or 2 * * `STORAGE` - memory in bytes dedicated to the `Storage` module * * `SERIAL` - the serial number of this chip - * * `CONSOLE` - the name of the current console device being used (`Serial1`, `USB`, `Bluetooth`, etc) + * * `CONSOLE` - the name of the current console device being used (`Serial1`, + * `USB`, `Bluetooth`, etc) * * `MODULES` - a list of built-in modules separated by commas - * * `EXPTR` - The address of the `exportPtrs` structure in flash (this includes links to built-in functions that compiled JS code needs) - * * `APP_RAM_BASE` - On nRF5x boards, this is the RAM required by the Softdevice *if it doesn't exactly match what was allocated*. You can use this to update `LD_APP_RAM_BASE` in the `BOARD.py` file - * For example, to get a list of built-in modules, you can use `process.env.MODULES.split(',')` + * * `EXPTR` - The address of the `exportPtrs` structure in flash (this includes + * links to built-in functions that compiled JS code needs) + * * `APP_RAM_BASE` - On nRF5x boards, this is the RAM required by the Softdevice + * *if it doesn't exactly match what was allocated*. You can use this to update + * `LD_APP_RAM_BASE` in the `BOARD.py` file + * For example, to get a list of built-in modules, you can use + * `process.env.MODULES.split(',')` * @returns {any} An object * @url http://www.espruino.com/Reference#l_process_env */ env: any; /** - * Run a Garbage Collection pass, and return an object containing information on memory usage. - * * `free` : Memory that is available to be used (in blocks) + * Run a Garbage Collection pass, and return an object containing information on + * memory usage. + * * `free` : Memory that is available to be used (in blocks) * * `usage` : Memory that has been used (in blocks) * * `total` : Total memory (in blocks) - * * `history` : Memory used for command history - that is freed if memory is low. Note that this is INCLUDED in the figure for 'free' - * * `gc` : Memory freed during the GC pass - * * `gctime` : Time taken for GC pass (in milliseconds) + * * `history` : Memory used for command history - that is freed if memory is low. + * Note that this is INCLUDED in the figure for 'free' + * * `gc` : Memory freed during the GC pass + * * `gctime` : Time taken for GC pass (in milliseconds) * * `blocksize` : Size of a block (variable) in bytes - * * `stackEndAddress` : (on ARM) the address (that can be used with peek/poke/etc) of the END of the stack. The stack grows down, so unless you do a lot of recursion the bytes above this can be used. - * * `flash_start` : (on ARM) the address of the start of flash memory (usually `0x8000000`) - * * `flash_binary_end` : (on ARM) the address in flash memory of the end of Espruino's firmware. - * * `flash_code_start` : (on ARM) the address in flash memory of pages that store any code that you save with `save()`. - * * `flash_length` : (on ARM) the amount of flash memory this firmware was built for (in bytes). **Note:** Some STM32 chips actually have more memory than is advertised. - * Memory units are specified in 'blocks', which are around 16 bytes each (depending on your device). The actual size is available in `blocksize`. See http://www.espruino.com/Performance for more information. + * * `stackEndAddress` : (on ARM) the address (that can be used with peek/poke/etc) + * of the END of the stack. The stack grows down, so unless you do a lot of + * recursion the bytes above this can be used. + * * `flash_start` : (on ARM) the address of the start of flash memory (usually + * `0x8000000`) + * * `flash_binary_end` : (on ARM) the address in flash memory of the end of + * Espruino's firmware. + * * `flash_code_start` : (on ARM) the address in flash memory of pages that store + * any code that you save with `save()`. + * * `flash_length` : (on ARM) the amount of flash memory this firmware was built + * for (in bytes). **Note:** Some STM32 chips actually have more memory than is + * advertised. + * Memory units are specified in 'blocks', which are around 16 bytes each + * (depending on your device). The actual size is available in `blocksize`. See + * http://www.espruino.com/Performance for more information. * **Note:** To find free areas of flash memory, see `require('Flash').getFree()` * * @param {any} gc - An optional boolean. If `undefined` or `true` Garbage collection is performed, if `false` it is not @@ -6873,13 +7557,13 @@ declare class Modules { * @param {any} id - The module name to remove * @url http://www.espruino.com/Reference#l_Modules_removeCached */ - static removeCached(id: any): any; + static removeCached(id: any): void; /** * Remove all cached modules * @url http://www.espruino.com/Reference#l_Modules_removeAllCached */ - static removeAllCached(): any; + static removeAllCached(): void; /** * Add the given module to the cache @@ -6888,7 +7572,9 @@ declare class Modules { * @param {any} sourcecode - The module's sourcecode * @url http://www.espruino.com/Reference#l_Modules_addCached */ - static addCached(id: any, sourcecode: any): any; + static addCached(id: any, sourcecode: any): void; + + } interface StringConstructor { @@ -6930,7 +7616,8 @@ interface String { charAt(pos: number): any; /** - * Return the integer value of a single character at the given position in the String. + * Return the integer value of a single character at the given position in the + * String. * Note that this returns 0 not 'NaN' for out of bounds characters * * @param {number} pos - The character number in the string. Negative values return characters from end of string (-1 = last char) @@ -6988,7 +7675,9 @@ interface String { match(substr: any): any; /** - * Search and replace ONE occurrance of `subStr` with `newSubStr` and return the result. This doesn't alter the original string. Regular expressions not supported. + * Search and replace ONE occurrance of `subStr` with `newSubStr` and return the + * result. This doesn't alter the original string. Regular expressions not + * supported. * * @param {any} subStr - The string to search for * @param {any} newSubStr - The string to replace it with @@ -7025,8 +7714,10 @@ interface String { slice(start: number, end: any): any; /** - * Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==['1', '2', '3']``` - * Regular Expressions can also be used to split strings, eg. `'1a2b3 4'.split(/[^0-9]/)==['1', '2', '3', '4']`. + * Return an array made by splitting this string up by the separator. eg. + * ```'1,2,3'.split(',')==['1', '2', '3']``` + * Regular Expressions can also be used to split strings, eg. `'1a2b3 + * 4'.split(/[^0-9]/)==['1', '2', '3', '4']`. * * @param {any} separator - The separator `String` or `RegExp` to use * @returns {any} Part of this string from start for len characters @@ -7054,10 +7745,11 @@ interface String { * @returns {any} A String with Whitespace removed from the beginning and end * @url http://www.espruino.com/Reference#l_String_trim */ - trim(): String; + trim(): string; /** - * Append all arguments to this `String` and return the result. Does not modify the original `String`. + * Append all arguments to this `String` and return the result. Does not modify the + * original `String`. * * @param {any} args - Strings to append * @returns {any} The result of appending all arguments to this string @@ -7099,7 +7791,7 @@ interface String { * @returns {any} A string containing repetitions of this string * @url http://www.espruino.com/Reference#l_String_repeat */ - repeat(count: number): String; + repeat(count: number): string; /** * Pad this string at the beginnind to the required number of characters @@ -7113,7 +7805,7 @@ interface String { * @returns {any} A string containing this string padded to the correct length * @url http://www.espruino.com/Reference#l_String_padStart */ - padStart(targetLength: number, padString?: any): String; + padStart(targetLength: number, padString?: any): string; /** * Pad this string at the end to the required number of characters @@ -7127,12 +7819,13 @@ interface String { * @returns {any} A string containing this string padded to the correct length * @url http://www.espruino.com/Reference#l_String_padEnd */ - padEnd(targetLength: number, padString?: any): String; + padEnd(targetLength: number, padString?: any): string; } /** * This is the built-in class for Text Strings. - * Text Strings in Espruino are not zero-terminated, so you can store zeros in them. + * Text Strings in Espruino are not zero-terminated, so you can store zeros in + * them. * @url http://www.espruino.com/Reference#String */ declare const String: StringConstructor @@ -7145,17 +7838,23 @@ interface ArrayConstructor { * @returns {boolean} True if var is an array, false if not. * @url http://www.espruino.com/Reference#l_Array_isArray */ - isArray(variable: any): boolean; + isArray(arg: any): arg is any[]; /** - * Create an Array. Either give it one integer argument (>=0) which is the length of the array, or any number of arguments + * Create an Array. Either give it one integer argument (>=0) which is the length + * of the array, or any number of arguments * @constructor * * @param {any} args - The length of the array OR any number of items to add to the array * @returns {any} An Array * @url http://www.espruino.com/Reference#l_Array_Array */ - new(...args: any[]): any; + new(arrayLength?: number): any[]; + new(arrayLength: number): T[]; + new(...items: T[]): T[]; + (arrayLength?: number): any[]; + (arrayLength: number): T[]; + (...items: T[]): T[]; } interface Array { @@ -7166,14 +7865,14 @@ interface Array { * @returns {any} A String representing the array * @url http://www.espruino.com/Reference#l_Array_toString */ - toString(radix: any): any; + toString(): string; /** * Find the length of the array - * @returns {any} The value of the array + * @returns {any} The length of the array * @url http://www.espruino.com/Reference#l_Array_length */ - length: any; + length: number; /** * Return the index of the value in the array, or -1 @@ -7183,7 +7882,7 @@ interface Array { * @returns {any} the index of the value in the array, or -1 * @url http://www.espruino.com/Reference#l_Array_indexOf */ - indexOf(value: any, startIndex: number): any; + indexOf(value: T, startIndex?: number): number; /** * Return `true` if the array includes the value, `false` otherwise @@ -7193,66 +7892,73 @@ interface Array { * @returns {boolean} `true` if the array includes the value, `false` otherwise * @url http://www.espruino.com/Reference#l_Array_includes */ - includes(value: any, startIndex: number): boolean; + includes(value: T, startIndex?: number): boolean; /** - * Join all elements of this array together into one string, using 'separator' between them. eg. ```[1,2,3].join(' ')=='1 2 3'``` + * Join all elements of this array together into one string, using 'separator' + * between them. e.g. ```[1,2,3].join(' ')=='1 2 3'``` * * @param {any} separator - The separator * @returns {any} A String representing the Joined array * @url http://www.espruino.com/Reference#l_Array_join */ - join(separator: any): any; + join(separator?: string): string; /** * Push a new value onto the end of this array' - * This is the opposite of `[1,2,3].unshift(0)`, which adds one or more elements to the beginning of the array. + * This is the opposite of `[1,2,3].unshift(0)`, which adds one or more elements to + * the beginning of the array. * * @param {any} arguments - One or more arguments to add * @returns {number} The new size of the array * @url http://www.espruino.com/Reference#l_Array_push */ - push(...arguments: any[]): number; + push(...arguments: T[]): number; /** * Remove and return the value on the end of this array. - * This is the opposite of `[1,2,3].shift()`, which removes an element from the beginning of the array. + * This is the opposite of `[1,2,3].shift()`, which removes an element from the + * beginning of the array. * @returns {any} The value that is popped off * @url http://www.espruino.com/Reference#l_Array_pop */ - pop(): any; + pop(): T | undefined; /** - * Return an array which is made from the following: ```A.map(function) = [function(A[0]), function(A[1]), ...]``` + * Return an array which is made from the following: ```A.map(function) = + * [function(A[0]), function(A[1]), ...]``` * * @param {any} function - Function used to map one item to another * @param {any} thisArg - if specified, the function is called with 'this' set to thisArg (optional) * @returns {any} An array containing the results * @url http://www.espruino.com/Reference#l_Array_map */ - map(func: any, thisArg: any): any; + map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; /** * Executes a provided function once per array element. * * @param {any} function - Function to be executed - * @param {any} thisArg - if specified, the function is called with 'this' set to thisArg (optional) + * @param {any} [thisArg] - [optional] If specified, the function is called with 'this' set to thisArg (optional) * @url http://www.espruino.com/Reference#l_Array_forEach */ - forEach(func: any, thisArg: any): any; + forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; /** - * Return an array which contains only those elements for which the callback function returns 'true' + * Return an array which contains only those elements for which the callback + * function returns 'true' * * @param {any} function - Function to be executed * @param {any} thisArg - if specified, the function is called with 'this' set to thisArg (optional) * @returns {any} An array containing the results * @url http://www.espruino.com/Reference#l_Array_filter */ - filter(func: any, thisArg: any): any; + filter(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; + filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; /** - * Return the array element where `function` returns `true`, or `undefined` if it doesn't returns `true` for any element. + * Return the array element where `function` returns `true`, or `undefined` if it + * doesn't returns `true` for any element. * ``` * ["Hello","There","World"].find(a=>a[0]=="T") * // returns "There" @@ -7262,10 +7968,12 @@ interface Array { * @returns {any} The array element where `function` returns `true`, or `undefined` * @url http://www.espruino.com/Reference#l_Array_find */ - find(func: any): any; + find(predicate: (this: void, value: T, index: number, obj: T[]) => value is S): S | undefined; + find(predicate: (value: T, index: number, obj: T[]) => unknown): T | undefined; /** - * Return the array element's index where `function` returns `true`, or `-1` if it doesn't returns `true` for any element. + * Return the array element's index where `function` returns `true`, or `-1` if it + * doesn't returns `true` for any element. * ``` * ["Hello","There","World"].findIndex(a=>a[0]=="T") * // returns 1 @@ -7275,17 +7983,18 @@ interface Array { * @returns {any} The array element's index where `function` returns `true`, or `-1` * @url http://www.espruino.com/Reference#l_Array_findIndex */ - findIndex(func: any): any; + findIndex(predicate: (value: T, index: number, obj: T[]) => unknown): number; /** - * Return 'true' if the callback returns 'true' for any of the elements in the array + * Return 'true' if the callback returns 'true' for any of the elements in the + * array * * @param {any} function - Function to be executed * @param {any} thisArg - if specified, the function is called with 'this' set to thisArg (optional) * @returns {any} A boolean containing the result * @url http://www.espruino.com/Reference#l_Array_some */ - some(func: any, thisArg: any): any; + some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; /** * Return 'true' if the callback returns 'true' for every element in the array @@ -7295,17 +8004,19 @@ interface Array { * @returns {any} A boolean containing the result * @url http://www.espruino.com/Reference#l_Array_every */ - every(func: any, thisArg: any): any; + every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; /** - * Execute `previousValue=initialValue` and then `previousValue = callback(previousValue, currentValue, index, array)` for each element in the array, and finally return previousValue. + * Execute `previousValue=initialValue` and then `previousValue = + * callback(previousValue, currentValue, index, array)` for each element in the + * array, and finally return previousValue. * * @param {any} callback - Function used to reduce the array * @param {any} initialValue - if specified, the initial value to pass to the function * @returns {any} The value returned by the last function called * @url http://www.espruino.com/Reference#l_Array_reduce */ - reduce(callback: any, initialValue: any): any; + reduce(callback: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T; /** * Both remove and add items to an array @@ -7316,7 +8027,7 @@ interface Array { * @returns {any} An array containing the removed elements. If only one element is removed, an array of one element is returned. * @url http://www.espruino.com/Reference#l_Array_splice */ - splice(index: number, howMany: any, ...elements: any[]): any; + splice(index: number, howMany?: number, ...elements: T[]): T[]; /** * Remove and return the first element of the array. @@ -7325,17 +8036,18 @@ interface Array { * @returns {any} The element that was removed * @url http://www.espruino.com/Reference#l_Array_shift */ - shift(): any; + shift(): T | undefined; /** * Add one or more items to the start of the array, and return its new length. - * This is the opposite of `[1,2,3].push(4)`, which puts one or more elements on the end. + * This is the opposite of `[1,2,3].push(4)`, which puts one or more elements on + * the end. * * @param {any} elements - One or more items to add to the beginning of the array * @returns {number} The new array length * @url http://www.espruino.com/Reference#l_Array_unshift */ - unshift(...elements: any[]): number; + unshift(...elements: T[]): number; /** * Return a copy of a portion of this array (in a new array) @@ -7345,7 +8057,7 @@ interface Array { * @returns {any} A new array * @url http://www.espruino.com/Reference#l_Array_slice */ - slice(start: number, end: any): any; + slice(start?: number, end?: number): T[]; /** * Do an in-place quicksort of the array @@ -7354,16 +8066,17 @@ interface Array { * @returns {any} This array object * @url http://www.espruino.com/Reference#l_Array_sort */ - sort(variable: any): any; + sort(compareFn?: (a: T, b: T) => number): T[]; /** - * Create a new array, containing the elements from this one and any arguments, if any argument is an array then those elements will be added. + * Create a new array, containing the elements from this one and any arguments, if + * any argument is an array then those elements will be added. * * @param {any} args - Any items to add to the array * @returns {any} An Array * @url http://www.espruino.com/Reference#l_Array_concat */ - concat(...args: any[]): any; + concat(...args: (T | T[])[]): T[]; /** * Fill this array with the given value, for every index `>= start` and `< end` @@ -7374,19 +8087,22 @@ interface Array { * @returns {any} This array * @url http://www.espruino.com/Reference#l_Array_fill */ - fill(value: any, start: number, end: any): any; + fill(value: T, start: number, end?: number): T[]; /** * Reverse all elements in this array (in place) * @returns {any} The array, but reversed. * @url http://www.espruino.com/Reference#l_Array_reverse */ - reverse(): any; + reverse(): T[]; + + [index: number]: T } /** * This is the built-in JavaScript class for arrays. - * Arrays can be defined with ```[]```, ```new Array()```, or ```new Array(length)``` + * Arrays can be defined with ```[]```, ```new Array()```, or ```new + * Array(length)``` * @url http://www.espruino.com/Reference#Array */ declare const Array: ArrayConstructor @@ -7402,7 +8118,8 @@ interface ObjectConstructor { keys(object: any): any; /** - * Returns an array of all properties (enumerable or not) found directly on a given object. + * Returns an array of all properties (enumerable or not) found directly on a given + * object. * * @param {any} object - The Object to return a list of property names for * @returns {any} An array of the Object's own properties @@ -7429,7 +8146,8 @@ interface ObjectConstructor { entries(object: any): any; /** - * Creates a new object with the specified prototype object and properties. properties are currently unsupported. + * Creates a new object with the specified prototype object and properties. + * properties are currently unsupported. * * @param {any} proto - A prototype object * @param {any} propertiesObject - An object containing properties. NOT IMPLEMENTED @@ -7450,13 +8168,19 @@ interface ObjectConstructor { /** * Add a new property to the Object. 'Desc' is an object with the following fields: - * * `configurable` (bool = false) - can this property be changed/deleted (not implemented) - * * `enumerable` (bool = false) - can this property be enumerated (not implemented) + * * `configurable` (bool = false) - can this property be changed/deleted (not + * implemented) + * * `enumerable` (bool = false) - can this property be enumerated (not + * implemented) * * `value` (anything) - the value of this property - * * `writable` (bool = false) - can the value be changed with the assignment operator? - * * `get` (function) - the getter function, or undefined if no getter (only supported on some platforms) - * * `set` (function) - the setter function, or undefined if no setter (only supported on some platforms) - * **Note:** `configurable`, `enumerable` and `writable` are not implemented and will be ignored. + * * `writable` (bool = false) - can the value be changed with the assignment + * operator? + * * `get` (function) - the getter function, or undefined if no getter (only + * supported on some platforms) + * * `set` (function) - the setter function, or undefined if no setter (only + * supported on some platforms) + * **Note:** `configurable`, `enumerable` and `writable` are not implemented and + * will be ignored. * * @param {any} obj - An object * @param {any} name - The name of the property @@ -7467,7 +8191,8 @@ interface ObjectConstructor { defineProperty(obj: any, name: any, desc: any): any; /** - * Adds new properties to the Object. See `Object.defineProperty` for more information + * Adds new properties to the Object. See `Object.defineProperty` for more + * information * * @param {any} obj - An object * @param {any} props - An object whose fields represent property names, and whose values are property descriptors. @@ -7487,8 +8212,8 @@ interface ObjectConstructor { getPrototypeOf(object: any): any; /** - * Set the prototype of the given object - this is like writing - * `object.__proto__ = prototype` but is the 'proper' ES6 way of doing it + * Set the prototype of the given object - this is like writing `object.__proto__ = + * prototype` but is the 'proper' ES6 way of doing it * * @param {any} object - An object * @param {any} prototype - The prototype to set on the object @@ -7552,7 +8277,8 @@ interface Object { /** * Return true if the object (not its prototype) has the given property. - * NOTE: This currently returns false-positives for built-in functions in prototypes + * NOTE: This currently returns false-positives for built-in functions in + * prototypes * * @param {any} name - The name of the property to search for * @returns {boolean} True if it exists, false if it doesn't @@ -7561,9 +8287,10 @@ interface Object { hasOwnProperty(name: any): boolean; /** - * Register an event listener for this object, for instance `Serial1.on('data', function(d) {...})`. - * This is the same as Node.js's [EventEmitter](https://nodejs.org/api/events.html) but on Espruino - * the functionality is built into every object: + * Register an event listener for this object, for instance `Serial1.on('data', + * function(d) {...})`. + * This is the same as Node.js's [EventEmitter](https://nodejs.org/api/events.html) + * but on Espruino the functionality is built into every object: * * `Object.on` * * `Object.emit` * * `Object.removeListener` @@ -7597,17 +8324,18 @@ interface Object { * @param {any} listener - The listener to call when this event is received * @url http://www.espruino.com/Reference#l_Object_on */ - on(event: any, listener: any): any; + on(event: any, listener: any): void; /** - * Call any event listeners that were added to this object with `Object.on`, for instance `obj.emit('data', 'Foo')`. + * Call any event listeners that were added to this object with `Object.on`, for + * instance `obj.emit('data', 'Foo')`. * For more information see `Object.on` * * @param {any} event - The name of the event, for instance 'data' * @param {any} args - Optional arguments * @url http://www.espruino.com/Reference#l_Object_emit */ - emit(event: any, ...args: any[]): any; + emit(event: any, ...args: any[]): void; /** * Removes the specified event listener. @@ -7624,7 +8352,7 @@ interface Object { * @param {any} listener - The listener to remove * @url http://www.espruino.com/Reference#l_Object_removeListener */ - removeListener(event: any, listener: any): any; + removeListener(event: any, listener: any): void; /** * Removes all listeners (if `event===undefined`), or those of the specified event. @@ -7639,7 +8367,7 @@ interface Object { * @param {any} event - The name of the event, for instance `'data'`. If not specified *all* listeners are removed. * @url http://www.espruino.com/Reference#l_Object_removeAllListeners */ - removeAllListeners(event: any): any; + removeAllListeners(event: any): void; } /** @@ -7662,13 +8390,14 @@ interface FunctionConstructor { interface Function { /** - * This replaces the function with the one in the argument - while keeping the old function's scope. - * This allows inner functions to be edited, and is used when edit() is called on an inner function. + * This replaces the function with the one in the argument - while keeping the old + * function's scope. This allows inner functions to be edited, and is used when + * edit() is called on an inner function. * * @param {any} newFunc - The new function to replace this function with * @url http://www.espruino.com/Reference#l_Function_replaceWith */ - replaceWith(newFunc: any): any; + replaceWith(newFunc: any): void; /** * This executes the function with the supplied 'this' argument and parameters @@ -7713,7 +8442,8 @@ declare const Function: FunctionConstructor */ declare class E { /** - * Setup the filesystem so that subsequent calls to `E.openFile` and `require('fs').*` will use an SD card on the supplied SPI device and pin. + * Setup the filesystem so that subsequent calls to `E.openFile` and + * `require('fs').*` will use an SD card on the supplied SPI device and pin. * It can even work using software SPI - for instance: * ``` * // DI/CMD = C7 @@ -7726,22 +8456,25 @@ declare class E { * console.log(require("fs").readdirSync()); * ``` * See [the page on File IO](http://www.espruino.com/File+IO) for more information. - * **Note:** We'd strongly suggest you add a pullup resistor from CD/CS pin to 3.3v. It is - * good practise to avoid accidental writes before Espruino is initialised, and some cards - * will not work reliably without one. - * **Note:** If you want to remove an SD card after you have started using it, you *must* call `E.unmountSD()` or you may cause damage to the card. + * **Note:** We'd strongly suggest you add a pullup resistor from CD/CS pin to + * 3.3v. It is good practise to avoid accidental writes before Espruino is + * initialised, and some cards will not work reliably without one. + * **Note:** If you want to remove an SD card after you have started using it, you + * *must* call `E.unmountSD()` or you may cause damage to the card. * * @param {any} spi - The SPI object to use for communication * @param {Pin} csPin - The pin to use for Chip Select * @url http://www.espruino.com/Reference#l_E_connectSDCard */ - static connectSDCard(spi: any, csPin: Pin): any; + static connectSDCard(spi: any, csPin: Pin): void; /** - * Unmount the SD card, so it can be removed. If you remove the SD card without calling this you may cause corruption, and you will be unable to access another SD card until you reset Espruino or call `E.unmountSD()`. + * Unmount the SD card, so it can be removed. If you remove the SD card without + * calling this you may cause corruption, and you will be unable to access another + * SD card until you reset Espruino or call `E.unmountSD()`. * @url http://www.espruino.com/Reference#l_E_unmountSD */ - static unmountSD(): any; + static unmountSD(): void; /** * Open a file @@ -7754,8 +8487,8 @@ declare class E { static openFile(path: any, mode: any): File; /** - * Change the paramters used for the flash filesystem. - * The default address is the last 1Mb of 4Mb Flash, 0x300000, with total size of 1Mb. + * Change the parameters used for the flash filesystem. The default address is the + * last 1Mb of 4Mb Flash, 0x300000, with total size of 1Mb. * Before first use the media needs to be formatted. * ``` * fs=require("fs"); @@ -7768,8 +8501,9 @@ declare class E { * fs.writeFileSync("bang.txt", "This is the way the world ends\nnot with a bang but a whimper.\n"); * fs.readdirSync(); * ``` - * This will create a drive of 100 * 4096 bytes at 0x300000. Be careful with the selection of flash addresses as you can overwrite firmware! - * You only need to format once, as each will erase the content. + * This will create a drive of 100 * 4096 bytes at 0x300000. Be careful with the + * selection of flash addresses as you can overwrite firmware! You only need to + * format once, as each will erase the content. * `E.flashFatFS({ addr:0x300000,sectors:100,format:true });` * * @param {any} options @@ -7784,8 +8518,8 @@ declare class E { /** * Display a menu on the screen, and set up the buttons to navigate through it. - * Supply an object containing menu items. When an item is selected, the - * function it references will be executed. For example: + * Supply an object containing menu items. When an item is selected, the function + * it references will be executed. For example: * ``` * var boolean = false; * var number = 50; @@ -7817,15 +8551,16 @@ declare class E { * // Actually display the menu * E.showMenu(mainmenu); * ``` - * The menu will stay onscreen and active until explicitly removed, - * which you can do by calling `E.showMenu()` without arguments. + * The menu will stay onscreen and active until explicitly removed, which you can + * do by calling `E.showMenu()` without arguments. * See http://www.espruino.com/graphical_menu for more detailed information. * * @param {any} menu - An object containing name->function mappings to to be used in a menu * @returns {any} A menu object with `draw`, `move` and `select` functions * @url http://www.espruino.com/Reference#l_E_showMenu */ - static showMenu(menu: any): any; + static showMenu(menu: Menu): MenuInstance; + static showMenu(): void; /** * A utility function for displaying a full screen message on the screen. @@ -7838,14 +8573,13 @@ declare class E { * @param {any} title - (optional) a title for the message * @url http://www.espruino.com/Reference#l_E_showMessage */ - static showMessage(message: any, title: any): any; + static showMessage(message: string, title?: string): void; /** - * Displays a full screen prompt on the screen, with the buttons - * requested (or `Yes` and `No` for defaults). - * When the button is pressed the promise is resolved with the - * requested values (for the `Yes` and `No` defaults, `true` and `false` - * are returned). + * Displays a full screen prompt on the screen, with the buttons requested (or + * `Yes` and `No` for defaults). + * When the button is pressed the promise is resolved with the requested values + * (for the `Yes` and `No` defaults, `true` and `false` are returned). * ``` * E.showPrompt("Do you like fish?").then(function(v) { * if (v) print("'Yes' chosen"); @@ -7873,7 +8607,8 @@ declare class E { * @returns {any} A promise that is resolved when 'Ok' is pressed * @url http://www.espruino.com/Reference#l_E_showPrompt */ - static showPrompt(message: any, options: any): any; + static showPrompt(message: string, options?: { title?: string, buttons?: { [key: string]: T } }): Promise; + static showPrompt(): void; /** * Displays a full screen prompt on the screen, with a single 'Ok' button. @@ -7894,10 +8629,11 @@ declare class E { * @returns {any} A promise that is resolved when 'Ok' is pressed * @url http://www.espruino.com/Reference#l_E_showAlert */ - static showAlert(message: any, options: any): any; + static showAlert(message?: string, options?: string): Promise; /** - * Called when a notification arrives on an Apple iOS device Bangle.js is connected to + * Called when a notification arrives on an Apple iOS device Bangle.js is connected + * to * ``` * { * event:"add", @@ -7923,7 +8659,8 @@ declare class E { static on(event: "ANCS", callback: (info: any) => void): void; /** - * Called when a media event arrives on an Apple iOS device Bangle.js is connected to + * Called when a media event arrives on an Apple iOS device Bangle.js is connected + * to * ``` * { * id : "artist"/"album"/"title"/"duration", @@ -7940,8 +8677,8 @@ declare class E { /** * Display a menu on the screen, and set up the buttons to navigate through it. - * Supply an object containing menu items. When an item is selected, the - * function it references will be executed. For example: + * Supply an object containing menu items. When an item is selected, the function + * it references will be executed. For example: * ``` * var boolean = false; * var number = 50; @@ -7973,20 +8710,25 @@ declare class E { * // Actually display the menu * E.showMenu(mainmenu); * ``` - * The menu will stay onscreen and active until explicitly removed, - * which you can do by calling `E.showMenu()` without arguments. + * The menu will stay onscreen and active until explicitly removed, which you can + * do by calling `E.showMenu()` without arguments. * See http://www.espruino.com/graphical_menu for more detailed information. * On Bangle.js there are a few additions over the standard `graphical_menu`: * * The options object can contain: - * * `back : function() { }` - add a 'back' button, with the function called when it is pressed - * * (Bangle.js 2) `scroll : int` - an integer specifying how much the initial menu should be scrolled by + * * `back : function() { }` - add a 'back' button, with the function called when + * it is pressed + * * (Bangle.js 2) `scroll : int` - an integer specifying how much the initial + * menu should be scrolled by * * The object returned by `E.showMenu` contains: - * * (Bangle.js 2) `scroller` - the object returned by `E.showScroller` - `scroller.scroll` returns the amount the menu is currently scrolled by + * * (Bangle.js 2) `scroller` - the object returned by `E.showScroller` - + * `scroller.scroll` returns the amount the menu is currently scrolled by * * In the object specified for editable numbers: - * * (Bangle.js 2) the `format` function is called with `format(value)` in the main menu, `format(value,1)` when in a scrollable list, or `format(value,2)` when in a popup window. - * You can also specify menu items as an array (rather than an Object). This can be useful - * if you have menu items with the same title, or you want to `push` menu items onto an - * array: + * * (Bangle.js 2) the `format` function is called with `format(value)` in the + * main menu, `format(value,1)` when in a scrollable list, or `format(value,2)` + * when in a popup window. + * You can also specify menu items as an array (rather than an Object). This can be + * useful if you have menu items with the same title, or you want to `push` menu + * items onto an array: * ``` * var menu = [ * { title:"Something", onchange:function() { print("selected"); } }, @@ -8001,7 +8743,8 @@ declare class E { * @returns {any} A menu object with `draw`, `move` and `select` functions * @url http://www.espruino.com/Reference#l_E_showMenu */ - static showMenu(menu: any): any; + static showMenu(menu: Menu): MenuInstance; + static showMenu(): void; /** * A utility function for displaying a full screen message on the screen. @@ -8021,14 +8764,13 @@ declare class E { * @param {any} options - (optional) a title for the message, or an object of options `{title:string, img:image_string}` * @url http://www.espruino.com/Reference#l_E_showMessage */ - static showMessage(message: any, options: any): any; + static showMessage(message: string, title?: string | { title?: string, img?: string }): void; /** - * Displays a full screen prompt on the screen, with the buttons - * requested (or `Yes` and `No` for defaults). - * When the button is pressed the promise is resolved with the - * requested values (for the `Yes` and `No` defaults, `true` and `false` - * are returned). + * Displays a full screen prompt on the screen, with the buttons requested (or + * `Yes` and `No` for defaults). + * When the button is pressed the promise is resolved with the requested values + * (for the `Yes` and `No` defaults, `true` and `false` are returned). * ``` * E.showPrompt("Do you like fish?").then(function(v) { * if (v) print("'Yes' chosen"); @@ -8064,11 +8806,12 @@ declare class E { * @returns {any} A promise that is resolved when 'Ok' is pressed * @url http://www.espruino.com/Reference#l_E_showPrompt */ - static showPrompt(message: any, options: any): any; + static showPrompt(message: string, options?: { title?: string, buttons?: { [key: string]: T } }): Promise; + static showPrompt(): void; /** - * Display a scrollable menu on the screen, and set up the buttons/touchscreen to navigate through it - * and select items. + * Display a scrollable menu on the screen, and set up the buttons/touchscreen to + * navigate through it and select items. * Supply an object containing: * ``` * { @@ -8099,27 +8842,28 @@ declare class E { * @returns {any} A menu object with `draw()` and `drawItem(itemNo)` functions * @url http://www.espruino.com/Reference#l_E_showScroller */ - static showScroller(options: any): any; + static showScroller(options?: { h: number, c: number, draw: (idx: number, rect: { x: number, y: number, w: number, h: number }) => void, select: (idx: number) => void, back?: () => void }): { draw: () => void, drawItem: (itemNo: number) => void }; + static showScroller(): void; /** * @url http://www.espruino.com/Reference#l_E_showMenu */ - static showMenu(): any; + static showMenu(): void; /** * @url http://www.espruino.com/Reference#l_E_showMenu */ - static showMenu(): any; + static showMenu(): void; /** * @url http://www.espruino.com/Reference#l_E_showPrompt */ - static showPrompt(): any; + static showPrompt(): void; /** * @url http://www.espruino.com/Reference#l_E_showScroller */ - static showScroller(): any; + static showScroller(): void; /** * Displays a full screen prompt on the screen, with a single 'Ok' button. @@ -8140,7 +8884,7 @@ declare class E { * @returns {any} A promise that is resolved when 'Ok' is pressed * @url http://www.espruino.com/Reference#l_E_showAlert */ - static showAlert(message: any, options: any): any; + static showAlert(message?: string, options?: string): Promise; /** * This event is called right after the board starts up, and has a similar effect @@ -8169,9 +8913,9 @@ declare class E { * console.log("Bye!"); * }); * ``` - * **NOTE:** This event is not called when the device is 'hard reset' - for - * example by removing power, hitting an actual reset button, or via - * a Watchdog timer reset. + * **NOTE:** This event is not called when the device is 'hard reset' - for example + * by removing power, hitting an actual reset button, or via a Watchdog timer + * reset. * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_E_kill @@ -8179,26 +8923,25 @@ declare class E { static on(event: "kill", callback: () => void): void; /** - * This event is called when an error is created by Espruino itself (rather - * than JS code) which changes the state of the error flags reported by - * `E.getErrorFlags()` + * This event is called when an error is created by Espruino itself (rather than JS + * code) which changes the state of the error flags reported by `E.getErrorFlags()` * This could be low memory, full buffers, UART overflow, etc. `E.getErrorFlags()` * has a full description of each type of error. - * This event will only be emitted when error flag is set. If the error - * flag was already set nothing will be emitted. To clear error flags - * so that you do get a callback each time a flag is set, call `E.getErrorFlags()`. + * This event will only be emitted when error flag is set. If the error flag was + * already set nothing will be emitted. To clear error flags so that you do get a + * callback each time a flag is set, call `E.getErrorFlags()`. * @param {string} event - The event to listen to. * @param {(errorFlags: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `errorFlags` An array of new error flags, as would be returned by `E.getErrorFlags()`. Error flags that were present before won't be reported. * @url http://www.espruino.com/Reference#l_E_errorFlag */ - static on(event: "errorFlag", callback: (errorFlags: any) => void): void; + static on(event: "errorFlag", callback: (errorFlags: ErrorFlag[]) => void): void; /** - * This event is called when a full touchscreen device on an Espruino - * is interacted with. - * **Note:** This event is not implemented on Bangle.js because - * it only has a two area touchscreen. + * This event is called when a full touchscreen device on an Espruino is interacted + * with. + * **Note:** This event is not implemented on Bangle.js because it only has a two + * area touchscreen. * To use the touchscreen to draw lines, you could do: * ``` * var last; @@ -8219,31 +8962,44 @@ declare class E { /** * Use the microcontroller's internal thermistor to work out the temperature. - * On Puck.js v2.0 this will use the on-board PCT2075TP temperature sensor, but on other devices it may not be desperately well calibrated. - * While this is implemented on Espruino boards, it may not be implemented on other devices. If so it'll return NaN. - * **Note:** This is not entirely accurate and varies by a few degrees from chip to chip. It measures the **die temperature**, so when connected to USB it could be reading 10 over degrees C above ambient temperature. When running from battery with `setDeepSleep(true)` it is much more accurate though. + * On Puck.js v2.0 this will use the on-board PCT2075TP temperature sensor, but on + * other devices it may not be desperately well calibrated. + * While this is implemented on Espruino boards, it may not be implemented on other + * devices. If so it'll return NaN. + * **Note:** This is not entirely accurate and varies by a few degrees from chip + * to chip. It measures the **die temperature**, so when connected to USB it could + * be reading 10 over degrees C above ambient temperature. When running from + * battery with `setDeepSleep(true)` it is much more accurate though. * @returns {number} The temperature in degrees C * @url http://www.espruino.com/Reference#l_E_getTemperature */ static getTemperature(): number; /** - * Check the internal voltage reference. To work out an actual voltage of an input pin, you can use `analogRead(pin)*E.getAnalogVRef()` - * **Note:** This value is calculated by reading the voltage on an internal voltage reference with the ADC. - * It will be slightly noisy, so if you need this for accurate measurements we'd recommend that you call - * this function several times and average the results. - * While this is implemented on Espruino boards, it may not be implemented on other devices. If so it'll return NaN. + * Check the internal voltage reference. To work out an actual voltage of an input + * pin, you can use `analogRead(pin)*E.getAnalogVRef()` + * **Note:** This value is calculated by reading the voltage on an internal + * voltage reference with the ADC. It will be slightly noisy, so if you need this + * for accurate measurements we'd recommend that you call this function several + * times and average the results. + * While this is implemented on Espruino boards, it may not be implemented on other + * devices. If so it'll return NaN. * @returns {number} The voltage (in Volts) that a reading of 1 from `analogRead` actually represents - usually around 3.3v * @url http://www.espruino.com/Reference#l_E_getAnalogVRef */ static getAnalogVRef(): number; /** - * ADVANCED: This is a great way to crash Espruino if you're not sure what you are doing - * Create a native function that executes the code at the given address. Eg. `E.nativeCall(0x08012345,'double (double,double)')(1.1, 2.2)` - * If you're executing a thumb function, you'll almost certainly need to set the bottom bit of the address to 1. - * Note it's not guaranteed that the call signature you provide can be used - there are limits on the number of arguments allowed. - * When supplying `data`, if it is a 'flat string' then it will be used directly, otherwise it'll be converted to a flat string and used. + * ADVANCED: This is a great way to crash Espruino if you're not sure what you are + * doing + * Create a native function that executes the code at the given address, e.g. + * `E.nativeCall(0x08012345,'double (double,double)')(1.1, 2.2)` + * If you're executing a thumb function, you'll almost certainly need to set the + * bottom bit of the address to 1. + * Note it's not guaranteed that the call signature you provide can be used - there + * are limits on the number of arguments allowed. + * When supplying `data`, if it is a 'flat string' then it will be used directly, + * otherwise it'll be converted to a flat string and used. * * @param {number} addr - The address in memory of the function (or offset in `data` if it was supplied * @param {any} sig - The signature of the call, `returnType (arg1,arg2,...)`. Allowed types are `void`,`bool`,`int`,`double`,`Pin`,`JsVar` @@ -8251,7 +9007,7 @@ declare class E { * @returns {any} The native function * @url http://www.espruino.com/Reference#l_E_nativeCall */ - static nativeCall(addr: number, sig: any, data: any): any; + static nativeCall(addr: number, sig: string, data?: string): any; /** * Clip a number to be between min and max (inclusive) @@ -8271,20 +9027,23 @@ declare class E { * @returns {number} The sum of the given buffer * @url http://www.espruino.com/Reference#l_E_sum */ - static sum(arr: any): number; + static sum(arr: string | number[] | ArrayBuffer): number; /** - * Work out the variance of the contents of the given Array, String or ArrayBuffer and return the result. This is equivalent to `v=0;for (i in arr) v+=Math.pow(mean-arr[i],2)` + * Work out the variance of the contents of the given Array, String or ArrayBuffer + * and return the result. This is equivalent to `v=0;for (i in arr) + * v+=Math.pow(mean-arr[i],2)` * * @param {any} arr - The array to work out the variance for * @param {number} mean - The mean value of the array * @returns {number} The variance of the given buffer * @url http://www.espruino.com/Reference#l_E_variance */ - static variance(arr: any, mean: number): number; + static variance(arr: string | number[] | ArrayBuffer, mean: number): number; /** - * Convolve arr1 with arr2. This is equivalent to `v=0;for (i in arr1) v+=arr1[i] * arr2[(i+offset) % arr2.length]` + * Convolve arr1 with arr2. This is equivalent to `v=0;for (i in arr1) v+=arr1[i] * + * arr2[(i+offset) % arr2.length]` * * @param {any} arr1 - An array to convolve * @param {any} arr2 - An array to convolve @@ -8292,28 +9051,32 @@ declare class E { * @returns {number} The variance of the given buffer * @url http://www.espruino.com/Reference#l_E_convolve */ - static convolve(arr1: any, arr2: any, offset: number): number; + static convolve(arr1: string | number[] | ArrayBuffer, arr2: string | number[] | ArrayBuffer, offset: number): number; /** - * Performs a Fast Fourier Transform (FFT) in 32 bit floats on the supplied data and writes it back into the - * original arrays. Note that if only one array is supplied, the data written back is the modulus of the complex - * result `sqrt(r*r+i*i)`. - * In order to perform the FFT, there has to be enough room on the stack to allocate two arrays of 32 bit - * floating point numbers - this will limit the maximum size of FFT possible to around 1024 items on - * most platforms. - * **Note:** on the Original Espruino board, FFTs are performed in 64bit arithmetic as there isn't - * space to include the 32 bit maths routines (2x more RAM is required). + * Performs a Fast Fourier Transform (FFT) in 32 bit floats on the supplied data + * and writes it back into the original arrays. Note that if only one array is + * supplied, the data written back is the modulus of the complex result + * `sqrt(r*r+i*i)`. + * In order to perform the FFT, there has to be enough room on the stack to + * allocate two arrays of 32 bit floating point numbers - this will limit the + * maximum size of FFT possible to around 1024 items on most platforms. + * **Note:** on the Original Espruino board, FFTs are performed in 64bit arithmetic + * as there isn't space to include the 32 bit maths routines (2x more RAM is + * required). * * @param {any} arrReal - An array of real values * @param {any} arrImage - An array of imaginary values (or if undefined, all values will be taken to be 0) * @param {boolean} inverse - Set this to true if you want an inverse FFT - otherwise leave as 0 * @url http://www.espruino.com/Reference#l_E_FFT */ - static FFT(arrReal: any, arrImage: any, inverse: boolean): any; + static FFT(arrReal: string | number[] | ArrayBuffer, arrImage?: string | number[] | ArrayBuffer, inverse?: boolean): any; /** - * Enable the watchdog timer. This will reset Espruino if it isn't able to return to the idle loop within the timeout. - * If `isAuto` is false, you must call `E.kickWatchdog()` yourself every so often or the chip will reset. + * Enable the watchdog timer. This will reset Espruino if it isn't able to return + * to the idle loop within the timeout. + * If `isAuto` is false, you must call `E.kickWatchdog()` yourself every so often + * or the chip will reset. * ``` * E.enableWatchdog(0.5); // automatic mode * while(1); // Espruino will reboot because it has not been idle for 0.5 sec @@ -8327,57 +9090,73 @@ declare class E { * // Espruino will now reset if everything_ok is false, * // or if the interval fails to be called * ``` - * **NOTE:** This is only implemented on STM32 and nRF5x devices (all official Espruino boards). + * **NOTE:** This is only implemented on STM32 and nRF5x devices (all official + * Espruino boards). * **NOTE:** On STM32 (Pico, WiFi, Original) with `setDeepSleep(1)` you need to - * explicitly wake Espruino up with an interval of less than the watchdog timeout or the watchdog will fire and - * the board will reboot. You can do this with `setInterval("", time_in_milliseconds)`. + * explicitly wake Espruino up with an interval of less than the watchdog timeout + * or the watchdog will fire and the board will reboot. You can do this with + * `setInterval("", time_in_milliseconds)`. * * @param {number} timeout - The timeout in seconds before a watchdog reset * @param {any} isAuto - If undefined or true, the watchdog is kicked automatically. If not, you must call `E.kickWatchdog()` yourself * @url http://www.espruino.com/Reference#l_E_enableWatchdog */ - static enableWatchdog(timeout: number, isAuto: any): any; + static enableWatchdog(timeout: number, isAuto?: boolean): void; /** * Kicks a Watchdog timer set up with `E.enableWatchdog(..., false)`. See * `E.enableWatchdog` for more information. - * **NOTE:** This is only implemented on STM32 and nRF5x devices (all official Espruino boards). + * **NOTE:** This is only implemented on STM32 and nRF5x devices (all official + * Espruino boards). * @url http://www.espruino.com/Reference#l_E_kickWatchdog */ - static kickWatchdog(): any; + static kickWatchdog(): void; /** * Get and reset the error flags. Returns an array that can contain: - * `'FIFO_FULL'`: The receive FIFO filled up and data was lost. This could be state transitions for setWatch, or received characters. - * `'BUFFER_FULL'`: A buffer for a stream filled up and characters were lost. This can happen to any stream - Serial,HTTP,etc. - * `'CALLBACK'`: A callback (`setWatch`, `setInterval`, `on('data',...)`) caused an error and so was removed. - * `'LOW_MEMORY'`: Memory is running low - Espruino had to run a garbage collection pass or remove some of the command history - * `'MEMORY'`: Espruino ran out of memory and was unable to allocate some data that it needed. - * `'UART_OVERFLOW'` : A UART received data but it was not read in time and was lost + * `'FIFO_FULL'`: The receive FIFO filled up and data was lost. This could be state + * transitions for setWatch, or received characters. + * `'BUFFER_FULL'`: A buffer for a stream filled up and characters were lost. This + * can happen to any stream - Serial,HTTP,etc. + * `'CALLBACK'`: A callback (`setWatch`, `setInterval`, `on('data',...)`) caused an + * error and so was removed. + * `'LOW_MEMORY'`: Memory is running low - Espruino had to run a garbage collection + * pass or remove some of the command history + * `'MEMORY'`: Espruino ran out of memory and was unable to allocate some data that + * it needed. + * `'UART_OVERFLOW'` : A UART received data but it was not read in time and was + * lost * @returns {any} An array of error flags * @url http://www.espruino.com/Reference#l_E_getErrorFlags */ - static getErrorFlags(): any; + static getErrorFlags(): ErrorFlag[] /** - * Get Espruino's interpreter flags that control the way it handles your JavaScript code. + * Get Espruino's interpreter flags that control the way it handles your JavaScript + * code. * * `deepSleep` - Allow deep sleep modes (also set by setDeepSleep) - * * `pretokenise` - When adding functions, pre-minify them and tokenise reserved words - * * `unsafeFlash` - Some platforms stop writes/erases to interpreter memory to stop you bricking the device accidentally - this removes that protection - * * `unsyncFiles` - When writing files, *don't* flush all data to the SD card after each command (the default is *to* flush). This is much faster, but can cause filesystem damage if power is lost without the filesystem unmounted. + * * `pretokenise` - When adding functions, pre-minify them and tokenise reserved + * words + * * `unsafeFlash` - Some platforms stop writes/erases to interpreter memory to + * stop you bricking the device accidentally - this removes that protection + * * `unsyncFiles` - When writing files, *don't* flush all data to the SD card + * after each command (the default is *to* flush). This is much faster, but can + * cause filesystem damage if power is lost without the filesystem unmounted. * @returns {any} An object containing flag names and their values * @url http://www.espruino.com/Reference#l_E_getFlags */ - static getFlags(): any; + static getFlags(): { [key in Flag]: boolean } /** - * Set the Espruino interpreter flags that control the way it handles your JavaScript code. - * Run `E.getFlags()` and check its description for a list of available flags and their values. + * Set the Espruino interpreter flags that control the way it handles your + * JavaScript code. + * Run `E.getFlags()` and check its description for a list of available flags and + * their values. * * @param {any} flags - An object containing flag names and boolean values. You need only specify the flags that you want to change. * @url http://www.espruino.com/Reference#l_E_setFlags */ - static setFlags(flags: any): any; + static setFlags(flags: { [key in Flag]?: boolean }): void /** * @@ -8390,44 +9169,50 @@ declare class E { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_E_pipe */ - static pipe(source: any, destination: any, options: any): any; + static pipe(source: any, destination: any, options?: { chunkSize?: number, end?: boolean, complete?: () => void }): void /** - * Create an ArrayBuffer from the given string. This is done via a reference, not a copy - so it is very fast and memory efficient. - * Note that this is an ArrayBuffer, not a Uint8Array. To get one of those, do: `new Uint8Array(E.toArrayBuffer('....'))`. + * Create an ArrayBuffer from the given string. This is done via a reference, not a + * copy - so it is very fast and memory efficient. + * Note that this is an ArrayBuffer, not a Uint8Array. To get one of those, do: + * `new Uint8Array(E.toArrayBuffer('....'))`. * * @param {any} str - The string to convert to an ArrayBuffer * @returns {any} An ArrayBuffer that uses the given string * @url http://www.espruino.com/Reference#l_E_toArrayBuffer */ - static toArrayBuffer(str: any): ArrayBufferView; + static toArrayBuffer(str: string): ArrayBuffer; /** - * Returns a 'flat' string representing the data in the arguments, or return `undefined` - * if a flat string cannot be created. - * This creates a string from the given arguments. If an argument is a String or an Array, - * each element is traversed and added as an 8 bit character. If it is anything else, it is - * converted to a character directly. + * Returns a 'flat' string representing the data in the arguments, or return + * `undefined` if a flat string cannot be created. + * This creates a string from the given arguments. If an argument is a String or an + * Array, each element is traversed and added as an 8 bit character. If it is + * anything else, it is converted to a character directly. * In the case where there's one argument which is an 8 bit typed array backed by a - * flat string of the same length, the backing string will be returned without doing - * a copy or other allocation. The same applies if there's a single argument which - * is itself a flat string. + * flat string of the same length, the backing string will be returned without + * doing a copy or other allocation. The same applies if there's a single argument + * which is itself a flat string. * * @param {any} args - The arguments to convert to a String * @returns {any} A String (or `undefined` if a Flat String cannot be created) * @url http://www.espruino.com/Reference#l_E_toString */ - static toString(...args: any[]): String; + static toString(...args: any[]): string | undefined; /** - * This creates a Uint8Array from the given arguments. These are handled as follows: + * This creates a Uint8Array from the given arguments. These are handled as + * follows: * * `Number` -> read as an integer, using the lowest 8 bits - * * `String` -> use each character's numeric value (eg. `String.charCodeAt(...)`) + * * `String` -> use each character's numeric value (e.g. + * `String.charCodeAt(...)`) * * `Array` -> Call itself on each element * * `ArrayBuffer` or Typed Array -> use the lowest 8 bits of each element * * `Object`: - * * `{data:..., count: int}` -> call itself `object.count` times, on `object.data` - * * `{callback : function}` -> call the given function, call itself on return value + * * `{data:..., count: int}` -> call itself `object.count` times, on + * `object.data` + * * `{callback : function}` -> call the given function, call itself on return + * value * For example: * ``` * E.toUint8Array([1,2,3]) @@ -8444,54 +9229,53 @@ declare class E { * @returns {any} A Uint8Array * @url http://www.espruino.com/Reference#l_E_toUint8Array */ - static toUint8Array(...args: any[]): Uint8Array; + static toUint8Array(...args: Uint8ArrayResolvable[]): Uint8Array; /** - * This performs the same basic function as `JSON.stringify`, - * however `JSON.stringify` adds extra characters to conform - * to the JSON spec which aren't required if outputting JS. - * `E.toJS` will also stringify JS functions, whereas - * `JSON.stringify` ignores them. + * This performs the same basic function as `JSON.stringify`, however + * `JSON.stringify` adds extra characters to conform to the JSON spec which aren't + * required if outputting JS. + * `E.toJS` will also stringify JS functions, whereas `JSON.stringify` ignores + * them. * For example: * * `JSON.stringify({a:1,b:2}) == '{"a":1,"b":2}'` * * `E.toJS({a:1,b:2}) == '{a:1,b:2}'` - * **Note:** Strings generated with `E.toJS` can't be - * reliably parsed by `JSON.parse` - however they are - * valid JS so will work with `eval` (but this has security - * implications if you don't trust the source of the string). - * On the desktop [JSON5 parsers](https://github.com/json5/json5) - * will parse the strings produced by `E.toJS` without trouble. + * **Note:** Strings generated with `E.toJS` can't be reliably parsed by + * `JSON.parse` - however they are valid JS so will work with `eval` (but this has + * security implications if you don't trust the source of the string). + * On the desktop [JSON5 parsers](https://github.com/json5/json5) will parse the + * strings produced by `E.toJS` without trouble. * * @param {any} arg - The JS variable to convert to a string * @returns {any} A String * @url http://www.espruino.com/Reference#l_E_toJS */ - static toJS(arg: any): String; + static toJS(arg: any): string; /** - * This creates and returns a special type of string, which actually references - * a specific memory address. It can be used in order to use sections of - * Flash memory directly in Espruino (for example to execute code straight - * from flash memory with `eval(E.memoryArea( ... ))`) - * **Note:** This is only tested on STM32-based platforms (Espruino Original - * and Espruino Pico) at the moment. + * This creates and returns a special type of string, which actually references a + * specific memory address. It can be used in order to use sections of Flash memory + * directly in Espruino (for example to execute code straight from flash memory + * with `eval(E.memoryArea( ... ))`) + * **Note:** This is only tested on STM32-based platforms (Espruino Original and + * Espruino Pico) at the moment. * * @param {number} addr - The address of the memory area * @param {number} len - The length (in bytes) of the memory area * @returns {any} A String * @url http://www.espruino.com/Reference#l_E_memoryArea */ - static memoryArea(addr: number, len: number): String; + static memoryArea(addr: number, len: number): string; /** * This writes JavaScript code into Espruino's flash memory, to be executed on - * startup. It differs from `save()` in that `save()` saves the whole state of - * the interpreter, whereas this just saves JS code that is executed at boot. + * startup. It differs from `save()` in that `save()` saves the whole state of the + * interpreter, whereas this just saves JS code that is executed at boot. * Code will be executed before `onInit()` and `E.on('init', ...)`. * If `alwaysExec` is `true`, the code will be executed even after a call to - * `reset()`. This is useful if you're making something that you want to - * program, but you want some code that is always built in (for instance - * setting up a display or keyboard). + * `reset()`. This is useful if you're making something that you want to program, + * but you want some code that is always built in (for instance setting up a + * display or keyboard). * To remove boot code that has been saved previously, use `E.setBootCode("")` * **Note:** this removes any code that was previously saved with `save()` * @@ -8499,11 +9283,11 @@ declare class E { * @param {boolean} alwaysExec - Whether to always execute the code (even after a reset) * @url http://www.espruino.com/Reference#l_E_setBootCode */ - static setBootCode(code: any, alwaysExec: boolean): any; + static setBootCode(code: string, alwaysExec?: boolean): void; /** - * This sets the clock frequency of Espruino's processor. It will return `0` if - * it is unimplemented or the clock speed cannot be changed. + * This sets the clock frequency of Espruino's processor. It will return `0` if it + * is unimplemented or the clock speed cannot be changed. * **Note:** On pretty much all boards, UART, SPI, I2C, PWM, etc will change * frequency and will need setting up again in order to work. * ### STM32F4 @@ -8515,13 +9299,13 @@ declare class E { * * `latency` - flash latency from 0..15 * * `PCLK1` - Peripheral clock 1 divisor (default: 2) * * `PCLK2` - Peripheral clock 2 divisor (default: 4) - * The Pico's default is `{M:8, N:336, P:4, Q:7, PCLK1:2, PCLK2:4}`, use - * `{M:8, N:336, P:8, Q:7, PCLK:1, PCLK2:2}` to halve the system clock speed - * while keeping the peripherals running at the same speed (omitting PCLK1/2 - * will lead to the peripherals changing speed too). - * On STM32F4 boards (eg. Espruino Pico), the USB clock needs to be kept at 48Mhz - * or USB will fail to work. You'll also experience USB instability if the processor - * clock falls much below 48Mhz. + * The Pico's default is `{M:8, N:336, P:4, Q:7, PCLK1:2, PCLK2:4}`, use `{M:8, + * N:336, P:8, Q:7, PCLK:1, PCLK2:2}` to halve the system clock speed while keeping + * the peripherals running at the same speed (omitting PCLK1/2 will lead to the + * peripherals changing speed too). + * On STM32F4 boards (e.g. Espruino Pico), the USB clock needs to be kept at 48Mhz + * or USB will fail to work. You'll also experience USB instability if the + * processor clock falls much below 48Mhz. * ### ESP8266 * Just specify an integer value, either 80 or 160 (for 80 or 160Mhz) * @@ -8529,24 +9313,23 @@ declare class E { * @returns {number} The actual frequency the clock has been set to * @url http://www.espruino.com/Reference#l_E_setClock */ - static setClock(options: any): number; + static setClock(options: number | { M: number, N: number, P: number, Q: number, latency?: number, PCLK?: number, PCLK2?: number }): number; /** - * Changes the device that the JS console (otherwise known as the REPL) - * is attached to. If the console is on a device, that - * device can be used for programming Espruino. + * Changes the device that the JS console (otherwise known as the REPL) is attached + * to. If the console is on a device, that device can be used for programming + * Espruino. * Rather than calling `Serial.setConsole` you can call * `E.setConsole("DeviceName")`. - * This is particularly useful if you just want to - * remove the console. `E.setConsole(null)` will - * make the console completely inaccessible. - * `device` may be `"Serial1"`,`"USB"`,`"Bluetooth"`,`"Telnet"`,`"Terminal"`, - * any other *hardware* `Serial` device, or `null` to disable the console completely. + * This is particularly useful if you just want to remove the console. + * `E.setConsole(null)` will make the console completely inaccessible. + * `device` may be `"Serial1"`,`"USB"`,`"Bluetooth"`,`"Telnet"`,`"Terminal"`, any + * other *hardware* `Serial` device, or `null` to disable the console completely. * `options` is of the form: * ``` * { * force : bool // default false, force the console onto this device so it does not move - * // if false, changes in connection state (eg USB/Bluetooth) can move + * // if false, changes in connection state (e.g. USB/Bluetooth) can move * // the console automatically. * } * ``` @@ -8555,19 +9338,20 @@ declare class E { * @param {any} options - (optional) object of options, see below * @url http://www.espruino.com/Reference#l_E_setConsole */ - static setConsole(device: any, options: any): any; + static setConsole(device: "Serial1" | "USB" | "Bluetooth" | "Telnet" | "Terminal" | Serial | null, options?: { force?: boolean }): void; /** * Returns the current console device - see `E.setConsole` for more information. * @returns {any} The current console device as a string, or just `null` if the console is null * @url http://www.espruino.com/Reference#l_E_getConsole */ - static getConsole(): any; + static getConsole(): string | null /** * Reverse the 8 bits in a byte, swapping MSB and LSB. * For example, `E.reverseByte(0b10010000) == 0b00001001`. - * Note that you can reverse all the bytes in an array with: `arr = arr.map(E.reverseByte)` + * Note that you can reverse all the bytes in an array with: `arr = + * arr.map(E.reverseByte)` * * @param {number} x - A byte value to reverse the bits of * @returns {number} The byte with reversed bits @@ -8579,51 +9363,52 @@ declare class E { * Output the current list of Utility Timer Tasks - for debugging only * @url http://www.espruino.com/Reference#l_E_dumpTimers */ - static dumpTimers(): any; + static dumpTimers(): void; /** - * Dump any locked variables that aren't referenced from `global` - for debugging memory leaks only. + * Dump any locked variables that aren't referenced from `global` - for debugging + * memory leaks only. * @url http://www.espruino.com/Reference#l_E_dumpLockedVars */ - static dumpLockedVars(): any; + static dumpLockedVars(): void; /** - * Dump any locked variables that aren't referenced from `global` - for debugging memory leaks only. + * Dump any locked variables that aren't referenced from `global` - for debugging + * memory leaks only. * @url http://www.espruino.com/Reference#l_E_dumpFreeList */ - static dumpFreeList(): any; + static dumpFreeList(): void; /** * Show fragmentation. * * ` ` is free space * * `#` is a normal variable - * * `L` is a locked variable (address used, cannopt be moved) + * * `L` is a locked variable (address used, cannot be moved) * * `=` represents data in a Flat String (must be contiguous) * @url http://www.espruino.com/Reference#l_E_dumpFragmentation */ - static dumpFragmentation(): any; + static dumpFragmentation(): void; /** - * Dumps a comma-separated list of all allocated variables - * along with the variables they link to. Can be used - * to visualise where memory is used. + * Dumps a comma-separated list of all allocated variables along with the variables + * they link to. Can be used to visualise where memory is used. * @url http://www.espruino.com/Reference#l_E_dumpVariables */ - static dumpVariables(): any; + static dumpVariables(): void; /** * BETA: defragment memory! * @url http://www.espruino.com/Reference#l_E_defrag */ - static defrag(): any; + static defrag(): void; /** * Return the number of variable blocks used by the supplied variable. This is - * useful if you're running out of memory and you want to be able to see what - * is taking up most of the available space. - * If `depth>0` and the variable can be recursed into, an array listing all property - * names (including internal Espruino names) and their sizes is returned. If - * `depth>1` there is also a `more` field that inspects the objects's children's + * useful if you're running out of memory and you want to be able to see what is + * taking up most of the available space. + * If `depth>0` and the variable can be recursed into, an array listing all + * property names (including internal Espruino names) and their sizes is returned. + * If `depth>1` there is also a `more` field that inspects the objects' children's * children. * For instance `E.getSizeOf(function(a,b) { })` returns `5`. * But `E.getSizeOf(function(a,b) { }, 1)` returns: @@ -8640,8 +9425,8 @@ declare class E { * "size": 2 } * ] * ``` - * In this case setting depth to `2` will make no difference as there are - * no more children to traverse. + * In this case setting depth to `2` will make no difference as there are no more + * children to traverse. * See http://www.espruino.com/Internals for more information * * @param {any} v - A variable to get the size of @@ -8649,15 +9434,15 @@ declare class E { * @returns {any} Information about the variable size - see below * @url http://www.espruino.com/Reference#l_E_getSizeOf */ - static getSizeOf(v: any, depth: number): any; + static getSizeOf(v: any, depth?: 0): number; + static getSizeOf(v: any, depth: number): VariableSizeInformation; /** - * Return the address in memory of the given variable. This can then - * be used with `peek` and `poke` functions. However, changing data in - * JS variables directly (flatAddress=false) will most likely result in a crash. - * This functions exists to allow embedded targets to set up - * peripherals such as DMA so that they write directly to - * JS variables. + * Return the address in memory of the given variable. This can then be used with + * `peek` and `poke` functions. However, changing data in JS variables directly + * (flatAddress=false) will most likely result in a crash. + * This functions exists to allow embedded targets to set up peripherals such as + * DMA so that they write directly to JS variables. * See http://www.espruino.com/Internals for more information * * @param {any} v - A variable to get the address of @@ -8668,8 +9453,8 @@ declare class E { static getAddressOf(v: any, flatAddress: boolean): number; /** - * Take each element of the `from` array, look it up in `map` (or call `map(value,index)` - * if it is a function), and write it into the corresponding + * Take each element of the `from` array, look it up in `map` (or call + * `map(value,index)` if it is a function), and write it into the corresponding * element in the `to` array. * You can use an array to map: * ``` @@ -8705,7 +9490,7 @@ declare class E { * @param {number} bits - If specified, the number of bits per element (MSB first) - otherwise use a 1:1 mapping. If negative, use LSB first. * @url http://www.espruino.com/Reference#l_E_mapInPlace */ - static mapInPlace(from: any, to: any, map: any, bits: number): any; + static mapInPlace(from: ArrayBuffer, to: ArrayBuffer, map?: number[] | ((value: number, index: number) => number) | undefined, bits?: number): void; /** * Search in an Object, Array, or Function @@ -8716,14 +9501,16 @@ declare class E { * @returns {any} The value in the Object matching 'needle', or if `returnKey==true` the key's name - or undefined * @url http://www.espruino.com/Reference#l_E_lookupNoCase */ - static lookupNoCase(haystack: any, needle: any, returnKey: boolean): any; + static lookupNoCase(haystack: any[] | object | Function, needle: string, returnKey?: false): any; + static lookupNoCase(haystack: any[] | object | Function, needle: T, returnKey: true): T | undefined; /** - * Get the current interpreter state in a text form such that it can be copied to a new device + * Get the current interpreter state in a text form such that it can be copied to a + * new device * @returns {any} A String * @url http://www.espruino.com/Reference#l_E_dumpStr */ - static dumpStr(): String; + static dumpStr(): string; /** * Set the seed for the random number generator used by `Math.random()`. @@ -8731,21 +9518,20 @@ declare class E { * @param {number} v - The 32 bit integer seed to use for the random number generator * @url http://www.espruino.com/Reference#l_E_srand */ - static srand(v: number): any; + static srand(v: number): void; /** - * Unlike 'Math.random()' which uses a pseudo-random number generator, this - * method reads from the internal voltage reference several times, xoring and - * rotating to try and make a relatively random value from the noise in the - * signal. + * Unlike 'Math.random()' which uses a pseudo-random number generator, this method + * reads from the internal voltage reference several times, XOR-ing and rotating to + * try and make a relatively random value from the noise in the signal. * @returns {number} A random number * @url http://www.espruino.com/Reference#l_E_hwRand */ static hwRand(): number; /** - * Perform a standard 32 bit CRC (Cyclic redundancy check) on the supplied data (one byte at a time) - * and return the result as an unsigned integer. + * Perform a standard 32 bit CRC (Cyclic redundancy check) on the supplied data + * (one byte at a time) and return the result as an unsigned integer. * * @param {any} data - Iterable data to perform CRC32 on (each element treated as a byte) * @returns {any} The CRC of the supplied data @@ -8754,11 +9540,13 @@ declare class E { static CRC32(data: any): any; /** - * Convert hue, saturation and brightness to red, green and blue (packed into an integer if `asArray==false` or an array if `asArray==true`). - * This replaces `Graphics.setColorHSB` and `Graphics.setBgColorHSB`. On devices with 24 bit colour it can - * be used as: `Graphics.setColor(E.HSBtoRGB(h, s, b))` - * You can quickly set RGB items in an Array or Typed Array using `array.set(E.HSBtoRGB(h, s, b,true), offset)`, - * which can be useful with arrays used with `require("neopixel").write`. + * Convert hue, saturation and brightness to red, green and blue (packed into an + * integer if `asArray==false` or an array if `asArray==true`). + * This replaces `Graphics.setColorHSB` and `Graphics.setBgColorHSB`. On devices + * with 24 bit colour it can be used as: `Graphics.setColor(E.HSBtoRGB(h, s, b))` + * You can quickly set RGB items in an Array or Typed Array using + * `array.set(E.HSBtoRGB(h, s, b,true), offset)`, which can be useful with arrays + * used with `require("neopixel").write`. * * @param {number} hue - The hue, as a value between 0 and 1 * @param {number} sat - The saturation, as a value between 0 and 1 @@ -8767,76 +9555,95 @@ declare class E { * @returns {any} A 24 bit number containing bytes representing red, green, and blue `0xBBGGRR`. Or if `asArray` is true, an array `[R,G,B]` * @url http://www.espruino.com/Reference#l_E_HSBtoRGB */ - static HSBtoRGB(hue: number, sat: number, bri: number, asArray: boolean): any; + static HSBtoRGB(hue: number, sat: number, bri: number, asArray?: false): number; + static HSBtoRGB(hue: number, sat: number, bri: number, asArray: true): [number, number, number]; /** - * Set a password on the console (REPL). When powered on, Espruino will - * then demand a password before the console can be used. If you want to - * lock the console immediately after this you can call `E.lockConsole()` + * Set a password on the console (REPL). When powered on, Espruino will then demand + * a password before the console can be used. If you want to lock the console + * immediately after this you can call `E.lockConsole()` * To remove the password, call this function with no arguments. * **Note:** There is no protection against multiple password attempts, so someone * could conceivably try every password in a dictionary. - * **Note:** This password is stored in memory in plain text. If someone is able - * to execute arbitrary JavaScript code on the device (eg, you use `eval` on input + * **Note:** This password is stored in memory in plain text. If someone is able to + * execute arbitrary JavaScript code on the device (e.g., you use `eval` on input * from unknown sources) or read the device's firmware then they may be able to * obtain it. * * @param {any} password - The password - max 20 chars * @url http://www.espruino.com/Reference#l_E_setPassword */ - static setPassword(password: any): any; + static setPassword(password: string): void; /** - * If a password has been set with `E.setPassword()`, this will lock the console - * so the password needs to be entered to unlock it. + * If a password has been set with `E.setPassword()`, this will lock the console so + * the password needs to be entered to unlock it. * @url http://www.espruino.com/Reference#l_E_lockConsole */ - static lockConsole(): any; + static lockConsole(): void; /** * Set the time zone to be used with `Date` objects. * For example `E.setTimeZone(1)` will be GMT+0100 - * Note that `E.setTimeZone()` will have no effect when daylight savings time rules have been set with `E.setDST()`. The - * timezone value will be stored, but never used so long as DST settings are in effect. + * Note that `E.setTimeZone()` will have no effect when daylight savings time rules + * have been set with `E.setDST()`. The timezone value will be stored, but never + * used so long as DST settings are in effect. * Time can be set with `setTime`. * * @param {number} zone - The time zone in hours * @url http://www.espruino.com/Reference#l_E_setTimeZone */ - static setTimeZone(zone: number): any; + static setTimeZone(zone: number): void; /** * Set the daylight savings time parameters to be used with `Date` objects. * The parameters are - * - dstOffset: The number of minutes daylight savings time adds to the clock (usually 60) - set to 0 to disable DST - * - timezone: The time zone, in minutes, when DST is not in effect - positive east of Greenwich - * - startDowNumber: The index of the day-of-week in the month when DST starts - 0 for first, 1 for second, 2 for third, 3 for fourth and 4 for last - * - startDow: The day-of-week for the DST start calculation - 0 for Sunday, 6 for Saturday - * - startMonth: The number of the month that DST starts - 0 for January, 11 for December - * - startDayOffset: The number of days between the selected day-of-week and the actual day that DST starts - usually 0 + * - dstOffset: The number of minutes daylight savings time adds to the clock + * (usually 60) - set to 0 to disable DST + * - timezone: The time zone, in minutes, when DST is not in effect - positive east + * of Greenwich + * - startDowNumber: The index of the day-of-week in the month when DST starts - 0 + * for first, 1 for second, 2 for third, 3 for fourth and 4 for last + * - startDow: The day-of-week for the DST start calculation - 0 for Sunday, 6 for + * Saturday + * - startMonth: The number of the month that DST starts - 0 for January, 11 for + * December + * - startDayOffset: The number of days between the selected day-of-week and the + * actual day that DST starts - usually 0 * - startTimeOfDay: The number of minutes elapsed in the day before DST starts - * - endDowNumber: The index of the day-of-week in the month when DST ends - 0 for first, 1 for second, 2 for third, 3 for fourth and 4 for last - * - endDow: The day-of-week for the DST end calculation - 0 for Sunday, 6 for Saturday - * - endMonth: The number of the month that DST ends - 0 for January, 11 for December - * - endDayOffset: The number of days between the selected day-of-week and the actual day that DST ends - usually 0 + * - endDowNumber: The index of the day-of-week in the month when DST ends - 0 for + * first, 1 for second, 2 for third, 3 for fourth and 4 for last + * - endDow: The day-of-week for the DST end calculation - 0 for Sunday, 6 for + * Saturday + * - endMonth: The number of the month that DST ends - 0 for January, 11 for + * December + * - endDayOffset: The number of days between the selected day-of-week and the + * actual day that DST ends - usually 0 * - endTimeOfDay: The number of minutes elapsed in the day before DST ends - * To determine what the `dowNumber, dow, month, dayOffset, timeOfDay` parameters should be, start with a sentence of the form - * "DST starts on the last Sunday of March (plus 0 days) at 03:00". Since it's the last Sunday, we have startDowNumber = 4, and since - * it's Sunday, we have startDow = 0. That it is March gives us startMonth = 2, and that the offset is zero days, we have + * To determine what the `dowNumber, dow, month, dayOffset, timeOfDay` parameters + * should be, start with a sentence of the form "DST starts on the last Sunday of + * March (plus 0 days) at 03:00". Since it's the last Sunday, we have + * startDowNumber = 4, and since it's Sunday, we have startDow = 0. That it is + * March gives us startMonth = 2, and that the offset is zero days, we have * startDayOffset = 0. The time that DST starts gives us startTimeOfDay = 3*60. - * "DST ends on the Friday before the second Sunday in November at 02:00" would give us endDowNumber=1, endDow=0, endMonth=10, endDayOffset=-2 and endTimeOfDay=120. - * Using Ukraine as an example, we have a time which is 2 hours ahead of GMT in winter (EET) and 3 hours in summer (EEST). DST starts at 03:00 EET on the last Sunday in March, - * and ends at 04:00 EEST on the last Sunday in October. So someone in Ukraine might call `E.setDST(60,120,4,0,2,0,180,4,0,9,0,240);` - * Note that when DST parameters are set (i.e. when `dstOffset` is not zero), `E.setTimeZone()` has no effect. + * "DST ends on the Friday before the second Sunday in November at 02:00" would + * give us endDowNumber=1, endDow=0, endMonth=10, endDayOffset=-2 and + * endTimeOfDay=120. + * Using Ukraine as an example, we have a time which is 2 hours ahead of GMT in + * winter (EET) and 3 hours in summer (EEST). DST starts at 03:00 EET on the last + * Sunday in March, and ends at 04:00 EEST on the last Sunday in October. So + * someone in Ukraine might call `E.setDST(60,120,4,0,2,0,180,4,0,9,0,240);` + * Note that when DST parameters are set (i.e. when `dstOffset` is not zero), + * `E.setTimeZone()` has no effect. * * @param {any} params - An array containing the settings for DST * @url http://www.espruino.com/Reference#l_E_setDST */ - static setDST(...params: any[]): any; + static setDST(dstOffset: number, timezone: number, startDowNumber: number, startDow: number, startMonth: number, startDayOffset: number, startTimeOfDay: number, endDowNumber: number, endDow: number, endMonth: number, endDayOffset: number, endTimeOfDay: number): void /** - * Create an object where every field accesses a specific 32 bit address in the microcontroller's memory. This - * is perfect for accessing on-chip peripherals. + * Create an object where every field accesses a specific 32 bit address in the + * microcontroller's memory. This is perfect for accessing on-chip peripherals. * ``` * // for NRF52 based chips * var GPIO = E.memoryMap(0x50000000,{OUT:0x504, OUTSET:0x508, OUTCLR:0x50C, IN:0x510, DIR:0x514, DIRSET:0x518, DIRCLR:0x51C}); @@ -8849,53 +9656,53 @@ declare class E { * @returns {any} An object where each field is memory-mapped to a register. * @url http://www.espruino.com/Reference#l_E_memoryMap */ - static memoryMap(baseAddress: any, registers: any): any; + static memoryMap(baseAddress: number, registers: { [key in T]: number }): { [key in T]: number }; /** * Provide assembly to Espruino. - * **This function is not part of Espruino**. Instead, it is detected - * by the Espruino IDE (or command-line tools) at upload time and is - * replaced with machine code and an `E.nativeCall` call. - * See [the documentation on the Assembler](http://www.espruino.com/Assembler) for more information. + * **This function is not part of Espruino**. Instead, it is detected by the + * Espruino IDE (or command-line tools) at upload time and is replaced with machine + * code and an `E.nativeCall` call. + * See [the documentation on the Assembler](http://www.espruino.com/Assembler) for + * more information. * - * @param {any} callspec - The arguments this assembly takes - eg `void(int)` + * @param {any} callspec - The arguments this assembly takes - e.g. `void(int)` * @param {any} assemblycode - One of more strings of assembler code * @url http://www.espruino.com/Reference#l_E_asm */ - static asm(callspec: any, ...assemblycode: any[]): any; + static asm(callspec: string, ...assemblycode: string[]): any; /** * Provides the ability to write C code inside your JavaScript file. - * **This function is not part of Espruino**. Instead, it is detected - * by the Espruino IDE (or command-line tools) at upload time, is sent - * to our web service to be compiled, and is replaced with machine code - * and an `E.nativeCall` call. - * See [the documentation on Inline C](http://www.espruino.com/InlineC) for more information and examples. + * **This function is not part of Espruino**. Instead, it is detected by the + * Espruino IDE (or command-line tools) at upload time, is sent to our web service + * to be compiled, and is replaced with machine code and an `E.nativeCall` call. + * See [the documentation on Inline C](http://www.espruino.com/InlineC) for more + * information and examples. * * @param {any} code - A Templated string of C code * @url http://www.espruino.com/Reference#l_E_compiledC */ - static compiledC(code: any): any; + static compiledC(code: string): any; /** - * Forces a hard reboot of the microcontroller - as close as possible - * to if the reset pin had been toggled. - * **Note:** This is different to `reset()`, which performs a software - * reset of Espruino (resetting the interpreter and pin states, but not - * all the hardware) + * Forces a hard reboot of the microcontroller - as close as possible to if the + * reset pin had been toggled. + * **Note:** This is different to `reset()`, which performs a software reset of + * Espruino (resetting the interpreter and pin states, but not all the hardware) * @url http://www.espruino.com/Reference#l_E_reboot */ - static reboot(): any; + static reboot(): void; /** - * USB HID will only take effect next time you unplug and re-plug your Espruino. If you're - * disconnecting it from power you'll have to make sure you have `save()`d after calling - * this function. + * USB HID will only take effect next time you unplug and re-plug your Espruino. If + * you're disconnecting it from power you'll have to make sure you have `save()`d + * after calling this function. * * @param {any} opts - An object containing at least reportDescriptor, an array representing the report descriptor. Pass undefined to disable HID. * @url http://www.espruino.com/Reference#l_E_setUSBHID */ - static setUSBHID(opts: any): any; + static setUSBHID(opts?: { reportDescriptor: any[] }): void; /** * @@ -8903,36 +9710,39 @@ declare class E { * @returns {boolean} 1 on success, 0 on failure * @url http://www.espruino.com/Reference#l_E_sendUSBHID */ - static sendUSBHID(data: any): boolean; + static sendUSBHID(data: string | ArrayBuffer | number[]): boolean; /** - * In devices that come with batteries, this function returns - * the battery charge percentage as an integer between 0 and 100. - * **Note:** this is an estimation only, based on battery voltage. - * The temperature of the battery (as well as the load being drawn - * from it at the time `E.getBattery` is called) will affect the - * readings. + * In devices that come with batteries, this function returns the battery charge + * percentage as an integer between 0 and 100. + * **Note:** this is an estimation only, based on battery voltage. The temperature + * of the battery (as well as the load being drawn from it at the time + * `E.getBattery` is called) will affect the readings. * @returns {number} A percentage between 0 and 100 * @url http://www.espruino.com/Reference#l_E_getBattery */ static getBattery(): number; /** - * Sets the RTC's prescaler's maximum value. This is the counter that counts up on each oscillation of the low - * speed oscillator. When the prescaler counts to the value supplied, one second is deemed to have passed. - * By default this is set to the oscillator's average speed as specified in the datasheet, and usually that is - * fine. However on early [Espruino Pico](/Pico) boards the STM32F4's internal oscillator could vary by as - * much as 15% from the value in the datasheet. In that case you may want to alter this value to reflect the - * true RTC speed for more accurate timekeeping. - * To change the RTC's prescaler value to a computed value based on comparing against the high speed oscillator, - * just run the following command, making sure it's done a few seconds after the board starts up: + * Sets the RTC's prescaler's maximum value. This is the counter that counts up on + * each oscillation of the low speed oscillator. When the prescaler counts to the + * value supplied, one second is deemed to have passed. + * By default this is set to the oscillator's average speed as specified in the + * datasheet, and usually that is fine. However on early [Espruino Pico](/Pico) + * boards the STM32F4's internal oscillator could vary by as much as 15% from the + * value in the datasheet. In that case you may want to alter this value to reflect + * the true RTC speed for more accurate timekeeping. + * To change the RTC's prescaler value to a computed value based on comparing + * against the high speed oscillator, just run the following command, making sure + * it's done a few seconds after the board starts up: * ``` * E.setRTCPrescaler(E.getRTCPrescaler(true)); * ``` - * When changing the RTC prescaler, the RTC 'follower' counters are reset and it can take a second or two before - * readings from getTime are stable again. - * To test, you can connect an input pin to a known frequency square wave and then use `setWatch`. If you don't - * have a frequency source handy, you can check against the high speed oscillator: + * When changing the RTC prescaler, the RTC 'follower' counters are reset and it + * can take a second or two before readings from getTime are stable again. + * To test, you can connect an input pin to a known frequency square wave and then + * use `setWatch`. If you don't have a frequency source handy, you can check + * against the high speed oscillator: * ``` * // connect pin B3 to B4 * analogWrite(B3, 0.5, {freq:0.5}); @@ -8940,18 +9750,20 @@ declare class E { * print(e.time - e.lastTime); * }, B4, {repeat:true}); * ``` - * **Note:** This is only used on official Espruino boards containing an STM32 microcontroller. Other boards - * (even those using an STM32) don't use the RTC and so this has no effect. + * **Note:** This is only used on official Espruino boards containing an STM32 + * microcontroller. Other boards (even those using an STM32) don't use the RTC and + * so this has no effect. * * @param {number} prescaler - The amount of counts for one second of the RTC - this is a 15 bit integer value (0..32767) * @url http://www.espruino.com/Reference#l_E_setRTCPrescaler */ - static setRTCPrescaler(prescaler: number): any; + static setRTCPrescaler(prescaler: number): void; /** * Gets the RTC's current prescaler value if `calibrate` is undefined or false. - * If `calibrate` is true, the low speed oscillator's speed is calibrated against the high speed - * oscillator (usually +/- 20 ppm) and a suggested value to be fed into `E.setRTCPrescaler(...)` is returned. + * If `calibrate` is true, the low speed oscillator's speed is calibrated against + * the high speed oscillator (usually +/- 20 ppm) and a suggested value to be fed + * into `E.setRTCPrescaler(...)` is returned. * See `E.setRTCPrescaler` for more information. * * @param {boolean} calibrate - If `false`, the current value. If `true`, the calculated 'correct' value @@ -8983,18 +9795,23 @@ declare class E { * @returns {any} A string containing all UTF8 sequences flattened to 8 bits * @url http://www.espruino.com/Reference#l_E_decodeUTF8 */ - static decodeUTF8(str: any, lookup: any, replaceFn: any): any; + static decodeUTF8(str: string, lookup: string[], replaceFn: string | ((charCode: number) => string)): string; + + } interface consoleConstructor { /** * Print the supplied string(s) to the console - * **Note:** If you're connected to a computer (not a wall adaptor) via USB but **you are not running a terminal app** then when you print data Espruino may pause execution and wait until the computer requests the data it is trying to print. + * **Note:** If you're connected to a computer (not a wall adaptor) via USB but + * **you are not running a terminal app** then when you print data Espruino may + * pause execution and wait until the computer requests the data it is trying to + * print. * * @param {any} text - One or more arguments to print * @url http://www.espruino.com/Reference#l_console_log */ - log(...text: any[]): any; + log(...text: any[]): void; } interface console { @@ -9016,7 +9833,7 @@ interface ErrorConstructor { * @returns {any} An Error object * @url http://www.espruino.com/Reference#l_Error_Error */ - new(message: any): any; + new(message?: string): Error; } interface Error { @@ -9024,7 +9841,7 @@ interface Error { * @returns {any} A String * @url http://www.espruino.com/Reference#l_Error_toString */ - toString(): any; + toString(): string; } /** @@ -9042,7 +9859,7 @@ interface SyntaxErrorConstructor { * @returns {any} A SyntaxError object * @url http://www.espruino.com/Reference#l_SyntaxError_SyntaxError */ - new(message: any): any; + new(message?: string): SyntaxError; } interface SyntaxError { @@ -9050,7 +9867,7 @@ interface SyntaxError { * @returns {any} A String * @url http://www.espruino.com/Reference#l_SyntaxError_toString */ - toString(): any; + toString(): string; } /** @@ -9068,7 +9885,7 @@ interface TypeErrorConstructor { * @returns {any} A TypeError object * @url http://www.espruino.com/Reference#l_TypeError_TypeError */ - new(message: any): any; + new(message?: string): TypeError; } interface TypeError { @@ -9076,7 +9893,7 @@ interface TypeError { * @returns {any} A String * @url http://www.espruino.com/Reference#l_TypeError_toString */ - toString(): any; + toString(): string; } /** @@ -9098,11 +9915,13 @@ declare class InternalError { * @returns {any} An InternalError object * @url http://www.espruino.com/Reference#l_InternalError_InternalError */ - static new(message: any): any;/** + static new(message?: string): InternalError; + + /** * @returns {any} A String * @url http://www.espruino.com/Reference#l_InternalError_toString */ - toString(): any; + toString(): string; } interface ReferenceErrorConstructor { @@ -9114,7 +9933,7 @@ interface ReferenceErrorConstructor { * @returns {any} A ReferenceError object * @url http://www.espruino.com/Reference#l_ReferenceError_ReferenceError */ - new(message: any): any; + new(message?: string): ReferenceError; } interface ReferenceError { @@ -9122,22 +9941,24 @@ interface ReferenceError { * @returns {any} A String * @url http://www.espruino.com/Reference#l_ReferenceError_toString */ - toString(): any; + toString(): string; } /** - * The base class for reference errors - where a variable - * which doesn't exist has been accessed. + * The base class for reference errors - where a variable which doesn't exist has + * been accessed. * @url http://www.espruino.com/Reference#ReferenceError */ declare const ReferenceError: ReferenceErrorConstructor interface JSONConstructor { /** - * Convert the given object into a JSON string which can subsequently be parsed with JSON.parse or eval. + * Convert the given object into a JSON string which can subsequently be parsed + * with JSON.parse or eval. * **Note:** This differs from JavaScript's standard `JSON.stringify` in that: * * The `replacer` argument is ignored - * * Typed arrays like `new Uint8Array(5)` will be dumped as if they were arrays, not as if they were objects (since it is more compact) + * * Typed arrays like `new Uint8Array(5)` will be dumped as if they were arrays, + * not as if they were objects (since it is more compact) * * @param {any} data - The data to be converted to a JSON string * @param {any} replacer - This value is ignored @@ -9149,7 +9970,8 @@ interface JSONConstructor { /** * Parse the given JSON string into a JavaScript object - * NOTE: This implementation uses eval() internally, and as such it is unsafe as it can allow arbitrary JS commands to be executed. + * NOTE: This implementation uses eval() internally, and as such it is unsafe as it + * can allow arbitrary JS commands to be executed. * * @param {any} string - A JSON string * @returns {any} The JavaScript object created by parsing the data string @@ -9183,7 +10005,8 @@ interface RegExpConstructor { interface RegExp { /** - * Test this regex on a string - returns a result array on success, or `null` otherwise. + * Test this regex on a string - returns a result array on success, or `null` + * otherwise. * `/Wo/.exec("Hello World")` will return: * ``` * [ @@ -9208,7 +10031,8 @@ interface RegExp { exec(str: any): any; /** - * Test this regex on a string - returns `true` on a successful match, or `false` otherwise + * Test this regex on a string - returns `true` on a successful match, or `false` + * otherwise * * @param {any} str - A string to match on * @returns {boolean} true for a match, or false @@ -9220,7 +10044,8 @@ interface RegExp { /** * The built-in class for handling Regular Expressions * **Note:** Espruino's regular expression parser does not contain all the features - * present in a full ES6 JS engine. However it does contain support for the all the basics. + * present in a full ES6 JS engine. However it does contain support for the all the + * basics. * @url http://www.espruino.com/Reference#RegExp */ declare const RegExp: RegExpConstructor @@ -9361,10 +10186,13 @@ declare class Nucleo { * @url http://www.espruino.com/Reference#l_Nucleo_D15 */ static D15: Pin; + + } /** - * This is a built-in class to allow you to use the ESP8266 NodeMCU boards's pin namings to access pins. It is only available on ESP8266-based boards. + * This is a built-in class to allow you to use the ESP8266 NodeMCU boards's pin + * namings to access pins. It is only available on ESP8266-based boards. * @url http://www.espruino.com/Reference#NodeMCU */ declare class NodeMCU { @@ -9439,10 +10267,13 @@ declare class NodeMCU { * @url http://www.espruino.com/Reference#l_NodeMCU_D10 */ static D10: Pin; + + } /** - * Class containing utility functions for the [ESP32](http://www.espruino.com/ESP32) + * Class containing utility functions for the + * [ESP32](http://www.espruino.com/ESP32) * @url http://www.espruino.com/Reference#ESP32 */ declare class ESP32 { @@ -9452,13 +10283,13 @@ declare class ESP32 { * @param {number} atten - Attenuate factor * @url http://www.espruino.com/Reference#l_ESP32_setAtten */ - static setAtten(pin: Pin, atten: number): any; + static setAtten(pin: Pin, atten: number): void; /** * Perform a hardware reset/reboot of the ESP32. * @url http://www.espruino.com/Reference#l_ESP32_reboot */ - static reboot(): any; + static reboot(): void; /** * Put device in deepsleep state for "us" microseconds. @@ -9466,15 +10297,16 @@ declare class ESP32 { * @param {number} us - Sleeptime in us * @url http://www.espruino.com/Reference#l_ESP32_deepSleep */ - static deepSleep(us: number): any; + static deepSleep(us: number): void; /** - * Returns an object that contains details about the state of the ESP32 with the following fields: - * * `sdkVersion` - Version of the SDK. - * * `freeHeap` - Amount of free heap in bytes. - * * `BLE` - Status of BLE, enabled if true. - * * `Wifi` - Status of Wifi, enabled if true. - * * `minHeap` - Minimum heap, calculated by heap_caps_get_minimum_free_size + * Returns an object that contains details about the state of the ESP32 with the + * following fields: + * * `sdkVersion` - Version of the SDK. + * * `freeHeap` - Amount of free heap in bytes. + * * `BLE` - Status of BLE, enabled if true. + * * `Wifi` - Status of Wifi, enabled if true. + * * `minHeap` - Minimum heap, calculated by heap_caps_get_minimum_free_size * @returns {any} The state of the ESP32 * @url http://www.espruino.com/Reference#l_ESP32_getState */ @@ -9485,25 +10317,27 @@ declare class ESP32 { * @param {number} level - which events should be shown (GATTS, GATTC, GAP) * @url http://www.espruino.com/Reference#l_ESP32_setBLE_Debug */ - static setBLE_Debug(level: number): any; + static setBLE_Debug(level: number): void; /** - * Switches Bluetooth off/on, removes saved code from Flash, resets the board, - * and on restart creates jsVars depending on available heap (actual additional 1800) + * Switches Bluetooth off/on, removes saved code from Flash, resets the board, and + * on restart creates jsVars depending on available heap (actual additional 1800) * * @param {boolean} enable - switches Bluetooth on or off * @url http://www.espruino.com/Reference#l_ESP32_enableBLE */ - static enableBLE(enable: boolean): any; + static enableBLE(enable: boolean): void; /** - * Switches Wifi off/on, removes saved code from Flash, resets the board, - * and on restart creates jsVars depending on available heap (actual additional 3900) + * Switches Wifi off/on, removes saved code from Flash, resets the board, and on + * restart creates jsVars depending on available heap (actual additional 3900) * * @param {boolean} enable - switches Wifi on or off * @url http://www.espruino.com/Reference#l_ESP32_enableWifi */ - static enableWifi(enable: boolean): any; + static enableWifi(enable: boolean): void; + + } /** @@ -9519,11 +10353,13 @@ declare class Queue { * @returns {any} A Queue object * @url http://www.espruino.com/Reference#l_Queue_Queue */ - static new(queueName: any): any;/** + static new(queueName: any): any; + + /** * reads one character from queue, if available * @url http://www.espruino.com/Reference#l_Queue_read */ - read(): any; + read(): void; /** * Writes one character to queue @@ -9531,13 +10367,13 @@ declare class Queue { * @param {any} char - char to be send * @url http://www.espruino.com/Reference#l_Queue_writeChar */ - writeChar(char: any): any; + writeChar(char: any): void; /** * logs list of queues * @url http://www.espruino.com/Reference#l_Queue_log */ - log(): any; + log(): void; } /** @@ -9553,17 +10389,19 @@ declare class Task { * @returns {any} A Task object * @url http://www.espruino.com/Reference#l_Task_Task */ - static new(taskName: any): any;/** + static new(taskName: any): any; + + /** * Suspend task, be careful not to suspend Espruino task itself * @url http://www.espruino.com/Reference#l_Task_suspend */ - suspend(): any; + suspend(): void; /** * Resumes a suspended task * @url http://www.espruino.com/Reference#l_Task_resume */ - resume(): any; + resume(): void; /** * returns name of actual task @@ -9576,13 +10414,13 @@ declare class Task { * Sends a binary notify to task * @url http://www.espruino.com/Reference#l_Task_notify */ - notify(): any; + notify(): void; /** * logs list of tasks * @url http://www.espruino.com/Reference#l_Task_log */ - log(): any; + log(): void; } /** @@ -9601,13 +10439,15 @@ declare class Timer { * @returns {any} A Timer Object * @url http://www.espruino.com/Reference#l_Timer_Timer */ - static new(timerName: any, group: number, index: number, isrIndex: number): any;/** + static new(timerName: any, group: number, index: number, isrIndex: number): any; + + /** * Starts a timer * * @param {number} duration - duration of timmer in micro secs * @url http://www.espruino.com/Reference#l_Timer_start */ - start(duration: number): any; + start(duration: number): void; /** * Reschedules a timer, needs to be started at least once @@ -9615,13 +10455,13 @@ declare class Timer { * @param {number} duration - duration of timmer in micro secs * @url http://www.espruino.com/Reference#l_Timer_reschedule */ - reschedule(duration: number): any; + reschedule(duration: number): void; /** * logs list of timers * @url http://www.espruino.com/Reference#l_Timer_log */ - log(): any; + log(): void; } interface BooleanConstructor { @@ -9646,10 +10486,12 @@ declare const Boolean: BooleanConstructor // GLOBALS /** - * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) board + * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) + * board * Show an image on the in-built 5x5 LED screen. * Image can be: - * * A number where each bit represents a pixel (so 25 bits). eg. `5` or `0x1FFFFFF` + * * A number where each bit represents a pixel (so 25 bits). eg. `5` or + * `0x1FFFFFF` * * A string, eg: `show("10001")`. Newlines are ignored, and anything that is not * a space or `0` is treated as a 1. * * An array of 4 bytes (more will be ignored), eg `show([1,2,3,0])` @@ -9671,10 +10513,11 @@ declare const Boolean: BooleanConstructor * @param {any} image - The image to show * @url http://www.espruino.com/Reference#l__global_show */ -declare function show(image: any): any; +declare function show(image: any): void; /** - * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) board + * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) + * board * Get the current acceleration of the micro:bit from the on-board accelerometer * **This is deprecated.** Please use `Microbit.accel` instead. * @returns {any} An object with x, y, and z fields in it @@ -9683,8 +10526,10 @@ declare function show(image: any): any; declare function acceleration(): any; /** - * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) board - * Get the current compass position for the micro:bit from the on-board magnetometer + * **Note:** This function is only available on the [BBC micro:bit](/MicroBit) + * board + * Get the current compass position for the micro:bit from the on-board + * magnetometer * **This is deprecated.** Please use `Microbit.mag` instead. * @returns {any} An object with x, y, and z fields in it * @url http://www.espruino.com/Reference#l__global_compass @@ -9776,21 +10621,24 @@ declare const CORNER5: Pin; declare const CORNER6: Pin; /** - * On Puck.js V2 (not v1.0) this is the pin that controls the FET, for high-powered outputs. + * On Puck.js V2 (not v1.0) this is the pin that controls the FET, for high-powered + * outputs. * @returns {Pin} * @url http://www.espruino.com/Reference#l__global_FET */ declare const FET: Pin; /** - * The pin marked SDA on the Arduino pin footprint. This is connected directly to pin A4. + * The pin marked SDA on the Arduino pin footprint. This is connected directly to + * pin A4. * @returns {Pin} * @url http://www.espruino.com/Reference#l__global_SDA */ declare const SDA: Pin; /** - * The pin marked SDA on the Arduino pin footprint. This is connected directly to pin A5. + * The pin marked SDA on the Arduino pin footprint. This is connected directly to + * pin A5. * @returns {Pin} * @url http://www.espruino.com/Reference#l__global_SCL */ @@ -9804,30 +10652,33 @@ declare const SCL: Pin; declare const VIBRATE: Pin; /** - * On most Espruino board there are LEDs, in which case `LED` will be an actual Pin. - * On Bangle.js there are no LEDs, so to remain compatible with example code that might - * expect an LED, this is an object that behaves like a pin, but which just displays - * a circle on the display + * On most Espruino board there are LEDs, in which case `LED` will be an actual + * Pin. + * On Bangle.js there are no LEDs, so to remain compatible with example code that + * might expect an LED, this is an object that behaves like a pin, but which just + * displays a circle on the display * @returns {any} A `Pin` object for a fake LED which appears on * @url http://www.espruino.com/Reference#l__global_LED */ declare const LED: any; /** - * On most Espruino board there are LEDs, in which case `LED1` will be an actual Pin. - * On Bangle.js there are no LEDs, so to remain compatible with example code that might - * expect an LED, this is an object that behaves like a pin, but which just displays - * a circle on the display + * On most Espruino board there are LEDs, in which case `LED1` will be an actual + * Pin. + * On Bangle.js there are no LEDs, so to remain compatible with example code that + * might expect an LED, this is an object that behaves like a pin, but which just + * displays a circle on the display * @returns {any} A `Pin` object for a fake LED which appears on * @url http://www.espruino.com/Reference#l__global_LED1 */ declare const LED1: any; /** - * On most Espruino board there are LEDs, in which case `LED2` will be an actual Pin. - * On Bangle.js there are no LEDs, so to remain compatible with example code that might - * expect an LED, this is an object that behaves like a pin, but which just displays - * a circle on the display + * On most Espruino board there are LEDs, in which case `LED2` will be an actual + * Pin. + * On Bangle.js there are no LEDs, so to remain compatible with example code that + * might expect an LED, this is an object that behaves like a pin, but which just + * displays a circle on the display * @returns {any} A `Pin` object for a fake LED which appears on * @url http://www.espruino.com/Reference#l__global_LED2 */ @@ -9897,13 +10748,13 @@ declare const Infinity: number; * @returns {number} Logic 1 for Arduino compatibility - this is the same as just typing `1` * @url http://www.espruino.com/Reference#l__global_HIGH */ -declare const HIGH: number; +declare const HIGH: 1; /** * @returns {number} Logic 0 for Arduino compatibility - this is the same as just typing `0` * @url http://www.espruino.com/Reference#l__global_LOW */ -declare const LOW: number; +declare const LOW: 0; /** * A variable containing the arguments given to the function: @@ -9915,11 +10766,11 @@ declare const LOW: number; * hello("Test") // 1 ["Test"] * hello(1,2,3) // 3 [1,2,3] * ``` - * **Note:** Due to the way Espruino works this is doesn't behave exactly - * the same as in normal JavaScript. The length of the arguments array - * will never be less than the number of arguments specified in the - * function declaration: `(function(a){ return arguments.length; })() == 1`. - * Normal JavaScript interpreters would return `0` in the above case. + * **Note:** Due to the way Espruino works this is doesn't behave exactly the same + * as in normal JavaScript. The length of the arguments array will never be less + * than the number of arguments specified in the function declaration: + * `(function(a){ return arguments.length; })() == 1`. Normal JavaScript + * interpreters would return `0` in the above case. * @returns {any} An array containing all the arguments given to the function * @url http://www.espruino.com/Reference#l__global_arguments */ @@ -9954,7 +10805,8 @@ declare function parseInt(string: any, radix: any): any; declare function parseFloat(string: any): number; /** - * Is the parameter a finite num,ber or not? If needed, the parameter is first converted to a number. + * Is the parameter a finite num,ber or not? If needed, the parameter is first + * converted to a number. * * @param {any} x * @returns {boolean} True is the value is a Finite number, false if not. @@ -9990,7 +10842,8 @@ declare function btoa(binaryData: any): any; declare function atob(base64Data: any): any; /** - * Convert a string with any character not alphanumeric or `- _ . ! ~ * ' ( )` converted to the form `%XY` where `XY` is its hexadecimal representation + * Convert a string with any character not alphanumeric or `- _ . ! ~ * ' ( )` + * converted to the form `%XY` where `XY` is its hexadecimal representation * * @param {any} str - A string to encode as a URI * @returns {any} A string containing the encoded data @@ -9999,7 +10852,8 @@ declare function atob(base64Data: any): any; declare function encodeURIComponent(str: any): any; /** - * Convert any groups of characters of the form '%ZZ', into characters with hex code '0xZZ' + * Convert any groups of characters of the form '%ZZ', into characters with hex + * code '0xZZ' * * @param {any} str - A string to decode from a URI * @returns {any} A string containing the decoded data @@ -10016,17 +10870,15 @@ declare function decodeURIComponent(str: any): any; * print(s.read("test")); * // prints "hello world" * ``` - * Check out [the page on Modules](/Modules) for an explanation - * of what modules are and how you can use them. + * Check out [the page on Modules](/Modules) for an explanation of what modules are + * and how you can use them. * * @param {any} moduleName - A String containing the name of the given module * @returns {any} The result of evaluating the string * @url http://www.espruino.com/Reference#l__global_require */ -declare function require(moduleName: T): Modules[T] -declare function require< - T extends Exclude ->(moduleName: T): any +declare function require(moduleName: T): Libraries[T]; +declare function require>(moduleName: T): any; /** * Read 8 bits of memory at the given location - DANGEROUS! @@ -10036,7 +10888,8 @@ declare function require< * @returns {any} The value of memory at the given location * @url http://www.espruino.com/Reference#l__global_peek8 */ -declare function peek8(addr: number, count: number): any; +declare function peek8(addr: number, count?: 1): number; +declare function peek8(addr: number, count: number): Uint8Array; /** * Write 8 bits of memory at the given location - VERY DANGEROUS! @@ -10045,7 +10898,7 @@ declare function peek8(addr: number, count: number): any; * @param {any} value - The value to write, or an array of values * @url http://www.espruino.com/Reference#l__global_poke8 */ -declare function poke8(addr: number, value: any): any; +declare function poke8(addr: number, value: number | number[]): void; /** * Read 16 bits of memory at the given location - DANGEROUS! @@ -10055,7 +10908,8 @@ declare function poke8(addr: number, value: any): any; * @returns {any} The value of memory at the given location * @url http://www.espruino.com/Reference#l__global_peek16 */ -declare function peek16(addr: number, count: number): any; +declare function peek16(addr: number, count?: 1): number; +declare function peek16(addr: number, count: number): Uint8Array; /** * Write 16 bits of memory at the given location - VERY DANGEROUS! @@ -10064,7 +10918,7 @@ declare function peek16(addr: number, count: number): any; * @param {any} value - The value to write, or an array of values * @url http://www.espruino.com/Reference#l__global_poke16 */ -declare function poke16(addr: number, value: any): any; +declare function poke16(addr: number, value: number | number[]): void; /** * Read 32 bits of memory at the given location - DANGEROUS! @@ -10074,7 +10928,8 @@ declare function poke16(addr: number, value: any): any; * @returns {any} The value of memory at the given location * @url http://www.espruino.com/Reference#l__global_peek32 */ -declare function peek32(addr: number, count: number): any; +declare function peek32(addr: number, count?: 1): number; +declare function peek32(addr: number, count: number): Uint8Array; /** * Write 32 bits of memory at the given location - VERY DANGEROUS! @@ -10083,13 +10938,14 @@ declare function peek32(addr: number, count: number): any; * @param {any} value - The value to write, or an array of values * @url http://www.espruino.com/Reference#l__global_poke32 */ -declare function poke32(addr: number, value: any): any; +declare function poke32(addr: number, value: number | number[]): void; /** * Get the analog value of the given pin * This is different to Arduino which only returns an integer between 0 and 1023 * However only pins connected to an ADC will work (see the datasheet) - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"analog"` + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset pin's state to `"analog"` * * @param {Pin} pin * The pin to use @@ -10102,10 +10958,13 @@ declare function analogRead(pin: Pin): number; /** * Set the analog Value of a pin. It will be output using PWM. * Objects can contain: - * * `freq` - pulse frequency in Hz, eg. ```analogWrite(A0,0.5,{ freq : 10 });``` - specifying a frequency will force PWM output, even if the pin has a DAC + * * `freq` - pulse frequency in Hz, eg. ```analogWrite(A0,0.5,{ freq : 10 });``` - + * specifying a frequency will force PWM output, even if the pin has a DAC * * `soft` - boolean, If true software PWM is used if hardware is not available. - * * `forceSoft` - boolean, If true software PWM is used even if hardware PWM or a DAC is available - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"output"` + * * `forceSoft` - boolean, If true software PWM is used even if hardware PWM or a + * DAC is available + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset pin's state to `"output"` * * @param {Pin} pin * The pin to use @@ -10115,29 +10974,39 @@ declare function analogRead(pin: Pin): number; * An object containing options for analog output - see below * @url http://www.espruino.com/Reference#l__global_analogWrite */ -declare function analogWrite(pin: Pin, value: number, options: any): any; +declare function analogWrite(pin: Pin, value: number, options?: { freq?: number, soft?: boolean, forceSoft?: boolean }): void; /** - * Pulse the pin with the value for the given time in milliseconds. It uses a hardware timer to produce accurate pulses, and returns immediately (before the pulse has finished). Use `digitalPulse(A0,1,0)` to wait until a previous pulse has finished. - * eg. `digitalPulse(A0,1,5);` pulses A0 high for 5ms. `digitalPulse(A0,1,[5,2,4]);` pulses A0 high for 5ms, low for 2ms, and high for 4ms - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"output"` - * digitalPulse is for SHORT pulses that need to be very accurate. If you're doing anything over a few milliseconds, use setTimeout instead. + * Pulse the pin with the value for the given time in milliseconds. It uses a + * hardware timer to produce accurate pulses, and returns immediately (before the + * pulse has finished). Use `digitalPulse(A0,1,0)` to wait until a previous pulse + * has finished. + * eg. `digitalPulse(A0,1,5);` pulses A0 high for 5ms. + * `digitalPulse(A0,1,[5,2,4]);` pulses A0 high for 5ms, low for 2ms, and high for + * 4ms + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset pin's state to `"output"` + * digitalPulse is for SHORT pulses that need to be very accurate. If you're doing + * anything over a few milliseconds, use setTimeout instead. * * @param {Pin} pin - The pin to use * @param {boolean} value - Whether to pulse high (true) or low (false) * @param {any} time - A time in milliseconds, or an array of times (in which case a square wave will be output starting with a pulse of 'value') * @url http://www.espruino.com/Reference#l__global_digitalPulse */ -declare function digitalPulse(pin: Pin, value: boolean, time: any): any; +declare function digitalPulse(pin: Pin, value: boolean, time: number | number[]): void; /** * Set the digital value of the given pin. - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"output"` - * If pin argument is an array of pins (eg. `[A2,A1,A0]`) the value argument will be treated - * as an array of bits where the last array element is the least significant bit. - * In this case, pin values are set least significant bit first (from the right-hand side - * of the array of pins). This means you can use the same pin multiple times, for - * example `digitalWrite([A1,A1,A0,A0],0b0101)` would pulse A0 followed by A1. + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset pin's state to `"output"` + * If pin argument is an array of pins (eg. `[A2,A1,A0]`) the value argument will + * be treated as an array of bits where the last array element is the least + * significant bit. + * In this case, pin values are set least significant bit first (from the + * right-hand side of the array of pins). This means you can use the same pin + * multiple times, for example `digitalWrite([A1,A1,A0,A0],0b0101)` would pulse A0 + * followed by A1. * If the pin argument is an object with a `write` method, the `write` method will * be called with the value passed through. * @@ -10145,58 +11014,67 @@ declare function digitalPulse(pin: Pin, value: boolean, time: any): any; * @param {number} value - Whether to pulse high (true) or low (false) * @url http://www.espruino.com/Reference#l__global_digitalWrite */ -declare function digitalWrite(pin: any, value: number): any; +declare function digitalWrite(pin: Pin, value: typeof HIGH | typeof LOW): void; /** * Get the digital value of the given pin. - * **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"input"` - * If the pin argument is an array of pins (eg. `[A2,A1,A0]`) the value returned will be an number where - * the last array element is the least significant bit, for example if `A0=A1=1` and `A2=0`, `digitalRead([A2,A1,A0]) == 0b011` - * If the pin argument is an object with a `read` method, the `read` method will be called and the integer value it returns - * passed back. + * **Note:** if you didn't call `pinMode` beforehand then this function will also + * reset pin's state to `"input"` + * If the pin argument is an array of pins (eg. `[A2,A1,A0]`) the value returned + * will be an number where the last array element is the least significant bit, for + * example if `A0=A1=1` and `A2=0`, `digitalRead([A2,A1,A0]) == 0b011` + * If the pin argument is an object with a `read` method, the `read` method will be + * called and the integer value it returns passed back. * * @param {any} pin - The pin to use * @returns {number} The digital Value of the Pin * @url http://www.espruino.com/Reference#l__global_digitalRead */ -declare function digitalRead(pin: any): number; +declare function digitalRead(pin: Pin): number; /** * Set the mode of the given pin. - * * `auto`/`undefined` - Don't change state, but allow `digitalWrite`/etc to automatically change state as appropriate + * * `auto`/`undefined` - Don't change state, but allow `digitalWrite`/etc to + * automatically change state as appropriate * * `analog` - Analog input * * `input` - Digital input * * `input_pullup` - Digital input with internal ~40k pull-up resistor * * `input_pulldown` - Digital input with internal ~40k pull-down resistor * * `output` - Digital output - * * `opendrain` - Digital output that only ever pulls down to 0v. Sending a logical `1` leaves the pin open circuit - * * `opendrain_pullup` - Digital output that pulls down to 0v. Sending a logical `1` enables internal ~40k pull-up resistor + * * `opendrain` - Digital output that only ever pulls down to 0v. Sending a + * logical `1` leaves the pin open circuit + * * `opendrain_pullup` - Digital output that pulls down to 0v. Sending a logical + * `1` enables internal ~40k pull-up resistor * * `af_output` - Digital output from built-in peripheral - * * `af_opendrain` - Digital output from built-in peripheral that only ever pulls down to 0v. Sending a logical `1` leaves the pin open circuit - * **Note:** `digitalRead`/`digitalWrite`/etc set the pin mode automatically *unless* `pinMode` has been called first. - * If you want `digitalRead`/etc to set the pin mode automatically after you have called `pinMode`, simply call it again - * with no mode argument (`pinMode(pin)`), `auto` as the argument (`pinMode(pin, "auto")`), or with the 3rd 'automatic' - * argument set to true (`pinMode(pin, "output", true)`). + * * `af_opendrain` - Digital output from built-in peripheral that only ever pulls + * down to 0v. Sending a logical `1` leaves the pin open circuit + * **Note:** `digitalRead`/`digitalWrite`/etc set the pin mode automatically + * *unless* `pinMode` has been called first. If you want `digitalRead`/etc to set + * the pin mode automatically after you have called `pinMode`, simply call it again + * with no mode argument (`pinMode(pin)`), `auto` as the argument (`pinMode(pin, + * "auto")`), or with the 3rd 'automatic' argument set to true (`pinMode(pin, + * "output", true)`). * * @param {Pin} pin - The pin to set pin mode for * @param {any} mode - The mode - a string that is either 'analog', 'input', 'input_pullup', 'input_pulldown', 'output', 'opendrain', 'af_output' or 'af_opendrain'. Do not include this argument or use 'auto' if you want to revert to automatic pin mode setting. * @param {boolean} automatic - Optional, default is false. If true, subsequent commands will automatically change the state (see notes below) * @url http://www.espruino.com/Reference#l__global_pinMode */ -declare function pinMode(pin: Pin, mode: any, automatic: boolean): any; +declare function pinMode(pin: Pin, mode?: PinMode | "auto", automatic?: boolean): void; /** - * Return the current mode of the given pin. See `pinMode` for more information on returned values. + * Return the current mode of the given pin. See `pinMode` for more information on + * returned values. * * @param {Pin} pin - The pin to check * @returns {any} The pin mode, as a string * @url http://www.espruino.com/Reference#l__global_getPinMode */ -declare function getPinMode(pin: Pin): any; +declare function getPinMode(pin: Pin): PinMode; /** - * Shift an array of data out using the pins supplied *least significant bit first*, - * for example: + * Shift an array of data out using the pins supplied *least significant bit + * first*, for example: * ``` * // shift out to single clk+data * shiftOut(A0, { clk : A1 }, [1,0,1,0]); @@ -10217,9 +11095,9 @@ declare function getPinMode(pin: Pin): any; * repeat : int, // number of clocks per array item * } * ``` - * Each item in the `data` array will be output to the pins, with the first - * pin in the array being the MSB and the last the LSB, then the clock will be - * pulsed in the polarity given. + * Each item in the `data` array will be output to the pins, with the first pin in + * the array being the MSB and the last the LSB, then the clock will be pulsed in + * the polarity given. * `repeat` is the amount of times shift data out for each array item. For instance * we may want to shift 8 bits out through 2 pins - in which case we need to set * repeat to 4. @@ -10229,11 +11107,13 @@ declare function getPinMode(pin: Pin): any; * @param {any} data - The data to shift out (see `E.toUint8Array` for info on the forms this can take) * @url http://www.espruino.com/Reference#l__global_shiftOut */ -declare function shiftOut(pins: any, options: any, data: any): any; +declare function shiftOut(pins: Pin | Pin[], options: { clk?: Pin, clkPol?: boolean, repeat?: number }, data: Uint8ArrayResolvable): void; /** - * Call the function specified when the pin changes. Watches set with `setWatch` can be removed using `clearWatch`. - * If the `options` parameter is an object, it can contain the following information (all optional): + * Call the function specified when the pin changes. Watches set with `setWatch` + * can be removed using `clearWatch`. + * If the `options` parameter is an object, it can contain the following + * information (all optional): * ``` * { * // Whether to keep producing callbacks, or remove the watch after the first callback @@ -10256,24 +11136,33 @@ declare function shiftOut(pins: any, options: any, data: any): any; * hispeed : true * } * ``` - * The `function` callback is called with an argument, which is an object of type `{state:bool, time:float, lastTime:float}`. + * The `function` callback is called with an argument, which is an object of type + * `{state:bool, time:float, lastTime:float}`. * * `state` is whether the pin is currently a `1` or a `0` * * `time` is the time in seconds at which the pin changed state - * * `lastTime` is the time in seconds at which the **pin last changed state**. When using `edge:'rising'` or `edge:'falling'`, this is not the same as when the function was last called. - * * `data` is included if `data:pin` was specified in the options, and can be used for reading in clocked data - * For instance, if you want to measure the length of a positive pulse you could use `setWatch(function(e) { console.log(e.time-e.lastTime); }, BTN, { repeat:true, edge:'falling' });`. - * This will only be called on the falling edge of the pulse, but will be able to measure the width of the pulse because `e.lastTime` is the time of the rising edge. - * Internally, an interrupt writes the time of the pin's state change into a queue with the exact - * time that it happened, and the function supplied to `setWatch` is executed only from the main - * message loop. However, if the callback is a native function `void (bool state)` then you can - * add `irq:true` to options, which will cause the function to be called from within the IRQ. - * When doing this, interrupts will happen on both edges and there will be no debouncing. - * **Note:** if you didn't call `pinMode` beforehand then this function will reset pin's state to `"input"` - * **Note:** The STM32 chip (used in the [Espruino Board](/EspruinoBoard) and [Pico](/Pico)) cannot - * watch two pins with the same number - eg `A0` and `B0`. - * **Note:** On nRF52 chips (used in Puck.js, Pixl.js, MDBT42Q) `setWatch` disables the GPIO - * output on that pin. In order to be able to write to the pin again you need to disable - * the watch with `clearWatch`. + * * `lastTime` is the time in seconds at which the **pin last changed state**. + * When using `edge:'rising'` or `edge:'falling'`, this is not the same as when + * the function was last called. + * * `data` is included if `data:pin` was specified in the options, and can be + * used for reading in clocked data + * For instance, if you want to measure the length of a positive pulse you could + * use `setWatch(function(e) { console.log(e.time-e.lastTime); }, BTN, { + * repeat:true, edge:'falling' });`. This will only be called on the falling edge + * of the pulse, but will be able to measure the width of the pulse because + * `e.lastTime` is the time of the rising edge. + * Internally, an interrupt writes the time of the pin's state change into a queue + * with the exact time that it happened, and the function supplied to `setWatch` is + * executed only from the main message loop. However, if the callback is a native + * function `void (bool state)` then you can add `irq:true` to options, which will + * cause the function to be called from within the IRQ. When doing this, interrupts + * will happen on both edges and there will be no debouncing. + * **Note:** if you didn't call `pinMode` beforehand then this function will reset + * pin's state to `"input"` + * **Note:** The STM32 chip (used in the [Espruino Board](/EspruinoBoard) and + * [Pico](/Pico)) cannot watch two pins with the same number - eg `A0` and `B0`. + * **Note:** On nRF52 chips (used in Puck.js, Pixl.js, MDBT42Q) `setWatch` disables + * the GPIO output on that pin. In order to be able to write to the pin again you + * need to disable the watch with `clearWatch`. * * @param {any} function - A Function or String to be executed * @param {Pin} pin - The pin to watch @@ -10281,7 +11170,7 @@ declare function shiftOut(pins: any, options: any, data: any): any; * @returns {any} An ID that can be passed to clearWatch * @url http://www.espruino.com/Reference#l__global_setWatch */ -declare function setWatch(func: any, pin: Pin, options: any): any; +declare function setWatch(func: ((arg: { state: boolean, time: number, lastTime: number }) => void) | string, pin: Pin, options?: boolean | { repeat?: boolean, edge?: "rising" | "falling" | "both", debounce?: number, irq?: boolean, data?: Pin, hispeed?: boolean }): number; /** * Clear the Watch that was created with setWatch. If no parameter is supplied, all watches will be removed. @@ -10290,57 +11179,145 @@ declare function setWatch(func: any, pin: Pin, options: any): any; * @param {any} id - The id returned by a previous call to setWatch. **Only one argument is allowed.** * @url http://www.espruino.com/Reference#l__global_clearWatch */ -declare function clearWatch(...id: any[]): any; +declare function clearWatch(id: number): void; + +declare const global: { + show: typeof show; + acceleration: typeof acceleration; + compass: typeof compass; + BTNA: typeof BTNA; + BTNB: typeof BTNB; + BTNU: typeof BTNU; + BTND: typeof BTND; + BTNL: typeof BTNL; + BTNR: typeof BTNR; + CORNER1: typeof CORNER1; + CORNER2: typeof CORNER2; + CORNER3: typeof CORNER3; + CORNER4: typeof CORNER4; + CORNER5: typeof CORNER5; + CORNER6: typeof CORNER6; + FET: typeof FET; + SDA: typeof SDA; + SCL: typeof SCL; + VIBRATE: typeof VIBRATE; + LED: typeof LED; + LED1: typeof LED1; + LED2: typeof LED2; + MOS1: typeof MOS1; + MOS2: typeof MOS2; + MOS3: typeof MOS3; + MOS4: typeof MOS4; + IOEXT0: typeof IOEXT0; + IOEXT1: typeof IOEXT1; + IOEXT2: typeof IOEXT2; + IOEXT3: typeof IOEXT3; + NaN: typeof NaN; + Infinity: typeof Infinity; + HIGH: typeof HIGH; + LOW: typeof LOW; + arguments: typeof arguments; + eval: typeof eval; + parseInt: typeof parseInt; + parseFloat: typeof parseFloat; + isFinite: typeof isFinite; + isNaN: typeof isNaN; + btoa: typeof btoa; + atob: typeof atob; + encodeURIComponent: typeof encodeURIComponent; + decodeURIComponent: typeof decodeURIComponent; + require: typeof require; + peek8: typeof peek8; + poke8: typeof poke8; + peek16: typeof peek16; + poke16: typeof poke16; + peek32: typeof peek32; + poke32: typeof poke32; + analogRead: typeof analogRead; + analogWrite: typeof analogWrite; + digitalPulse: typeof digitalPulse; + digitalWrite: typeof digitalWrite; + digitalRead: typeof digitalRead; + pinMode: typeof pinMode; + getPinMode: typeof getPinMode; + shiftOut: typeof shiftOut; + setWatch: typeof setWatch; + clearWatch: typeof clearWatch; + global: typeof global; + setBusyIndicator: typeof setBusyIndicator; + setSleepIndicator: typeof setSleepIndicator; + setDeepSleep: typeof setDeepSleep; + trace: typeof trace; + dump: typeof dump; + load: typeof load; + save: typeof save; + reset: typeof reset; + print: typeof print; + edit: typeof edit; + echo: typeof echo; + getTime: typeof getTime; + setTime: typeof setTime; + getSerial: typeof getSerial; + setInterval: typeof setInterval; + setTimeout: typeof setTimeout; + clearInterval: typeof clearInterval; + clearTimeout: typeof clearTimeout; + changeInterval: typeof changeInterval; + [key: string]: any; +} /** - * A reference to the global scope, where everything is defined. - * @returns {any} The global scope - * @url http://www.espruino.com/Reference#l__global_global - */ -declare const global: any; - -/** - * When Espruino is busy, set the pin specified here high. Set this to undefined to disable the feature. + * When Espruino is busy, set the pin specified here high. Set this to undefined to + * disable the feature. * * @param {any} pin * @url http://www.espruino.com/Reference#l__global_setBusyIndicator */ -declare function setBusyIndicator(pin: any): any; +declare function setBusyIndicator(pin: any): void; /** - * When Espruino is asleep, set the pin specified here low (when it's awake, set it high). Set this to undefined to disable the feature. + * When Espruino is asleep, set the pin specified here low (when it's awake, set it + * high). Set this to undefined to disable the feature. * Please see http://www.espruino.com/Power+Consumption for more details on this. * * @param {any} pin * @url http://www.espruino.com/Reference#l__global_setSleepIndicator */ -declare function setSleepIndicator(pin: any): any; +declare function setSleepIndicator(pin: any): void; /** - * Set whether we can enter deep sleep mode, which reduces power consumption to around 100uA. This only works on STM32 Espruino Boards (nRF52 boards sleep automatically). + * Set whether we can enter deep sleep mode, which reduces power consumption to + * around 100uA. This only works on STM32 Espruino Boards (nRF52 boards sleep + * automatically). * Please see http://www.espruino.com/Power+Consumption for more details on this. * * @param {boolean} sleep * @url http://www.espruino.com/Reference#l__global_setDeepSleep */ -declare function setDeepSleep(sleep: boolean): any; +declare function setDeepSleep(sleep: boolean): void; /** * Output debugging information - * Note: This is not included on boards with low amounts of flash memory, or the Espruino board. + * Note: This is not included on boards with low amounts of flash memory, or the + * Espruino board. * * @param {any} root - The symbol to output (optional). If nothing is specified, everything will be output * @url http://www.espruino.com/Reference#l__global_trace */ -declare function trace(root: any): any; +declare function trace(root: any): void; /** - * Output current interpreter state in a text form such that it can be copied to a new device - * Espruino keeps its current state in RAM (even if the function code is stored in Flash). When you type `dump()` it dumps the current state of code in RAM plus the hardware state, then if there's code saved in flash it writes "// Code saved with E.setBootCode" and dumps that too. - * **Note:** 'Internal' functions are currently not handled correctly. You will need to recreate these in the `onInit` function. + * Output current interpreter state in a text form such that it can be copied to a + * new device + * Espruino keeps its current state in RAM (even if the function code is stored in + * Flash). When you type `dump()` it dumps the current state of code in RAM plus + * the hardware state, then if there's code saved in flash it writes "// Code saved + * with E.setBootCode" and dumps that too. + * **Note:** 'Internal' functions are currently not handled correctly. You will + * need to recreate these in the `onInit` function. * @url http://www.espruino.com/Reference#l__global_dump */ -declare function dump(): any; +declare function dump(): void; /** * Restart and load the program out of flash - this has an effect similar to @@ -10349,81 +11326,95 @@ declare function dump(): any; * This command only executes when the Interpreter returns to the Idle state - for * instance ```a=1;load();a=2;``` will still leave 'a' as undefined (or what it was * set to in the saved program). - * Espruino will resume from where it was when you last typed `save()`. - * If you want code to be executed right after loading (for instance to initialise - * devices connected to Espruino), add an `init` event handler to `E` with - * `E.on('init', function() { ... your_code ... });`. This will then be automatically - * executed by Espruino every time it starts. - * **If you specify a filename in the argument then that file will be loaded - * from Storage after reset** in much the same way as calling `reset()` then `eval(require("Storage").read(filename))` + * Espruino will resume from where it was when you last typed `save()`. If you want + * code to be executed right after loading (for instance to initialise devices + * connected to Espruino), add an `init` event handler to `E` with `E.on('init', + * function() { ... your_code ... });`. This will then be automatically executed by + * Espruino every time it starts. + * **If you specify a filename in the argument then that file will be loaded from + * Storage after reset** in much the same way as calling `reset()` then + * `eval(require("Storage").read(filename))` * * @param {any} filename - optional: The name of a text JS file to load from Storage after reset * @url http://www.espruino.com/Reference#l__global_load */ -declare function load(filename: any): any; +declare function load(filename: any): void; /** * Save the state of the interpreter into flash (including the results of calling - * `setWatch`, `setInterval`, `pinMode`, and any listeners). The state will then be loaded automatically - * every time Espruino powers on or is hard-reset. To see what will get saved you can call `dump()`. - * **Note:** If you set up intervals/etc in `onInit()` and you have already called `onInit` - * before running `save()`, when Espruino resumes there will be two copies of your intervals - - * the ones from before the save, and the ones from after - which may cause you problems. - * For more information about this and other options for saving, please see - * the [Saving code on Espruino](https://www.espruino.com/Saving) page. + * `setWatch`, `setInterval`, `pinMode`, and any listeners). The state will then be + * loaded automatically every time Espruino powers on or is hard-reset. To see what + * will get saved you can call `dump()`. + * **Note:** If you set up intervals/etc in `onInit()` and you have already called + * `onInit` before running `save()`, when Espruino resumes there will be two copies + * of your intervals - the ones from before the save, and the ones from after - + * which may cause you problems. + * For more information about this and other options for saving, please see the + * [Saving code on Espruino](https://www.espruino.com/Saving) page. * This command only executes when the Interpreter returns to the Idle state - for * instance ```a=1;save();a=2;``` will save 'a' as 2. - * When Espruino powers on, it will resume from where it was when you typed `save()`. - * If you want code to be executed right after loading (for instance to initialise - * devices connected to Espruino), add a function called `onInit`, or add a `init` - * event handler to `E` with `E.on('init', function() { ... your_code ... });`. - * This will then be automatically executed by Espruino every time it starts. + * When Espruino powers on, it will resume from where it was when you typed + * `save()`. If you want code to be executed right after loading (for instance to + * initialise devices connected to Espruino), add a function called `onInit`, or + * add a `init` event handler to `E` with `E.on('init', function() { ... your_code + * ... });`. This will then be automatically executed by Espruino every time it + * starts. * In order to stop the program saved with this command being loaded automatically, - * check out [the Troubleshooting guide](https://www.espruino.com/Troubleshooting#espruino-stopped-working-after-i-typed-save-) + * check out [the Troubleshooting + * guide](https://www.espruino.com/Troubleshooting#espruino-stopped-working-after-i-typed-save-) * @url http://www.espruino.com/Reference#l__global_save */ -declare function save(): any; +declare function save(): void; /** - * Reset the interpreter - clear program memory in RAM, and do not load a saved program from flash. This does NOT reset the underlying hardware (which allows you to reset the device without it disconnecting from USB). - * This command only executes when the Interpreter returns to the Idle state - for instance ```a=1;reset();a=2;``` will still leave 'a' as undefined. + * Reset the interpreter - clear program memory in RAM, and do not load a saved + * program from flash. This does NOT reset the underlying hardware (which allows + * you to reset the device without it disconnecting from USB). + * This command only executes when the Interpreter returns to the Idle state - for + * instance ```a=1;reset();a=2;``` will still leave 'a' as undefined. * The safest way to do a full reset is to hit the reset button. - * If `reset()` is called with no arguments, it will reset the board's state in - * RAM but will not reset the state in flash. When next powered on (or when - * `load()` is called) the board will load the previously saved code. - * Calling `reset(true)` will cause *all saved code in flash memory to - * be cleared as well*. + * If `reset()` is called with no arguments, it will reset the board's state in RAM + * but will not reset the state in flash. When next powered on (or when `load()` is + * called) the board will load the previously saved code. + * Calling `reset(true)` will cause *all saved code in flash memory to be cleared + * as well*. * * @param {boolean} clearFlash - Remove saved code from flash as well * @url http://www.espruino.com/Reference#l__global_reset */ -declare function reset(clearFlash: boolean): any; +declare function reset(clearFlash: boolean): void; /** * Print the supplied string(s) to the console - * **Note:** If you're connected to a computer (not a wall adaptor) via USB but **you are not running a terminal app** then when you print data Espruino may pause execution and wait until the computer requests the data it is trying to print. + * **Note:** If you're connected to a computer (not a wall adaptor) via USB but + * **you are not running a terminal app** then when you print data Espruino may + * pause execution and wait until the computer requests the data it is trying to + * print. * * @param {any} text * @url http://www.espruino.com/Reference#l__global_print */ -declare function print(...text: any[]): any; +declare function print(...text: any[]): void; /** * Fill the console with the contents of the given function, so you can edit it. - * NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it. + * NOTE: This is a convenience function - it will not edit 'inner functions'. For + * that, you must edit the 'outer function' and re-execute it. * * @param {any} funcName - The name of the function to edit (either a string or just the unquoted name) * @url http://www.espruino.com/Reference#l__global_edit */ -declare function edit(funcName: any): any; +declare function edit(funcName: any): void; /** - * Should Espruino echo what you type back to you? true = yes (Default), false = no. When echo is off, the result of executing a command is not returned. Instead, you must use 'print' to send output. + * Should Espruino echo what you type back to you? true = yes (Default), false = + * no. When echo is off, the result of executing a command is not returned. + * Instead, you must use 'print' to send output. * * @param {boolean} echoOn * @url http://www.espruino.com/Reference#l__global_echo */ -declare function echo(echoOn: boolean): any; +declare function echo(echoOn: boolean): void; /** * Return the current system time in Seconds (as a floating point number) @@ -10433,12 +11424,11 @@ declare function echo(echoOn: boolean): any; declare function getTime(): number; /** - * Set the current system time in seconds (`time` can be a floating - * point value). - * This is used with `getTime`, the time reported from `setWatch`, as - * well as when using `new Date()`. - * `Date.prototype.getTime()` reports the time in milliseconds, so - * you can set the time to a `Date` object using: + * Set the current system time in seconds (`time` can be a floating point value). + * This is used with `getTime`, the time reported from `setWatch`, as well as when + * using `new Date()`. + * `Date.prototype.getTime()` reports the time in milliseconds, so you can set the + * time to a `Date` object using: * ``` * setTime((new Date("Tue, 19 Feb 2019 10:57")).getTime()/1000) * ``` @@ -10447,7 +11437,7 @@ declare function getTime(): number; * @param {number} time * @url http://www.espruino.com/Reference#l__global_setTime */ -declare function setTime(time: number): any; +declare function setTime(time: number): void; /** * Get the serial number of this board @@ -10457,7 +11447,8 @@ declare function setTime(time: number): any; declare function getSerial(): any; /** - * Call the function (or evaluate the string) specified REPEATEDLY after the timeout in milliseconds. + * Call the function (or evaluate the string) specified REPEATEDLY after the + * timeout in milliseconds. * For instance: * ``` * setInterval(function () { @@ -10467,16 +11458,20 @@ declare function getSerial(): any; * setInterval('console.log("Hello World");', 1000); * // both print 'Hello World' every second * ``` - * You can also specify extra arguments that will be sent to the function when it is executed. For example: + * You can also specify extra arguments that will be sent to the function when it + * is executed. For example: * ``` * setInterval(function (a,b) { * console.log(a+" "+b); * }, 1000, "Hello", "World"); * // prints 'Hello World' every second * ``` - * If you want to stop your function from being called, pass the number that - * was returned by `setInterval` into the `clearInterval` function. - * **Note:** If `setDeepSleep(true)` has been called and the interval is greater than 5 seconds, Espruino may execute the interval up to 1 second late. This is because Espruino can only wake from deep sleep every second - and waking early would cause Espruino to waste power while it waited for the correct time. + * If you want to stop your function from being called, pass the number that was + * returned by `setInterval` into the `clearInterval` function. + * **Note:** If `setDeepSleep(true)` has been called and the interval is greater + * than 5 seconds, Espruino may execute the interval up to 1 second late. This is + * because Espruino can only wake from deep sleep every second - and waking early + * would cause Espruino to waste power while it waited for the correct time. * * @param {any} function - A Function or String to be executed * @param {number} timeout - The time between calls to the function (max 3153600000000 = 100 years @@ -10487,7 +11482,8 @@ declare function getSerial(): any; declare function setInterval(func: any, timeout: number, ...args: any[]): any; /** - * Call the function (or evaluate the string) specified ONCE after the timeout in milliseconds. + * Call the function (or evaluate the string) specified ONCE after the timeout in + * milliseconds. * For instance: * ``` * setTimeout(function () { @@ -10497,16 +11493,20 @@ declare function setInterval(func: any, timeout: number, ...args: any[]): any; * setTimeout('console.log("Hello World");', 1000); * // both print 'Hello World' after a second * ``` - * You can also specify extra arguments that will be sent to the function when it is executed. For example: + * You can also specify extra arguments that will be sent to the function when it + * is executed. For example: * ``` * setTimeout(function (a,b) { * console.log(a+" "+b); * }, 1000, "Hello", "World"); * // prints 'Hello World' after 1 second * ``` - * If you want to stop the function from being called, pass the number that - * was returned by `setTimeout` into the `clearTimeout` function. - * **Note:** If `setDeepSleep(true)` has been called and the interval is greater than 5 seconds, Espruino may execute the interval up to 1 second late. This is because Espruino can only wake from deep sleep every second - and waking early would cause Espruino to waste power while it waited for the correct time. + * If you want to stop the function from being called, pass the number that was + * returned by `setTimeout` into the `clearTimeout` function. + * **Note:** If `setDeepSleep(true)` has been called and the interval is greater + * than 5 seconds, Espruino may execute the interval up to 1 second late. This is + * because Espruino can only wake from deep sleep every second - and waking early + * would cause Espruino to waste power while it waited for the correct time. * * @param {any} function - A Function or String to be executed * @param {number} timeout - The time until the function will be executed (max 3153600000000 = 100 years @@ -10526,7 +11526,7 @@ declare function setTimeout(func: any, timeout: number, ...args: any[]): any; * @param {any} id - The id returned by a previous call to setInterval. **Only one argument is allowed.** * @url http://www.espruino.com/Reference#l__global_clearInterval */ -declare function clearInterval(...id: any[]): any; +declare function clearInterval(...id: any[]): void; /** * Clear the Timeout that was created with `setTimeout`, for example: @@ -10538,21 +11538,21 @@ declare function clearInterval(...id: any[]): any; * @param {any} id - The id returned by a previous call to setTimeout. **Only one argument is allowed.** * @url http://www.espruino.com/Reference#l__global_clearTimeout */ -declare function clearTimeout(...id: any[]): any; +declare function clearTimeout(...id: any[]): void; /** * Change the Interval on a callback created with `setInterval`, for example: * ```var id = setInterval(function () { print('foo'); }, 1000); // every second``` * ```changeInterval(id, 1500); // now runs every 1.5 seconds``` * This takes effect immediately and resets the timeout, so in the example above, - * regardless of when you call `changeInterval`, the next interval will occur 1500ms - * after it. + * regardless of when you call `changeInterval`, the next interval will occur + * 1500ms after it. * * @param {any} id - The id returned by a previous call to setInterval * @param {number} time - The new time period in ms * @url http://www.espruino.com/Reference#l__global_changeInterval */ -declare function changeInterval(id: any, time: number): any; +declare function changeInterval(id: any, time: number): void; // LIBRARIES @@ -10572,16 +11572,24 @@ type Libraries = { } /** - * This library handles interfacing with a FAT32 filesystem on an SD card. The API is designed to be similar to node.js's - However Espruino does not currently support asynchronous file IO, so the functions behave like node.js's xxxxSync functions. Versions of the functions with 'Sync' after them are also provided for compatibility. - * To use this, you must type ```var fs = require('fs')``` to get access to the library - * See [the page on File IO](http://www.espruino.com/File+IO) for more information, and for examples on wiring up an SD card if your device doesn't come with one. - * **Note:** If you want to remove an SD card after you have started using it, you *must* call `E.unmountSD()` or you may cause damage to the card. + * This library handles interfacing with a FAT32 filesystem on an SD card. The API + * is designed to be similar to node.js's - However Espruino does not currently + * support asynchronous file IO, so the functions behave like node.js's xxxxSync + * functions. Versions of the functions with 'Sync' after them are also provided + * for compatibility. + * To use this, you must type ```var fs = require('fs')``` to get access to the + * library + * See [the page on File IO](http://www.espruino.com/File+IO) for more information, + * and for examples on wiring up an SD card if your device doesn't come with one. + * **Note:** If you want to remove an SD card after you have started using it, you + * *must* call `E.unmountSD()` or you may cause damage to the card. * @url http://www.espruino.com/Reference#fs */ fs: { /** * List all files in the supplied directory, returning them as an array of strings. - * NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version. + * NOTE: Espruino does not yet support Async file IO, so this function behaves like + * the 'Sync' version. * * @param {any} path - The path of the directory to list. If it is not supplied, '' is assumed, which will list the root directory * @returns {any} An array of filename strings (or undefined if the directory couldn't be listed) @@ -10600,7 +11608,8 @@ type Libraries = { /** * Write the data to the given file - * NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version. + * NOTE: Espruino does not yet support Async file IO, so this function behaves like + * the 'Sync' version. * * @param {any} path - The path of the file to write * @param {any} data - The data to write to the file @@ -10621,7 +11630,8 @@ type Libraries = { /** * Append the data to the given file, created a new file if it doesn't exist - * NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version. + * NOTE: Espruino does not yet support Async file IO, so this function behaves like + * the 'Sync' version. * * @param {any} path - The path of the file to write * @param {any} data - The data to write to the file @@ -10642,7 +11652,8 @@ type Libraries = { /** * Read all data from a file and return as a string - * NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version. + * NOTE: Espruino does not yet support Async file IO, so this function behaves like + * the 'Sync' version. * * @param {any} path - The path of the file to read * @returns {any} A string containing the contents of the file (or undefined if the file doesn't exist) @@ -10652,7 +11663,8 @@ type Libraries = { /** * Read all data from a file and return as a string. - * **Note:** The size of files you can load using this method is limited by the amount of available RAM. To read files a bit at a time, see the `File` class. + * **Note:** The size of files you can load using this method is limited by the + * amount of available RAM. To read files a bit at a time, see the `File` class. * * @param {any} path - The path of the file to read * @returns {any} A string containing the contents of the file (or undefined if the file doesn't exist) @@ -10662,7 +11674,8 @@ type Libraries = { /** * Delete the given file - * NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version. + * NOTE: Espruino does not yet support Async file IO, so this function behaves like + * the 'Sync' version. * * @param {any} path - The path of the file to delete * @returns {boolean} True on success, or false on failure @@ -10682,8 +11695,7 @@ type Libraries = { /** * Return information on the given file. This returns an object with the following * fields: - * size: size in bytes - * dir: a boolean specifying if the file is a directory or not + * size: size in bytes dir: a boolean specifying if the file is a directory or not * mtime: A Date structure specifying the time the file was last modified * * @param {any} path - The path of the file to get information on @@ -10694,7 +11706,8 @@ type Libraries = { /** * Create the directory - * NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version. + * NOTE: Espruino does not yet support Async file IO, so this function behaves like + * the 'Sync' version. * * @param {any} path - The name of the directory to create * @returns {boolean} True on success, or false on failure @@ -10722,12 +11735,14 @@ type Libraries = { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_fs_pipe */ - pipe(source: any, destination: any, options: any): any; + pipe(source: any, destination: any, options: any): void; } /** * Cryptographic functions - * **Note:** This library is currently only included in builds for boards where there is space. For other boards there is `crypto.js` which implements SHA1 in JS. + * **Note:** This library is currently only included in builds for boards where + * there is space. For other boards there is `crypto.js` which implements SHA1 in + * JS. * @url http://www.espruino.com/Reference#crypto */ crypto: { @@ -10740,9 +11755,9 @@ type Libraries = { /** * Performs a SHA1 hash and returns the result as a 20 byte ArrayBuffer. - * **Note:** On some boards (currently only Espruino Original) there - * isn't space for a fully unrolled SHA1 implementation so a slower - * all-JS implementation is used instead. + * **Note:** On some boards (currently only Espruino Original) there isn't space + * for a fully unrolled SHA1 implementation so a slower all-JS implementation is + * used instead. * * @param {any} message - The message to apply the hash to * @returns {any} Returns a 20 byte ArrayBuffer @@ -10804,7 +11819,8 @@ type Libraries = { */ NetworkJS: { /** - * Initialise the network using the callbacks given and return the first argument. For instance: + * Initialise the network using the callbacks given and return the first argument. + * For instance: * ``` * require("NetworkJS").create({ * create : function(host, port, socketType, options) { @@ -10832,8 +11848,9 @@ type Libraries = { * } * }); * ``` - * `socketType` is an integer - 2 for UDP, or see SocketType in https://github.com/espruino/Espruino/blob/master/libs/network/network.h - * for more information. + * `socketType` is an integer - 2 for UDP, or see SocketType in + * https://github.com/espruino/Espruino/blob/master/libs/network/network.h for more + * information. * * @param {any} obj - An object containing functions to access the network device * @returns {any} The object passed in @@ -10843,9 +11860,9 @@ type Libraries = { } /** - * This library implements a telnet console for the Espruino interpreter. It requires a network - * connection, e.g. Wifi, and **currently only functions on the ESP8266 and on Linux **. It uses - * port 23 on the ESP8266 and port 2323 on Linux. + * This library implements a telnet console for the Espruino interpreter. It + * requires a network connection, e.g. Wifi, and **currently only functions on the + * ESP8266 and on Linux **. It uses port 23 on the ESP8266 and port 2323 on Linux. * **Note:** To enable on Linux, run `./espruino --telnet` * @url http://www.espruino.com/Reference#TelnetServer */ @@ -10855,19 +11872,23 @@ type Libraries = { * @param {any} options - Options controlling the telnet console server `{ mode : 'on|off'}` * @url http://www.espruino.com/Reference#l_TelnetServer_setOptions */ - setOptions(options: any): any; + setOptions(options: any): void; } /** * This library allows you to create TCPIP servers and clients * In order to use this, you will need an extra module to get network connectivity. - * This is designed to be a cut-down version of the [node.js library](http://nodejs.org/api/net.html). Please see the [Internet](/Internet) page for more information on how to use it. + * This is designed to be a cut-down version of the [node.js + * library](http://nodejs.org/api/net.html). Please see the [Internet](/Internet) + * page for more information on how to use it. * @url http://www.espruino.com/Reference#net */ net: { /** * Create a Server - * When a request to the server is made, the callback is called. In the callback you can use the methods on the connection to send data. You can also add `connection.on('data',function() { ... })` to listen for received data + * When a request to the server is made, the callback is called. In the callback + * you can use the methods on the connection to send data. You can also add + * `connection.on('data',function() { ... })` to listen for received data * * @param {any} callback - A `function(connection)` that will be called when a connection is made * @returns {any} Returns a new Server Object @@ -10889,7 +11910,9 @@ type Libraries = { /** * This library allows you to create UDP/DATAGRAM servers and clients * In order to use this, you will need an extra module to get network connectivity. - * This is designed to be a cut-down version of the [node.js library](http://nodejs.org/api/dgram.html). Please see the [Internet](/Internet) page for more information on how to use it. + * This is designed to be a cut-down version of the [node.js + * library](http://nodejs.org/api/dgram.html). Please see the [Internet](/Internet) + * page for more information on how to use it. * @url http://www.espruino.com/Reference#dgram */ dgram: { @@ -10907,13 +11930,16 @@ type Libraries = { /** * This library allows you to create TCPIP servers and clients using TLS encryption * In order to use this, you will need an extra module to get network connectivity. - * This is designed to be a cut-down version of the [node.js library](http://nodejs.org/api/tls.html). Please see the [Internet](/Internet) page for more information on how to use it. + * This is designed to be a cut-down version of the [node.js + * library](http://nodejs.org/api/tls.html). Please see the [Internet](/Internet) + * page for more information on how to use it. * @url http://www.espruino.com/Reference#tls */ tls: { /** * Create a socket connection using TLS - * Options can have `ca`, `key` and `cert` fields, which should be the decoded content of the certificate. + * Options can have `ca`, `key` and `cert` fields, which should be the decoded + * content of the certificate. * ``` * var options = url.parse("localhost:1234"); * options.key = atob("MIIJKQ ... OZs08C"); @@ -10921,10 +11947,14 @@ type Libraries = { * options.ca = atob("MIIFgDCC ... GosQML4sc="); * require("tls").connect(options, ... ); * ``` - * If you have the certificates as `.pem` files, you need to load these files, take the information between the lines beginning with `----`, remove the newlines from it so you have raw base64, and then feed it into `atob` as above. + * If you have the certificates as `.pem` files, you need to load these files, take + * the information between the lines beginning with `----`, remove the newlines + * from it so you have raw base64, and then feed it into `atob` as above. * You can also: - * * Just specify the filename (<=100 characters) and it will be loaded and parsed if you have an SD card connected. For instance `options.key = "key.pem";` - * * Specify a function, which will be called to retrieve the data. For instance `options.key = function() { eeprom.load_my_info(); }; + * * Just specify the filename (<=100 characters) and it will be loaded and parsed + * if you have an SD card connected. For instance `options.key = "key.pem";` + * * Specify a function, which will be called to retrieve the data. For instance + * `options.key = function() { eeprom.load_my_info(); }; * For more information about generating and using certificates, see: * https://engineering.circle.com/https-authorized-certs-with-node-js/ * (You'll need to use 2048 bit certificates as opposed to 4096 bit shown above) @@ -10971,33 +12001,37 @@ type Libraries = { } /** - * The Wifi library is designed to control the Wifi interface. It supports functionality - * such as connecting to wifi networks, getting network information, starting an access - * point, etc. + * The Wifi library is designed to control the Wifi interface. It supports + * functionality such as connecting to wifi networks, getting network information, + * starting an access point, etc. * It is available on these devices: * * [Espruino WiFi](http://www.espruino.com/WiFi#using-wifi) * * [ESP8266](http://www.espruino.com/EspruinoESP8266) * * [ESP32](http://www.espruino.com/ESP32) - * **Certain features may or may not be implemented on your device** however - * we have documented what is available and what isn't. + * **Certain features may or may not be implemented on your device** however we + * have documented what is available and what isn't. * If you're not using one of the devices above, a separate WiFi library is * provided. For instance: - * * An [ESP8266 connected to an Espruino board](http://www.espruino.com/ESP8266#software) + * * An [ESP8266 connected to an Espruino + * board](http://www.espruino.com/ESP8266#software) * * An [CC3000 WiFi Module](http://www.espruino.com/CC3000) - * [Other ways of connecting to the net](http://www.espruino.com/Internet#related-pages) such - * as GSM, Ethernet and LTE have their own libraries. + * [Other ways of connecting to the + * net](http://www.espruino.com/Internet#related-pages) such as GSM, Ethernet and + * LTE have their own libraries. * You can use the WiFi library as follows: * ``` * var wifi = require("Wifi"); * wifi.connect("my-ssid", {password:"my-pwd"}, function(ap){ console.log("connected:", ap); }); * ``` - * On ESP32/ESP8266 if you want the connection to happen automatically at boot, add `wifi.save();`. - * On other platforms, place `wifi.connect` in a function called `onInit`. + * On ESP32/ESP8266 if you want the connection to happen automatically at boot, add + * `wifi.save();`. On other platforms, place `wifi.connect` in a function called + * `onInit`. * @url http://www.espruino.com/Reference#Wifi */ Wifi: { /** - * The 'associated' event is called when an association with an access point has succeeded, i.e., a connection to the AP's network has been established. + * The 'associated' event is called when an association with an access point has + * succeeded, i.e., a connection to the AP's network has been established. * On ESP32/ESP8266 there is a `details` parameter which includes: * * ssid - The SSID of the access point to which the association was established * * mac - The BSSID/mac address of the access point @@ -11010,7 +12044,8 @@ type Libraries = { on(event: "associated", callback: (details: any) => void): void; /** - * The 'disconnected' event is called when an association with an access point has been lost. + * The 'disconnected' event is called when an association with an access point has + * been lost. * On ESP32/ESP8266 there is a `details` parameter which includes: * * ssid - The SSID of the access point from which the association was lost * * mac - The BSSID/mac address of the access point @@ -11023,8 +12058,8 @@ type Libraries = { on(event: "disconnected", callback: (details: any) => void): void; /** - * The 'auth_change' event is called when the authentication mode with the associated access point changes. - * The details include: + * The 'auth_change' event is called when the authentication mode with the + * associated access point changes. The details include: * * oldMode - The old auth mode (string: open, wep, wpa, wpa2, wpa_wpa2) * * newMode - The new auth mode (string: open, wep, wpa, wpa2, wpa_wpa2) * @param {string} event - The event to listen to. @@ -11035,7 +12070,8 @@ type Libraries = { on(event: "auth_change", callback: (details: any) => void): void; /** - * The 'dhcp_timeout' event is called when a DHCP request to the connected access point fails and thus no IP address could be acquired (or renewed). + * The 'dhcp_timeout' event is called when a DHCP request to the connected access + * point fails and thus no IP address could be acquired (or renewed). * @param {string} event - The event to listen to. * @param {() => void} callback - A function that is executed when the event occurs. * @url http://www.espruino.com/Reference#l_Wifi_dhcp_timeout @@ -11043,7 +12079,11 @@ type Libraries = { on(event: "dhcp_timeout", callback: () => void): void; /** - * The 'connected' event is called when the connection with an access point is ready for traffic. In the case of a dynamic IP address configuration this is when an IP address is obtained, in the case of static IP address allocation this happens when an association is formed (in that case the 'associated' and 'connected' events are fired in rapid succession). + * The 'connected' event is called when the connection with an access point is + * ready for traffic. In the case of a dynamic IP address configuration this is + * when an IP address is obtained, in the case of static IP address allocation this + * happens when an association is formed (in that case the 'associated' and + * 'connected' events are fired in rapid succession). * On ESP32/ESP8266 there is a `details` parameter which includes: * * ip - The IP address obtained as string * * netmask - The network's IP range mask as string @@ -11056,8 +12096,8 @@ type Libraries = { on(event: "connected", callback: (details: any) => void): void; /** - * The 'sta_joined' event is called when a station establishes an association (i.e. connects) with the esp8266's access point. - * The details include: + * The 'sta_joined' event is called when a station establishes an association (i.e. + * connects) with the esp8266's access point. The details include: * * mac - The MAC address of the station in string format (00:00:00:00:00:00) * @param {string} event - The event to listen to. * @param {(details: any) => void} callback - A function that is executed when the event occurs. Its arguments are: @@ -11067,8 +12107,8 @@ type Libraries = { on(event: "sta_joined", callback: (details: any) => void): void; /** - * The 'sta_left' event is called when a station disconnects from the esp8266's access point (or its association times out?). - * The details include: + * The 'sta_left' event is called when a station disconnects from the esp8266's + * access point (or its association times out?). The details include: * * mac - The MAC address of the station in string format (00:00:00:00:00:00) * @param {string} event - The event to listen to. * @param {(details: any) => void} callback - A function that is executed when the event occurs. Its arguments are: @@ -11078,8 +12118,8 @@ type Libraries = { on(event: "sta_left", callback: (details: any) => void): void; /** - * The 'probe_recv' event is called when a probe request is received from some station by the esp8266's access point. - * The details include: + * The 'probe_recv' event is called when a probe request is received from some + * station by the esp8266's access point. The details include: * * mac - The MAC address of the station in string format (00:00:00:00:00:00) * * rssi - The signal strength in dB of the probe request * @param {string} event - The event to listen to. @@ -11090,43 +12130,65 @@ type Libraries = { on(event: "probe_recv", callback: (details: any) => void): void; /** - * Disconnect the wifi station from an access point and disable the station mode. It is OK to call `disconnect` to turn off station mode even if no connection exists (for example, connection attempts may be failing). Station mode can be re-enabled by calling `connect` or `scan`. + * Disconnect the wifi station from an access point and disable the station mode. + * It is OK to call `disconnect` to turn off station mode even if no connection + * exists (for example, connection attempts may be failing). Station mode can be + * re-enabled by calling `connect` or `scan`. * * @param {any} callback - An optional `callback()` function to be called back on disconnection. The callback function receives no argument. * @url http://www.espruino.com/Reference#l_Wifi_disconnect */ - disconnect(callback: any): any; + disconnect(callback: any): void; /** - * Stop being an access point and disable the AP operation mode. AP mode can be re-enabled by calling `startAP`. + * Stop being an access point and disable the AP operation mode. AP mode can be + * re-enabled by calling `startAP`. * * @param {any} callback - An optional `callback()` function to be called back on successful stop. The callback function receives no argument. * @url http://www.espruino.com/Reference#l_Wifi_stopAP */ - stopAP(callback: any): any; + stopAP(callback: any): void; /** - * Connect to an access point as a station. If there is an existing connection to an AP it is first disconnected if the SSID or password are different from those passed as parameters. Put differently, if the passed SSID and password are identical to the currently connected AP then nothing is changed. - * When the connection attempt completes the callback function is invoked with one `err` parameter, which is NULL if there is no error and a string message if there is an error. If DHCP is enabled the callback occurs once an IP addres has been obtained, if a static IP is set the callback occurs once the AP's network has been joined. The callback is also invoked if a connection already exists and does not need to be changed. + * Connect to an access point as a station. If there is an existing connection to + * an AP it is first disconnected if the SSID or password are different from those + * passed as parameters. Put differently, if the passed SSID and password are + * identical to the currently connected AP then nothing is changed. When the + * connection attempt completes the callback function is invoked with one `err` + * parameter, which is NULL if there is no error and a string message if there is + * an error. If DHCP is enabled the callback occurs once an IP addres has been + * obtained, if a static IP is set the callback occurs once the AP's network has + * been joined. The callback is also invoked if a connection already exists and + * does not need to be changed. * The options properties may contain: * * `password` - Password string to be used to access the network. - * * `dnsServers` (array of String) - An array of up to two DNS servers in dotted decimal format string. - * * `channel` - Wifi channel of the access point (integer, typ 0..14, 0 means any channel), only on ESP8266. - * * `bssid` - Mac address of the access point (string, type "00:00:00:00:00:00"), only on ESP8266. + * * `dnsServers` (array of String) - An array of up to two DNS servers in dotted + * decimal format string. + * * `channel` - Wifi channel of the access point (integer, typ 0..14, 0 means any + * channel), only on ESP8266. + * * `bssid` - Mac address of the access point (string, type "00:00:00:00:00:00"), + * only on ESP8266. * Notes: - * * the options should include the ability to set a static IP and associated netmask and gateway, this is a future enhancement. - * * the only error reported in the callback is "Bad password", all other errors (such as access point not found or DHCP timeout) just cause connection retries. If the reporting of such temporary errors is desired, the caller must use its own timeout and the `getDetails().status` field. - * * the `connect` call automatically enabled station mode, it can be disabled again by calling `disconnect`. + * * the options should include the ability to set a static IP and associated + * netmask and gateway, this is a future enhancement. + * * the only error reported in the callback is "Bad password", all other errors + * (such as access point not found or DHCP timeout) just cause connection + * retries. If the reporting of such temporary errors is desired, the caller must + * use its own timeout and the `getDetails().status` field. + * * the `connect` call automatically enabled station mode, it can be disabled + * again by calling `disconnect`. * * @param {any} ssid - The access point network id. * @param {any} options - Connection options (optional). * @param {any} callback - A `callback(err)` function to be called back on completion. `err` is null on success, or contains an error string on failure. * @url http://www.espruino.com/Reference#l_Wifi_connect */ - connect(ssid: any, options: any, callback: any): any; + connect(ssid: any, options: any, callback: any): void; /** - * Perform a scan for access points. This will enable the station mode if it is not currently enabled. Once the scan is complete the callback function is called with an array of APs found, each AP is an object with: + * Perform a scan for access points. This will enable the station mode if it is not + * currently enabled. Once the scan is complete the callback function is called + * with an array of APs found, each AP is an object with: * * `ssid`: SSID string. * * `mac`: access point MAC address in 00:00:00:00:00:00 format. * * `authMode`: `open`, `wep`, `wpa`, `wpa2`, or `wpa_wpa2`. @@ -11134,41 +12196,63 @@ type Libraries = { * * `hidden`: true if the SSID is hidden (ESP32/ESP8266 only) * * `rssi`: signal strength in dB in the range -110..0. * Notes: - * * in order to perform the scan the station mode is turned on and remains on, use Wifi.disconnect() to turn it off again, if desired. + * * in order to perform the scan the station mode is turned on and remains on, use + * Wifi.disconnect() to turn it off again, if desired. * * only one scan can be in progress at a time. * * @param {any} callback - A `callback(err, ap_list)` function to be called back on completion. `err==null` and `ap_list` is an array on success, or `err` is an error string and `ap_list` is undefined on failure. * @url http://www.espruino.com/Reference#l_Wifi_scan */ - scan(callback: any): any; + scan(callback: any): void; /** - * Create a WiFi access point allowing stations to connect. If the password is NULL or an empty string the access point is open, otherwise it is encrypted. - * The callback function is invoked once the access point is set-up and receives one `err` argument, which is NULL on success and contains an error message string otherwise. + * Create a WiFi access point allowing stations to connect. If the password is NULL + * or an empty string the access point is open, otherwise it is encrypted. The + * callback function is invoked once the access point is set-up and receives one + * `err` argument, which is NULL on success and contains an error message string + * otherwise. * The `options` object can contain the following properties. - * * `authMode` - The authentication mode to use. Can be one of "open", "wpa2", "wpa", "wpa_wpa2". The default is open (but open access points are not recommended). + * * `authMode` - The authentication mode to use. Can be one of "open", "wpa2", + * "wpa", "wpa_wpa2". The default is open (but open access points are not + * recommended). * * `password` - The password for connecting stations if authMode is not open. - * * `channel` - The channel to be used for the access point in the range 1..13. If the device is also connected to an access point as a station then that access point determines the channel. - * * `hidden` - The flag if visible or not (0:visible, 1:hidden), default is visible. + * * `channel` - The channel to be used for the access point in the range 1..13. If + * the device is also connected to an access point as a station then that access + * point determines the channel. + * * `hidden` - The flag if visible or not (0:visible, 1:hidden), default is + * visible. * Notes: - * * the options should include the ability to set the AP IP and associated netmask, this is a future enhancement. - * * the `startAP` call automatically enables AP mode. It can be disabled again by calling `stopAP`. + * * the options should include the ability to set the AP IP and associated + * netmask, this is a future enhancement. + * * the `startAP` call automatically enables AP mode. It can be disabled again by + * calling `stopAP`. * * @param {any} ssid - The network id. * @param {any} options - Configuration options (optional). * @param {any} callback - Optional `callback(err)` function to be called when the AP is successfully started. `err==null` on success, or an error string on failure. * @url http://www.espruino.com/Reference#l_Wifi_startAP */ - startAP(ssid: any, options: any, callback: any): any; + startAP(ssid: any, options: any, callback: any): void; /** - * Retrieve the current overall WiFi configuration. This call provides general information that pertains to both station and access point modes. The getDetails and getAPDetails calls provide more in-depth information about the station and access point configurations, respectively. The status object has the following properties: + * Retrieve the current overall WiFi configuration. This call provides general + * information that pertains to both station and access point modes. The getDetails + * and getAPDetails calls provide more in-depth information about the station and + * access point configurations, respectively. The status object has the following + * properties: * * `station` - Status of the wifi station: `off`, `connecting`, ... * * `ap` - Status of the wifi access point: `disabled`, `enabled`. * * `mode` - The current operation mode: `off`, `sta`, `ap`, `sta+ap`. - * * `phy` - Modulation standard configured: `11b`, `11g`, `11n` (the esp8266 docs are not very clear, but it is assumed that 11n means b/g/n). This setting limits the modulations that the radio will use, it does not indicate the current modulation used with a specific access point. - * * `powersave` - Power saving mode: `none` (radio is on all the time), `ps-poll` (radio is off between beacons as determined by the access point's DTIM setting). Note that in 'ap' and 'sta+ap' modes the radio is always on, i.e., no power saving is possible. - * * `savedMode` - The saved operation mode which will be applied at boot time: `off`, `sta`, `ap`, `sta+ap`. + * * `phy` - Modulation standard configured: `11b`, `11g`, `11n` (the esp8266 docs + * are not very clear, but it is assumed that 11n means b/g/n). This setting + * limits the modulations that the radio will use, it does not indicate the + * current modulation used with a specific access point. + * * `powersave` - Power saving mode: `none` (radio is on all the time), `ps-poll` + * (radio is off between beacons as determined by the access point's DTIM + * setting). Note that in 'ap' and 'sta+ap' modes the radio is always on, i.e., + * no power saving is possible. + * * `savedMode` - The saved operation mode which will be applied at boot time: + * `off`, `sta`, `ap`, `sta+ap`. * * @param {any} callback - Optional `callback(status)` function to be called back with the current Wifi status, i.e. the same object as returned directly. * @returns {any} An object representing the current WiFi status, if available immediately. @@ -11177,24 +12261,40 @@ type Libraries = { getStatus(callback: any): any; /** - * Sets a number of global wifi configuration settings. All parameters are optional and which are passed determines which settings are updated. - * The settings available are: - * * `phy` - Modulation standard to allow: `11b`, `11g`, `11n` (the esp8266 docs are not very clear, but it is assumed that 11n means b/g/n). - * * `powersave` - Power saving mode: `none` (radio is on all the time), `ps-poll` (radio is off between beacons as determined by the access point's DTIM setting). Note that in 'ap' and 'sta+ap' modes the radio is always on, i.e., no power saving is possible. - * Note: esp8266 SDK programmers may be missing an "opmode" option to set the sta/ap/sta+ap operation mode. Please use connect/scan/disconnect/startAP/stopAP, which all set the esp8266 opmode indirectly. + * Sets a number of global wifi configuration settings. All parameters are optional + * and which are passed determines which settings are updated. The settings + * available are: + * * `phy` - Modulation standard to allow: `11b`, `11g`, `11n` (the esp8266 docs + * are not very clear, but it is assumed that 11n means b/g/n). + * * `powersave` - Power saving mode: `none` (radio is on all the time), `ps-poll` + * (radio is off between beacons as determined by the access point's DTIM + * setting). Note that in 'ap' and 'sta+ap' modes the radio is always on, i.e., + * no power saving is possible. + * Note: esp8266 SDK programmers may be missing an "opmode" option to set the + * sta/ap/sta+ap operation mode. Please use connect/scan/disconnect/startAP/stopAP, + * which all set the esp8266 opmode indirectly. * * @param {any} settings - An object with the configuration settings to change. * @url http://www.espruino.com/Reference#l_Wifi_setConfig */ - setConfig(settings: any): any; + setConfig(settings: any): void; /** - * Retrieve the wifi station configuration and status details. The details object has the following properties: - * * `status` - Details about the wifi station connection, one of `off`, `connecting`, `wrong_password`, `no_ap_found`, `connect_fail`, or `connected`. The off, bad_password and connected states are stable, the other states are transient. The connecting state will either result in connected or one of the error states (bad_password, no_ap_found, connect_fail) and the no_ap_found and connect_fail states will result in a reconnection attempt after some interval. - * * `rssi` - signal strength of the connected access point in dB, typically in the range -110 to 0, with anything greater than -30 being an excessively strong signal. + * Retrieve the wifi station configuration and status details. The details object + * has the following properties: + * * `status` - Details about the wifi station connection, one of `off`, + * `connecting`, `wrong_password`, `no_ap_found`, `connect_fail`, or `connected`. + * The off, bad_password and connected states are stable, the other states are + * transient. The connecting state will either result in connected or one of the + * error states (bad_password, no_ap_found, connect_fail) and the no_ap_found and + * connect_fail states will result in a reconnection attempt after some interval. + * * `rssi` - signal strength of the connected access point in dB, typically in the + * range -110 to 0, with anything greater than -30 being an excessively strong + * signal. * * `ssid` - SSID of the access point. * * `password` - the password used to connect to the access point. - * * `authMode` - the authentication used: `open`, `wpa`, `wpa2`, `wpa_wpa2` (not currently supported). + * * `authMode` - the authentication used: `open`, `wpa`, `wpa2`, `wpa_wpa2` (not + * currently supported). * * `savedSsid` - the SSID to connect to automatically at boot time, null if none. * * @param {any} callback - An optional `callback(details)` function to be called back with the wifi details, i.e. the same object as returned directly. @@ -11204,15 +12304,20 @@ type Libraries = { getDetails(callback: any): any; /** - * Retrieve the current access point configuration and status. The details object has the following properties: + * Retrieve the current access point configuration and status. The details object + * has the following properties: * * `status` - Current access point status: `enabled` or `disabled` - * * `stations` - an array of the stations connected to the access point. This array may be empty. Each entry in the array is an object describing the station which, at a minimum contains `ip` being the IP address of the station. + * * `stations` - an array of the stations connected to the access point. This + * array may be empty. Each entry in the array is an object describing the + * station which, at a minimum contains `ip` being the IP address of the station. * * `ssid` - SSID to broadcast. * * `password` - Password for authentication. - * * `authMode` - the authentication required of stations: `open`, `wpa`, `wpa2`, `wpa_wpa2`. + * * `authMode` - the authentication required of stations: `open`, `wpa`, `wpa2`, + * `wpa_wpa2`. * * `hidden` - True if the SSID is hidden, false otherwise. * * `maxConn` - Max number of station connections supported. - * * `savedSsid` - the SSID to broadcast automatically at boot time, null if the access point is to be disabled at boot. + * * `savedSsid` - the SSID to broadcast automatically at boot time, null if the + * access point is to be disabled at boot. * * @param {any} callback - An optional `callback(details)` function to be called back with the current access point details, i.e. the same object as returned directly. * @returns {any} An object representing the current access point details, if available immediately. @@ -11221,8 +12326,12 @@ type Libraries = { getAPDetails(callback: any): any; /** - * On boards where this is not available, just issue the `connect` commands you need to run at startup from an `onInit` function. - * Save the current wifi configuration (station and access point) to flash and automatically apply this configuration at boot time, unless `what=="clear"`, in which case the saved configuration is cleared such that wifi remains disabled at boot. The saved configuration includes: + * On boards where this is not available, just issue the `connect` commands you + * need to run at startup from an `onInit` function. + * Save the current wifi configuration (station and access point) to flash and + * automatically apply this configuration at boot time, unless `what=="clear"`, in + * which case the saved configuration is cleared such that wifi remains disabled at + * boot. The saved configuration includes: * * mode (off/sta/ap/sta+ap) * * SSIDs & passwords * * phy (11b/g/n) @@ -11232,13 +12341,13 @@ type Libraries = { * @param {any} what - An optional parameter to specify what to save, on the esp8266 the two supported values are `clear` and `sta+ap`. The default is `sta+ap` * @url http://www.espruino.com/Reference#l_Wifi_save */ - save(what: any): any; + save(what: any): void; /** * Restores the saved Wifi configuration from flash. See `Wifi.save()`. * @url http://www.espruino.com/Reference#l_Wifi_restore */ - restore(): any; + restore(): void; /** * Return the station IP information in an object as follows: @@ -11268,17 +12377,20 @@ type Libraries = { getAPIP(callback: any): any; /** - * Lookup the hostname and invoke a callback with the IP address as integer argument. If the lookup fails, the callback is invoked with a null argument. - * **Note:** only a single hostname lookup can be made at a time, concurrent lookups are not supported. + * Lookup the hostname and invoke a callback with the IP address as integer + * argument. If the lookup fails, the callback is invoked with a null argument. + * **Note:** only a single hostname lookup can be made at a time, concurrent + * lookups are not supported. * * @param {any} hostname - The hostname to lookup. * @param {any} callback - The `callback(ip)` to invoke when the IP is returned. `ip==null` on failure. * @url http://www.espruino.com/Reference#l_Wifi_getHostByName */ - getHostByName(hostname: any, callback: any): any; + getHostByName(hostname: any, callback: any): void; /** - * Returns the hostname announced to the DHCP server and broadcast via mDNS when connecting to an access point. + * Returns the hostname announced to the DHCP server and broadcast via mDNS when + * connecting to an access point. * * @param {any} callback - An optional `callback(hostname)` function to be called back with the hostname. * @returns {any} The currently configured hostname, if available immediately. @@ -11287,84 +12399,96 @@ type Libraries = { getHostname(callback: any): any; /** - * Set the hostname. Depending on implemenation, the hostname is sent with every DHCP request and is broadcast via mDNS. The DHCP hostname may be visible in the access point and may be forwarded into DNS as hostname.local. - * If a DHCP lease currently exists changing the hostname will cause a disconnect and reconnect in order to transmit the change to the DHCP server. - * The mDNS announcement also includes an announcement for the "espruino" service. + * Set the hostname. Depending on implemenation, the hostname is sent with every + * DHCP request and is broadcast via mDNS. The DHCP hostname may be visible in the + * access point and may be forwarded into DNS as hostname.local. If a DHCP lease + * currently exists changing the hostname will cause a disconnect and reconnect in + * order to transmit the change to the DHCP server. The mDNS announcement also + * includes an announcement for the "espruino" service. * * @param {any} hostname - The new hostname. * @param {any} callback - An optional `callback()` function to be called back when the hostname is set * @url http://www.espruino.com/Reference#l_Wifi_setHostname */ - setHostname(hostname: any, callback: any): any; + setHostname(hostname: any, callback: any): void; /** - * Starts the SNTP (Simple Network Time Protocol) service to keep the clock synchronized with the specified server. Note that the time zone is really just an offset to UTC and doesn't handle daylight savings time. - * The interval determines how often the time server is queried and Espruino's time is synchronized. The initial synchronization occurs asynchronously after setSNTP returns. + * Starts the SNTP (Simple Network Time Protocol) service to keep the clock + * synchronized with the specified server. Note that the time zone is really just + * an offset to UTC and doesn't handle daylight savings time. The interval + * determines how often the time server is queried and Espruino's time is + * synchronized. The initial synchronization occurs asynchronously after setSNTP + * returns. * * @param {any} server - The NTP server to query, for example, `us.pool.ntp.org` * @param {any} tz_offset - Local time zone offset in the range -11..13. * @url http://www.espruino.com/Reference#l_Wifi_setSNTP */ - setSNTP(server: any, tz_offset: any): any; + setSNTP(server: any, tz_offset: any): void; /** * The `settings` object must contain the following properties. * * `ip` IP address as string (e.g. "192.168.5.100") - * * `gw` The network gateway as string (e.g. "192.168.5.1") + * * `gw` The network gateway as string (e.g. "192.168.5.1") * * `netmask` The interface netmask as string (e.g. "255.255.255.0") * * @param {any} settings - Configuration settings * @param {any} callback - A `callback(err)` function to invoke when ip is set. `err==null` on success, or a string on failure. * @url http://www.espruino.com/Reference#l_Wifi_setIP */ - setIP(settings: any, callback: any): any; + setIP(settings: any, callback: any): void; /** * The `settings` object must contain the following properties. * * `ip` IP address as string (e.g. "192.168.5.100") - * * `gw` The network gateway as string (e.g. "192.168.5.1") + * * `gw` The network gateway as string (e.g. "192.168.5.1") * * `netmask` The interface netmask as string (e.g. "255.255.255.0") * * @param {any} settings - Configuration settings * @param {any} callback - A `callback(err)` function to invoke when ip is set. `err==null` on success, or a string on failure. * @url http://www.espruino.com/Reference#l_Wifi_setAPIP */ - setAPIP(settings: any, callback: any): any; + setAPIP(settings: any, callback: any): void; /** - * Issues a ping to the given host, and calls a callback with the time when the ping is received. + * Issues a ping to the given host, and calls a callback with the time when the + * ping is received. * * @param {any} hostname - The host to ping * @param {any} callback - A `callback(time)` function to invoke when a ping is received * @url http://www.espruino.com/Reference#l_Wifi_ping */ - ping(hostname: any, callback: any): any; + ping(hostname: any, callback: any): void; /** * Switch to using a higher communication speed with the WiFi module. * * `true` = 921600 baud * * `false` = 115200 - * * `1843200` (or any number) = use a specific baud rate. - * * - * eg. `wifi.turbo(true,callback)` or `wifi.turbo(1843200,callback)` + * * `1843200` (or any number) = use a specific baud rate. * eg. + * `wifi.turbo(true,callback)` or `wifi.turbo(1843200,callback)` * * @param {any} enable - true (or a baud rate as a number) to enable, false to disable * @param {any} callback - A `callback()` function to invoke when turbo mode has been set * @url http://www.espruino.com/Reference#l_Wifi_turbo */ - turbo(enable: any, callback: any): any; + turbo(enable: any, callback: any): void; } /** * This library allows you to create http servers and make http requests - * In order to use this, you will need an extra module to get network connectivity such as the [TI CC3000](/CC3000) or [WIZnet W5500](/WIZnet). - * This is designed to be a cut-down version of the [node.js library](http://nodejs.org/api/http.html). Please see the [Internet](/Internet) page for more information on how to use it. + * In order to use this, you will need an extra module to get network connectivity + * such as the [TI CC3000](/CC3000) or [WIZnet W5500](/WIZnet). + * This is designed to be a cut-down version of the [node.js + * library](http://nodejs.org/api/http.html). Please see the [Internet](/Internet) + * page for more information on how to use it. * @url http://www.espruino.com/Reference#http */ http: { /** * Create an HTTP Server - * When a request to the server is made, the callback is called. In the callback you can use the methods on the response (`httpSRs`) to send data. You can also add `request.on('data',function() { ... })` to listen for POSTed data + * When a request to the server is made, the callback is called. In the callback + * you can use the methods on the response (`httpSRs`) to send data. You can also + * add `request.on('data',function() { ... })` to listen for POSTed data * * @param {any} callback - A function(request,response) that will be called when a connection is made * @returns {any} Returns a new httpSrv object @@ -11373,7 +12497,8 @@ type Libraries = { createServer(callback: any): httpSrv; /** - * Create an HTTP Request - `end()` must be called on it to complete the operation. `options` is of the form: + * Create an HTTP Request - `end()` must be called on it to complete the operation. + * `options` is of the form: * ``` * var options = { * host: 'example.com', // host name @@ -11394,10 +12519,12 @@ type Libraries = { * // You can req.write(...) here if your request requires data to be sent. * req.end(); // called to finish the HTTP request and get the response * ``` - * You can easily pre-populate `options` from a URL using `var options = url.parse("http://www.example.com/foo.html")` - * There's an example of using [`http.request` for HTTP POST here](/Internet#http-post) - * **Note:** if TLS/HTTPS is enabled, options can have `ca`, `key` and `cert` fields. See `tls.connect` for - * more information about these and how to use them. + * You can easily pre-populate `options` from a URL using `var options = + * url.parse("http://www.example.com/foo.html")` + * There's an example of using [`http.request` for HTTP POST + * here](/Internet#http-post) + * **Note:** if TLS/HTTPS is enabled, options can have `ca`, `key` and `cert` + * fields. See `tls.connect` for more information about these and how to use them. * * @param {any} options - An object containing host,port,path,method,headers fields (and also ca,key,cert if HTTPS is enabled) * @param {any} callback - A function(res) that will be called when a connection is made. You can then call `res.on('data', function(data) { ... })` and `res.on('close', function() { ... })` to deal with the response. @@ -11407,7 +12534,8 @@ type Libraries = { request(options: any, callback: any): httpCRq; /** - * Request a webpage over HTTP - a convenience function for `http.request()` that makes sure the HTTP command is 'GET', and that calls `end` automatically. + * Request a webpage over HTTP - a convenience function for `http.request()` that + * makes sure the HTTP command is 'GET', and that calls `end` automatically. * ``` * require("http").get("http://pur3.co.uk/hello.txt", function(res) { * res.on('data', function(data) { @@ -11418,7 +12546,8 @@ type Libraries = { * }); * }); * ``` - * See `http.request()` and [the Internet page](/Internet) and ` for more usage examples. + * See `http.request()` and [the Internet page](/Internet) and ` for more usage + * examples. * * @param {any} options - A simple URL, or an object containing host,port,path,method fields * @param {any} callback - A function(res) that will be called when a connection is made. You can then call `res.on('data', function(data) { ... })` and `res.on('close', function() { ... })` to deal with the response. @@ -11477,9 +12606,15 @@ type Libraries = { } /** - * Simple library for compression/decompression using [heatshrink](https://github.com/atomicobject/heatshrink), an [LZSS](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Storer%E2%80%93Szymanski) compression tool. - * Espruino uses heatshrink internally to compress RAM down to fit in Flash memory when `save()` is used. This just exposes that functionality. - * Functions here take and return buffers of data. There is no support for streaming, so both the compressed and decompressed data must be able to fit in memory at the same time. + * Simple library for compression/decompression using + * [heatshrink](https://github.com/atomicobject/heatshrink), an + * [LZSS](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Storer%E2%80%93Szymanski) + * compression tool. + * Espruino uses heatshrink internally to compress RAM down to fit in Flash memory + * when `save()` is used. This just exposes that functionality. + * Functions here take and return buffers of data. There is no support for + * streaming, so both the compressed and decompressed data must be able to fit in + * memory at the same time. * @url http://www.espruino.com/Reference#heatshrink */ heatshrink: { @@ -11508,8 +12643,8 @@ type Libraries = { */ neopixel: { /** - * Write to a strip of NeoPixel/WS281x/APA104/APA106/SK6812-style LEDs - * attached to the given pin. + * Write to a strip of NeoPixel/WS281x/APA104/APA106/SK6812-style LEDs attached to + * the given pin. * ``` * // set just one pixel, red, green, blue * require("neopixel").write(B15, [255,0,0]); @@ -11532,77 +12667,76 @@ type Libraries = { * }, 100); * ``` * **Note:** - * * Different types of LED have the data in different orders - so don't - * be surprised by RGB or BGR orderings! - * * Some LED strips (SK6812) actually take 4 bytes per LED (red, green, blue and white). - * These are still supported but the array of data supplied must still be a multiple of 3 - * bytes long. Just round the size up - it won't cause any problems. - * * On some platforms like STM32, pins capable of hardware SPI MOSI - * are required. - * * Espruino devices tend to have 3.3v IO, while WS2812/etc run - * off of 5v. Many WS2812 will only register a logic '1' at 70% - * of their input voltage - so if powering them off 5v you will not - * be able to send them data reliably. You can work around this by - * powering the LEDs off a lower voltage (for example 3.7v from a LiPo - * battery), can put the output into the `af_opendrain` state and use - * a pullup resistor to 5v on STM32 based boards (nRF52 are not 5v tolerant - * so you can't do this), or can use a level shifter to shift the voltage up - * into the 5v range. + * * Different types of LED have the data in different orders - so don't be + * surprised by RGB or BGR orderings! + * * Some LED strips (SK6812) actually take 4 bytes per LED (red, green, blue and + * white). These are still supported but the array of data supplied must still be a + * multiple of 3 bytes long. Just round the size up - it won't cause any problems. + * * On some platforms like STM32, pins capable of hardware SPI MOSI are required. + * * Espruino devices tend to have 3.3v IO, while WS2812/etc run off of 5v. Many + * WS2812 will only register a logic '1' at 70% of their input voltage - so if + * powering them off 5v you will not be able to send them data reliably. You can + * work around this by powering the LEDs off a lower voltage (for example 3.7v from + * a LiPo battery), can put the output into the `af_opendrain` state and use a + * pullup resistor to 5v on STM32 based boards (nRF52 are not 5v tolerant so you + * can't do this), or can use a level shifter to shift the voltage up into the 5v + * range. * * @param {Pin} pin - The Pin the LEDs are connected to * @param {any} data - The data to write to the LED strip (must be a multiple of 3 bytes long) * @url http://www.espruino.com/Reference#l_neopixel_write */ - write(pin: Pin, data: any): any; + write(pin: Pin, data: any): void; } /** - * This module allows you to read and write part of the nonvolatile flash - * memory of your device using a filesystem-like API. - * Also see the `Flash` library, which provides a low level, more dangerous way - * to access all parts of your flash memory. + * This module allows you to read and write part of the nonvolatile flash memory of + * your device using a filesystem-like API. + * Also see the `Flash` library, which provides a low level, more dangerous way to + * access all parts of your flash memory. * The `Storage` library provides two distinct types of file: - * * `require("Storage").write(...)`/`require("Storage").read(...)`/etc create simple - * contiguous files of fixed length. This is the recommended file type. - * * `require("Storage").open(...)` creates a `StorageFile`, which stores the file in - * numbered chunks (`"filename\1"`/`"filename\2"`/etc). It allows data to be appended - * and for the file to be read line by line. - * You must read a file using the same method you used to write it - eg. you can't create a - * file with `require("Storage").open(...)` and then read it with `require("Storage").read(...)`. - * **Note:** In firmware 2v05 and later, the maximum length for filenames - * is 28 characters. However in 2v04 and earlier the max length is 8. + * * `require("Storage").write(...)`/`require("Storage").read(...)`/etc create + * simple contiguous files of fixed length. This is the recommended file type. + * * `require("Storage").open(...)` creates a `StorageFile`, which stores the file + * in numbered chunks (`"filename\1"`/`"filename\2"`/etc). It allows data to be + * appended and for the file to be read line by line. + * You must read a file using the same method you used to write it - eg. you can't + * create a file with `require("Storage").open(...)` and then read it with + * `require("Storage").read(...)`. + * **Note:** In firmware 2v05 and later, the maximum length for filenames is 28 + * characters. However in 2v04 and earlier the max length is 8. * @url http://www.espruino.com/Reference#Storage */ Storage: { /** - * Erase the flash storage area. This will remove all files - * created with `require("Storage").write(...)` as well - * as any code saved with `save()` or `E.setBootCode()`. + * Erase the flash storage area. This will remove all files created with + * `require("Storage").write(...)` as well as any code saved with `save()` or + * `E.setBootCode()`. * @url http://www.espruino.com/Reference#l_Storage_eraseAll */ - eraseAll(): any; + eraseAll(): void; /** * Erase a single file from the flash storage area. - * **Note:** This function should be used with normal files, and not - * `StorageFile`s created with `require("Storage").open(filename, ...)` + * **Note:** This function should be used with normal files, and not `StorageFile`s + * created with `require("Storage").open(filename, ...)` * * @param {any} name - The filename - max 28 characters (case sensitive) * @url http://www.espruino.com/Reference#l_Storage_erase */ - erase(name: any): any; + erase(name: string): void; /** - * Read a file from the flash storage area that has - * been written with `require("Storage").write(...)`. - * This function returns a memory-mapped String that points to the actual - * memory area in read-only memory, so it won't use up RAM. - * As such you can check if a file exists efficiently using `require("Storage").read(filename)!==undefined`. - * If you evaluate this string with `eval`, any functions - * contained in the String will keep their code stored - * in flash memory. - * **Note:** This function should be used with normal files, and not - * `StorageFile`s created with `require("Storage").open(filename, ...)` + * Read a file from the flash storage area that has been written with + * `require("Storage").write(...)`. + * This function returns a memory-mapped String that points to the actual memory + * area in read-only memory, so it won't use up RAM. + * As such you can check if a file exists efficiently using + * `require("Storage").read(filename)!==undefined`. + * If you evaluate this string with `eval`, any functions contained in the String + * will keep their code stored in flash memory. + * **Note:** This function should be used with normal files, and not `StorageFile`s + * created with `require("Storage").open(filename, ...)` * * @param {any} name - The filename - max 28 characters (case sensitive) * @param {number} offset - (optional) The offset in bytes to start from @@ -11610,56 +12744,54 @@ type Libraries = { * @returns {any} A string of data, or `undefined` if the file is not found * @url http://www.espruino.com/Reference#l_Storage_read */ - read(name: any, offset: number, length: number): any; + read(name: string, offset?: number, length?: number): string | undefined; /** - * Read a file from the flash storage area that has - * been written with `require("Storage").write(...)`, - * and parse JSON in it into a JavaScript object. - * This is identical to `JSON.parse(require("Storage").read(...))`. - * It will throw an exception if the data in the file is not - * valid JSON. - * **Note:** This function should be used with normal files, and not - * `StorageFile`s created with `require("Storage").open(filename, ...)` + * Read a file from the flash storage area that has been written with + * `require("Storage").write(...)`, and parse JSON in it into a JavaScript object. + * This is identical to `JSON.parse(require("Storage").read(...))`. It will throw + * an exception if the data in the file is not valid JSON. + * **Note:** This function should be used with normal files, and not `StorageFile`s + * created with `require("Storage").open(filename, ...)` * * @param {any} name - The filename - max 28 characters (case sensitive) * @param {boolean} noExceptions - If true and the JSON is not valid, just return `undefined` - otherwise an `Exception` is thrown * @returns {any} An object containing parsed JSON from the file, or undefined * @url http://www.espruino.com/Reference#l_Storage_readJSON */ - readJSON(name: any, noExceptions: boolean): any; + readJSON(name: string, noExceptions: boolean): any; /** - * Read a file from the flash storage area that has - * been written with `require("Storage").write(...)`, - * and return the raw binary data as an ArrayBuffer. + * Read a file from the flash storage area that has been written with + * `require("Storage").write(...)`, and return the raw binary data as an + * ArrayBuffer. * This can be used: * * In a `DataView` with `new DataView(require("Storage").readArrayBuffer("x"))` - * * In a `Uint8Array/Float32Array/etc` with `new Uint8Array(require("Storage").readArrayBuffer("x"))` - * **Note:** This function should be used with normal files, and not - * `StorageFile`s created with `require("Storage").open(filename, ...)` + * * In a `Uint8Array/Float32Array/etc` with `new + * Uint8Array(require("Storage").readArrayBuffer("x"))` + * **Note:** This function should be used with normal files, and not `StorageFile`s + * created with `require("Storage").open(filename, ...)` * * @param {any} name - The filename - max 28 characters (case sensitive) * @returns {any} An ArrayBuffer containing data from the file, or undefined * @url http://www.espruino.com/Reference#l_Storage_readArrayBuffer */ - readArrayBuffer(name: any): any; + readArrayBuffer(name: string): ArrayBuffer | undefined; /** - * Write/create a file in the flash storage area. This is - * nonvolatile and will not disappear when the device resets - * or power is lost. - * Simply write `require("Storage").write("MyFile", "Some data")` to write - * a new file, and `require("Storage").read("MyFile")` to read it. + * Write/create a file in the flash storage area. This is nonvolatile and will not + * disappear when the device resets or power is lost. + * Simply write `require("Storage").write("MyFile", "Some data")` to write a new + * file, and `require("Storage").read("MyFile")` to read it. * If you supply: * * A String, it will be written as-is * * An array, will be written as a byte array (but read back as a String) - * * An object, it will automatically be converted to - * a JSON string before being written. - * **Note:** If an array is supplied it will not be converted to JSON. - * To be explicit about the conversion you can use `Storage.writeJSON` - * You may also create a file and then populate data later **as long as you - * don't try and overwrite data that already exists**. For instance: + * * An object, it will automatically be converted to a JSON string before being + * written. + * **Note:** If an array is supplied it will not be converted to JSON. To be + * explicit about the conversion you can use `Storage.writeJSON` + * You may also create a file and then populate data later **as long as you don't + * try and overwrite data that already exists**. For instance: * ``` * var f = require("Storage"); * f.write("a","Hello",0,14); @@ -11669,11 +12801,11 @@ type Libraries = { * f.write("a"," ",0); // Writing to location 0 again will cause the file to be re-written * print(f.read("a")); // " " * ``` - * This can be useful if you've got more data to write than you - * have RAM available - for instance the Web IDE uses this method - * to write large files into onboard storage. - * **Note:** This function should be used with normal files, and not - * `StorageFile`s created with `require("Storage").open(filename, ...)` + * This can be useful if you've got more data to write than you have RAM + * available - for instance the Web IDE uses this method to write large files into + * onboard storage. + * **Note:** This function should be used with normal files, and not `StorageFile`s + * created with `require("Storage").open(filename, ...)` * * @param {any} name - The filename - max 28 characters (case sensitive) * @param {any} data - The data to write @@ -11682,24 +12814,23 @@ type Libraries = { * @returns {boolean} True on success, false on failure * @url http://www.espruino.com/Reference#l_Storage_write */ - write(name: any, data: any, offset?: number, size?: number): boolean; + write(name: string | ArrayBuffer | ArrayBufferView | number[] | object, data: any, offset?: number, size?: number): boolean; /** - * Write/create a file in the flash storage area. This is - * nonvolatile and will not disappear when the device resets - * or power is lost. - * Simply write `require("Storage").writeJSON("MyFile", [1,2,3])` to write - * a new file, and `require("Storage").readJSON("MyFile")` to read it. + * Write/create a file in the flash storage area. This is nonvolatile and will not + * disappear when the device resets or power is lost. + * Simply write `require("Storage").writeJSON("MyFile", [1,2,3])` to write a new + * file, and `require("Storage").readJSON("MyFile")` to read it. * This is equivalent to: `require("Storage").write(name, JSON.stringify(data))` - * **Note:** This function should be used with normal files, and not - * `StorageFile`s created with `require("Storage").open(filename, ...)` + * **Note:** This function should be used with normal files, and not `StorageFile`s + * created with `require("Storage").open(filename, ...)` * * @param {any} name - The filename - max 28 characters (case sensitive) * @param {any} data - The JSON data to write * @returns {boolean} True on success, false on failure * @url http://www.espruino.com/Reference#l_Storage_writeJSON */ - writeJSON(name: any, data: any): boolean; + writeJSON(name: string, data: any): boolean; /** * List all files in the flash storage area. An array of Strings is returned. @@ -11715,69 +12846,65 @@ type Libraries = { * // All normal files (eg created with Storage.write) * require("Storage").list(undefined, {sf:false}) * ``` - * **Note:** This will output system files (eg. saved code) as well as - * files that you may have written. + * **Note:** This will output system files (eg. saved code) as well as files that + * you may have written. * * @param {any} regex - (optional) If supplied, filenames are checked against this regular expression (with `String.match(regexp)`) to see if they match before being returned * @param {any} filter - (optional) If supplied, File Types are filtered based on this: `{sf:true}` or `{sf:false}` for whether to show StorageFile * @returns {any} An array of filenames * @url http://www.espruino.com/Reference#l_Storage_list */ - list(regex: any, filter: any): any; + list(regex?: RegExp, filter?: { sf: boolean }): string[]; /** - * List all files in the flash storage area matching the specfied regex (ignores StorageFiles), - * and then hash their filenames *and* file locations. - * Identical files may have different hashes (eg. if Storage is compacted and the file moves) but - * the changes of different files having the same hash are extremely small. + * List all files in the flash storage area matching the specfied regex (ignores + * StorageFiles), and then hash their filenames *and* file locations. + * Identical files may have different hashes (eg. if Storage is compacted and the + * file moves) but the changes of different files having the same hash are + * extremely small. * ``` * // Hash files * require("Storage").hash() * // Files ending in '.boot.js' * require("Storage").hash(/\.boot\.js$/) * ``` - * **Note:** This function is used by Bangle.js as a way to cache files. - * For instance the bootloader will add all `.boot.js` files together into - * a single `.boot0` file, but it needs to know quickly whether anything has - * changed. + * **Note:** This function is used by Bangle.js as a way to cache files. For + * instance the bootloader will add all `.boot.js` files together into a single + * `.boot0` file, but it needs to know quickly whether anything has changed. * * @param {any} regex - (optional) If supplied, filenames are checked against this regular expression (with `String.match(regexp)`) to see if they match before being hashed * @returns {number} A hash of the files matching * @url http://www.espruino.com/Reference#l_Storage_hash */ - hash(regex: any): number; + hash(regex: RegExp): number; /** - * The Flash Storage system is journaling. To make the most of the limited - * write cycles of Flash memory, Espruino marks deleted/replaced files as - * garbage and moves on to a fresh part of flash memory. Espruino only - * fully erases those files when it is running low on flash, or when - * `compact` is called. - * `compact` may fail if there isn't enough RAM free on the stack to - * use as swap space, however in this case it will not lose data. - * **Note:** `compact` rearranges the contents of memory. If code is - * referencing that memory (eg. functions that have their code stored in flash) - * then they may become garbled when compaction happens. To avoid this, - * call `eraseFiles` before uploading data that you intend to reference to - * ensure that uploaded files are right at the start of flash and cannot be - * compacted further. + * The Flash Storage system is journaling. To make the most of the limited write + * cycles of Flash memory, Espruino marks deleted/replaced files as garbage and + * moves on to a fresh part of flash memory. Espruino only fully erases those files + * when it is running low on flash, or when `compact` is called. + * `compact` may fail if there isn't enough RAM free on the stack to use as swap + * space, however in this case it will not lose data. + * **Note:** `compact` rearranges the contents of memory. If code is referencing + * that memory (eg. functions that have their code stored in flash) then they may + * become garbled when compaction happens. To avoid this, call `eraseFiles` before + * uploading data that you intend to reference to ensure that uploaded files are + * right at the start of flash and cannot be compacted further. * @url http://www.espruino.com/Reference#l_Storage_compact */ - compact(): any; + compact(): void; /** - * This writes information about all blocks in flash - * memory to the console - and is only useful for debugging - * flash storage. + * This writes information about all blocks in flash memory to the console - and is + * only useful for debugging flash storage. * @url http://www.espruino.com/Reference#l_Storage_debug */ - debug(): any; + debug(): void; /** - * Return the amount of free bytes available in - * Storage. Due to fragmentation there may be more - * bytes available, but this represents the maximum - * size of file that can be written. + * Return the amount of free bytes available in Storage. Due to fragmentation there + * may be more bytes available, but this represents the maximum size of file that + * can be written. * @returns {number} The amount of free bytes * @url http://www.espruino.com/Reference#l_Storage_getFree */ @@ -11801,11 +12928,11 @@ type Libraries = { getStats(): any; /** - * Writes a lookup table for files into Bangle.js's storage. This allows any file stored - * up to that point to be accessed quickly. + * Writes a lookup table for files into Bangle.js's storage. This allows any file + * stored up to that point to be accessed quickly. * @url http://www.espruino.com/Reference#l_Storage_optimise */ - optimise(): any; + optimise(): void; /** * Open a file in the Storage area. This can be used for appending data @@ -11818,22 +12945,24 @@ type Libraries = { * @returns {any} An object containing {read,write,erase} * @url http://www.espruino.com/Reference#l_Storage_open */ - open(name: any, mode: any): StorageFile; + open(name: string, mode: "r" | "w" | "a"): StorageFile; } /** - * This module allows you to read and write the nonvolatile flash memory of your device. - * Also see the `Storage` library, which provides a safer file-like - * interface to nonvolatile storage. - * It should be used with extreme caution, as it is easy to overwrite parts of Flash - * memory belonging to Espruino or even its bootloader. If you damage the bootloader - * then you may need external hardware such as a USB-TTL converter to restore it. For - * more information on restoring the bootloader see `Advanced Reflashing` in your - * board's reference pages. + * This module allows you to read and write the nonvolatile flash memory of your + * device. + * Also see the `Storage` library, which provides a safer file-like interface to + * nonvolatile storage. + * It should be used with extreme caution, as it is easy to overwrite parts of + * Flash memory belonging to Espruino or even its bootloader. If you damage the + * bootloader then you may need external hardware such as a USB-TTL converter to + * restore it. For more information on restoring the bootloader see `Advanced + * Reflashing` in your board's reference pages. * To see which areas of memory you can and can't overwrite, look at the values * reported by `process.memory()`. * **Note:** On Nordic platforms there are checks in place to help you avoid - * 'bricking' your device be damaging the bootloader. You can disable these with `E.setFlags({unsafeFlash:1})` + * 'bricking' your device be damaging the bootloader. You can disable these with + * `E.setFlags({unsafeFlash:1})` * @url http://www.espruino.com/Reference#Flash */ Flash: { @@ -11847,11 +12976,12 @@ type Libraries = { getPage(addr: number): any; /** - * This method returns an array of objects of the form `{addr : #, length : #}`, representing - * contiguous areas of flash memory in the chip that are not used for anything. - * The memory areas returned are on page boundaries. This means that you can - * safely erase the page containing any address here, and you won't risk - * deleting part of the Espruino firmware. + * This method returns an array of objects of the form `{addr : #, length : #}`, + * representing contiguous areas of flash memory in the chip that are not used for + * anything. + * The memory areas returned are on page boundaries. This means that you can safely + * erase the page containing any address here, and you won't risk deleting part of + * the Espruino firmware. * @returns {any} Array of objects with `addr` and `length` properties * @url http://www.espruino.com/Reference#l_Flash_getFree */ @@ -11863,20 +12993,20 @@ type Libraries = { * @param {any} addr - An address in the page that is to be erased * @url http://www.espruino.com/Reference#l_Flash_erasePage */ - erasePage(addr: any): any; + erasePage(addr: any): void; /** * Write data into memory at the given address * In flash memory you may only turn bits that are 1 into bits that are 0. If * you're writing data into an area that you have already written (so `read` - * doesn't return all `0xFF`) you'll need to call `erasePage` to clear the - * entire page. + * doesn't return all `0xFF`) you'll need to call `erasePage` to clear the entire + * page. * * @param {any} data - The data to write * @param {number} addr - The address to start writing from * @url http://www.espruino.com/Reference#l_Flash_write */ - write(data: any, addr: number): any; + write(data: any, addr: number): void; /** * Read flash memory from the given address diff --git a/typescript/types/other.d.ts b/typescript/types/other.d.ts index 1f08c912f..2a58b9fe1 100644 --- a/typescript/types/other.d.ts +++ b/typescript/types/other.d.ts @@ -1,14 +1,3 @@ -// Bangle.js globals -declare const g: Graphics; - -type WidgetArea = "tl" | "tr" | "bl" | "br"; -type Widget = { - area: WidgetArea; - width: number; - draw: (this: { x: number; y: number }) => void; -}; -declare const WIDGETS: { [key: string]: Widget }; - // Required for TypeScript to work properly interface NewableFunction extends Function {} interface CallableFunction extends Function {}