Merge branch 'espruino:master' into rescalc

master
stweedo 2023-05-18 12:09:29 -05:00 committed by GitHub
commit c1f103eea7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 390 additions and 103 deletions

View File

@ -6,3 +6,4 @@
0.06: ClockInfo Fix: Use .get instead of .show as .show is not implemented for weather etc. 0.06: ClockInfo Fix: Use .get instead of .show as .show is not implemented for weather etc.
0.07: Use clock_info.addInteractive instead of a custom implementation 0.07: Use clock_info.addInteractive instead of a custom implementation
0.08: Use clock_info module as an app 0.08: Use clock_info module as an app
0.09: clock_info now uses app name to maintain settings specifically for this clock face

View File

@ -193,6 +193,7 @@ function queueDraw() {
*/ */
let clockInfoItems = clock_info.load(); let clockInfoItems = clock_info.load();
let clockInfoMenu = clock_info.addInteractive(clockInfoItems, { let clockInfoMenu = clock_info.addInteractive(clockInfoItems, {
app : "aiclock",
x : 0, x : 0,
y: 0, y: 0,
w: W, w: W,

View File

@ -3,7 +3,7 @@
"name": "AI Clock", "name": "AI Clock",
"shortName":"AI Clock", "shortName":"AI Clock",
"icon": "aiclock.png", "icon": "aiclock.png",
"version":"0.08", "version":"0.09",
"readme": "README.md", "readme": "README.md",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],
"dependencies" : { "clock_info":"module" }, "dependencies" : { "clock_info":"module" },

View File

@ -3,6 +3,7 @@
"version":"0.01", "version":"0.01",
"description": "For clocks that display 'clockinfo' (messages that can be cycled through using the clock_info module) this displays the day of the month in the icon, and the weekday", "description": "For clocks that display 'clockinfo' (messages that can be cycled through using the clock_info module) this displays the day of the month in the icon, and the weekday",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clkinfo", "type": "clkinfo",
"tags": "clkinfo,calendar", "tags": "clkinfo,calendar",
"supports" : ["BANGLEJS2"], "supports" : ["BANGLEJS2"],

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1 +1,3 @@
0.01: New app! 0.01: New app!
0.02: Add sensor icons
Customize code directly, remove config file

View File

@ -1,5 +1,5 @@
(function () { (function () {
const sb = () => require('hasensors').sendBattery(); const sb = () => require("hasensors").sendBattery();
Bangle.on("charging", sb); Bangle.on("charging", sb);
NRF.on("connect", () => setTimeout(sb, 2000)); NRF.on("connect", () => setTimeout(sb, 2000));
setInterval(sb, 10 * 60 * 1000); setInterval(sb, 10 * 60 * 1000);

View File

@ -39,14 +39,27 @@
<a href="https://my.home-assistant.io/redirect/profile/" target="_blank">your user profile</a>.</span></label> <a href="https://my.home-assistant.io/redirect/profile/" target="_blank">your user profile</a>.</span></label>
</form> </form>
<p> <p>
<button id="upload" class="btn btn-primary">Upload</button> <button id="upload" class="btn btn-primary" disabled>Upload</button>
</p> </p>
<script src="../../core/lib/customize.js"></script> <script src="../../core/lib/customize.js"></script>
<script> <script>
const STORAGE_KEY = 'hasensors-config'; const STORAGE_KEY = "hasensors-config";
const fields = ['id', 'name', 'url', 'token']; const fields = ["id", "name", "url", "token"];
const form = document.getElementById('sensorform'); const form = document.getElementById("sensorform");
const LIBRARY_URL = "./lib.js";
// fetch library code template, enable upload button once we"ve got it
let libTpl;
fetch(LIBRARY_URL).then(response=>{
if (! response.ok) return;
console.log(response);
response.text().then(code=>{
libTpl = code;
document.getElementById("upload").disabled = false;
});
});
// try to pre-fill form with values previously saved in localStorage
let stored = localStorage.getItem(STORAGE_KEY); let stored = localStorage.getItem(STORAGE_KEY);
if (stored) { if (stored) {
try { try {
@ -62,7 +75,7 @@
} }
document.getElementById("upload").addEventListener("click", function () { document.getElementById("upload").addEventListener("click", function () {
let config = {}; // validate form fields or bail out
for (const field of fields) { for (const field of fields) {
if (!form[field].validity.valid) { if (!form[field].validity.valid) {
form[field].focus(); form[field].focus();
@ -70,18 +83,21 @@
return; return;
} }
} }
let config = {};
for (const field of fields) { for (const field of fields) {
config[field] = form[field].value config[field] = form[field].value;
} }
console.log('config:', config, JSON.stringify(config)); // save config to localStorage for re-use next time
localStorage.setItem(STORAGE_KEY, JSON.stringify(config)); localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
// replace {placeholders} in library code template
const lib = libTpl.replace(/\{(\w+)\}/g, (_,f) => config[f]);
console.log("config:", config, JSON.stringify(config));
sendCustomizedApp({ sendCustomizedApp({
id: "hasensors", id: "hasensors",
storage: [ storage: [
{name: "hasensors.boot.js", url: "boot.js"}, {name: "hasensors.boot.js", url: "boot.js"},
{name: "hasensors", url: "lib.js"}, {name: "hasensors", content: lib},
{name: "hasensors.settings.json", content: JSON.stringify(config)}, ],
]
}); });
}); });
</script> </script>

View File

@ -1,35 +1,43 @@
// split out into a separate file to keep bootcode short. // split out into a separate file to keep bootcode short.
function s(key) { // placeholders are replaced by custom.html before upload
return (require('Storage').readJSON('hasensors.settings.js', true) || {})[key];
}
function post(sensor, data) { function post(sensor, data) {
const url = s('url') + '/api/states/sensor.' + s('id') + '_' + sensor; const url = "{url}/api/states/sensor.{id}_" + sensor;
Bangle.http(url, { Bangle.http(url, {
method: 'POST', method: "POST",
body: JSON.stringify(data), body: JSON.stringify(data),
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: 'Bearer ' + s('token'), Authorization: "Bearer {token}",
} }
}); });
} }
exports.sendBattery = function () { exports.sendBattery = function () {
if (!NRF.getSecurityStatus().connected) return; if (!NRF.getSecurityStatus().connected) return;
post('battery_level', { const b = E.getBattery(),
state: E.getBattery(), c = Bangle.isCharging();
let i = "mdi:battery";
if (c) i += "-charging";
post("battery_state", {
state: c ? "charging" : "discharging",
attributes: { attributes: {
friendly_name: s('name') + " Battery Level", friendly_name: "{name} Battery State",
icon: i + (c ? "" : "-minus"),
}
});
if (b<10) i += "-outline"; // there is no battery-0
else if (b<100 || c) i += "-" + Math.floor(b/10)*10; // no battery-100 either
post("battery_level", {
state: b,
attributes: {
friendly_name: "{name} Battery Level",
unit_of_measurement: "%", unit_of_measurement: "%",
device_class: "battery", device_class: "battery",
state_class: "measurement", state_class: "measurement",
} icon: i,
});
post('battery_state', {
state: Bangle.isCharging() ? 'charging' : 'discharging',
attributes: {
friendly_name: s('name') + " Battery State",
} }
}); });
} }

View File

@ -2,7 +2,7 @@
"id": "hasensors", "id": "hasensors",
"name": "Home Assistant Sensors", "name": "Home Assistant Sensors",
"shortName": "HA sensors", "shortName": "HA sensors",
"version": "0.01", "version": "0.02",
"description": "Send sensor values to Home Assistant using the Android Integration.", "description": "Send sensor values to Home Assistant using the Android Integration.",
"icon": "ha.png", "icon": "ha.png",
"type": "bootloader", "type": "bootloader",
@ -14,8 +14,5 @@
"storage": [ "storage": [
{"name":"hasensors","url":"lib.js"}, {"name":"hasensors","url":"lib.js"},
{"name":"hasensors.boot.js","url":"boot.js"} {"name":"hasensors.boot.js","url":"boot.js"}
],
"data": [
{"name":"hasensors.settings.json"}
] ]
} }

View File

@ -4,3 +4,4 @@
0.04: Show a random kana every minute to improve learning 0.04: Show a random kana every minute to improve learning
0.05: Tell clock widgets to hide 0.05: Tell clock widgets to hide
0.06: Fix exception when showing missing hiragana 'WO' 0.06: Fix exception when showing missing hiragana 'WO'
0.07: Fix regression in bitmap selection on some code paths

View File

@ -224,6 +224,7 @@ function drawKana (x, y) {
g.setColor(0, 0, 0); g.setColor(0, 0, 0);
g.fillRect(0, 0, g.getWidth(), 6 * (h / 8) + 1); g.fillRect(0, 0, g.getWidth(), 6 * (h / 8) + 1);
g.setColor(1, 1, 1); g.setColor(1, 1, 1);
kana = hiramode ? hiragana[curkana] : katakana[curkana];
g.drawImage(kana, x + 20, 40, { scale: 1.6 }); g.drawImage(kana, x + 20, 40, { scale: 1.6 });
g.setColor(1, 1, 1); g.setColor(1, 1, 1);
g.setFont('Vector', 24); g.setFont('Vector', 24);
@ -266,4 +267,3 @@ Bangle.setUI('clock');
Bangle.loadWidgets(); Bangle.loadWidgets();
tickWatch(); tickWatch();
setInterval(tickWatch, 1000 * 60); setInterval(tickWatch, 1000 * 60);

View File

@ -2,7 +2,7 @@
"id": "kanawatch", "id": "kanawatch",
"name": "Kanawatch", "name": "Kanawatch",
"shortName": "Kanawatch", "shortName": "Kanawatch",
"version": "0.06", "version": "0.07",
"type": "clock", "type": "clock",
"description": "Learn Hiragana and Katakana", "description": "Learn Hiragana and Katakana",
"icon": "app.png", "icon": "app.png",

View File

@ -1,2 +1,3 @@
0.01: first release 0.01: first release
0.02: Use clock_info module as an app 0.02: Use clock_info module as an app
0.03: clock_info now uses app name to maintain settings specifically for this clock face

View File

@ -37,13 +37,13 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
{ {
// must be inside our own scope here so that when we are unloaded everything disappears // must be inside our own scope here so that when we are unloaded everything disappears
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
let draw = function() { let draw = function() {
var date = new Date(); var date = new Date();
var timeStr = require("locale").time(date,1); var timeStr = require("locale").time(date,1);
var h = g.getHeight(); var h = g.getHeight();
var w = g.getWidth(); var w = g.getWidth();
g.reset(); g.reset();
g.setColor(g.theme.bg); g.setColor(g.theme.bg);
g.fillRect(Bangle.appRect); g.fillRect(Bangle.appRect);
@ -66,7 +66,7 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
/** /**
* clock_info_support * clock_info_support
* this is the callback function that get invoked by clockInfoMenu.redraw(); * this is the callback function that get invoked by clockInfoMenu.redraw();
* *
* We will display the image and text on the same line and centre the combined * We will display the image and text on the same line and centre the combined
* length of the image+text * length of the image+text
* *
@ -76,7 +76,7 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
//g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg); //g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg);
g.reset().setFontLatoSmall(); g.reset().setFontLatoSmall();
g.setBgColor(options.bg).setColor(options.fg); g.setBgColor(options.bg).setColor(options.fg);
//use info.text.toString(), steps does not have length defined //use info.text.toString(), steps does not have length defined
var text_w = g.stringWidth(info.text.toString()); var text_w = g.stringWidth(info.text.toString());
// gap between image and text // gap between image and text
@ -88,7 +88,7 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
// clear the whole info line, allow additional 2 pixels in case LatoFont overflows area // clear the whole info line, allow additional 2 pixels in case LatoFont overflows area
g.clearRect(0, options.y -2, g.getWidth(), options.y+ 23 + 2); g.clearRect(0, options.y -2, g.getWidth(), options.y+ 23 + 2);
// draw the image if we have one // draw the image if we have one
if (info.img) { if (info.img) {
// image start // image start
@ -110,8 +110,8 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
// clock_info_support // clock_info_support
// setup the way we wish to interact with the menu // setup the way we wish to interact with the menu
// the hl property defines the color the of the info when the menu is selected after tapping on it // the hl property defines the color the of the info when the menu is selected after tapping on it
let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} ); let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { app : "lato", x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} );
// timeout used to update every minute // timeout used to update every minute
var drawTimeout; var drawTimeout;
g.clear(); g.clear();

View File

@ -37,13 +37,13 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
{ {
// must be inside our own scope here so that when we are unloaded everything disappears // must be inside our own scope here so that when we are unloaded everything disappears
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
let draw = function() { let draw = function() {
var date = new Date(); var date = new Date();
var timeStr = require("locale").time(date,1); var timeStr = require("locale").time(date,1);
var h = g.getHeight(); var h = g.getHeight();
var w = g.getWidth(); var w = g.getWidth();
g.reset(); g.reset();
g.setColor(g.theme.bg); g.setColor(g.theme.bg);
g.fillRect(Bangle.appRect); g.fillRect(Bangle.appRect);
@ -66,7 +66,7 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
/** /**
* clock_info_support * clock_info_support
* this is the callback function that get invoked by clockInfoMenu.redraw(); * this is the callback function that get invoked by clockInfoMenu.redraw();
* *
* We will display the image and text on the same line and centre the combined * We will display the image and text on the same line and centre the combined
* length of the image+text * length of the image+text
* *
@ -76,7 +76,7 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
//g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg); //g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg);
g.reset().setFontLatoSmall(); g.reset().setFontLatoSmall();
g.setBgColor(options.bg).setColor(options.fg); g.setBgColor(options.bg).setColor(options.fg);
//use info.text.toString(), steps does not have length defined //use info.text.toString(), steps does not have length defined
var text_w = g.stringWidth(info.text.toString()); var text_w = g.stringWidth(info.text.toString());
// gap between image and text // gap between image and text
@ -88,7 +88,7 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
// clear the whole info line, allow additional 2 pixels in case LatoFont overflows area // clear the whole info line, allow additional 2 pixels in case LatoFont overflows area
g.clearRect(0, options.y -2, g.getWidth(), options.y+ 23 + 2); g.clearRect(0, options.y -2, g.getWidth(), options.y+ 23 + 2);
// draw the image if we have one // draw the image if we have one
if (info.img) { if (info.img) {
// image start // image start
@ -110,8 +110,8 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
// clock_info_support // clock_info_support
// setup the way we wish to interact with the menu // setup the way we wish to interact with the menu
// the hl property defines the color the of the info when the menu is selected after tapping on it // the hl property defines the color the of the info when the menu is selected after tapping on it
let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} ); let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { app : "lato", x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} );
// timeout used to update every minute // timeout used to update every minute
var drawTimeout; var drawTimeout;
g.clear(); g.clear();

View File

@ -64,7 +64,7 @@ function queueDraw() {
/** /**
* clock_info_support * clock_info_support
* this is the callback function that get invoked by clockInfoMenu.redraw(); * this is the callback function that get invoked by clockInfoMenu.redraw();
* *
* We will display the image and text on the same line and centre the combined * We will display the image and text on the same line and centre the combined
* length of the image+text * length of the image+text
* *
@ -109,8 +109,8 @@ let clockInfoItems = require("clock_info").load();
* selected after tapping on it * selected after tapping on it
* *
*/ */
let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} ); let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { app : "lato", x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} );
g.clear(); g.clear();
// Show launcher when middle button pressed // Show launcher when middle button pressed

View File

@ -1,7 +1,7 @@
{ {
"id": "lato", "id": "lato",
"name": "Lato", "name": "Lato",
"version": "0.02", "version": "0.03",
"description": "A Lato Font clock with fast load and clock_info", "description": "A Lato Font clock with fast load and clock_info",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",

View File

@ -1,2 +1,3 @@
0.01: New App! 0.01: New App!
0.02: Use clock_info module as an app 0.02: Use clock_info module as an app
0.03: clock_info now uses app name to maintain settings specifically for this clock face

View File

@ -79,6 +79,6 @@ let clockInfoDraw = (itm, info, options) => {
}; };
let clockInfoItems = require("clock_info").load(); let clockInfoItems = require("clock_info").load();
let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { x:R.x, y:R.y, w:midX-2, h:barY-R.y-2, draw : clockInfoDraw}); let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:R.x, y:R.y, w:midX-2, h:barY-R.y-2, draw : clockInfoDraw});
let clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { x:midX+2, y:R.y, w:midX-3, h:barY-R.y-2, draw : clockInfoDraw}); let clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:midX+2, y:R.y, w:midX-3, h:barY-R.y-2, draw : clockInfoDraw});
} }

View File

@ -1,6 +1,6 @@
{ "id": "lcdclock", { "id": "lcdclock",
"name": "LCD Clock", "name": "LCD Clock",
"version":"0.02", "version":"0.03",
"description": "A Casio-style clock, with ClockInfo areas at the top and bottom. Tap them and swipe up/down to toggle between different information", "description": "A Casio-style clock, with ClockInfo areas at the top and bottom. Tap them and swipe up/down to toggle between different information",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],

View File

@ -0,0 +1 @@
0.01: New App!

View File

@ -0,0 +1,15 @@
# Loading Screen Settings
This app allows you to choose the loading screen that's displayed when swapping between apps on Bangle.js.
## Usage
Go to the Launcher, then `Settings`, then `Apps` and click on `Loading Screen` - you can then click to choose the loading screen you'll see.
## Internals
When reloading an app (fast load doesn't display anything), Bangle.js looks for a file called `.loading` (in versions 2v18+) which should be
an image. If it doesn't exist, the default `Loading...` screen is displayed. If it does exist and is less than 3 bytes long,
nothing is displayed, or if it's an image it is displayed, centered.
This app sets that image file accordingly, but you can always upload your own file.

BIN
apps/loadingscreen/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

View File

@ -0,0 +1,14 @@
{ "id": "loadingscreen",
"name": "Loading Screen",
"version":"0.01",
"description": "On Bangle.js 2v18+, this lets you customize the app loading screen via an new menu in Settings -> Apps",
"icon": "app.png",
"screenshots" : [ { "url":"screenshot1.png" }, { "url":"screenshot2.png" } ],
"tags": "tool",
"type": "settings",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"loadingscreen.settings.js","url":"settings.js"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,81 @@
(function(back) {
function goBack() {
var im = require("Storage").read(".loading");
if (im && im.length>3) {
var i = g.imageMetrics(im);
g.reset().drawImage(im, (g.getWidth()-i.width)/2, (g.getHeight()-i.height)/2);
}
setTimeout(back, 500);
}
function savePattern(pattern) {
E.showMessage("Please wait...");
var im = Graphics.createImage(pattern,"string");
var w = g.getWidth(), h = g.getHeight();
var b = Graphics.createArrayBuffer(w,h,1,{msb:true});
for (var y=0;y<h;y+=im.height)
for (var x=0;x<w;x+=im.width)
b.drawImage(im,x,y);
b.transparent = 0;
require("Storage").write(".loading",b.asImage("string"));
goBack();
}
function iconHourglass() {
// To get FG+BG+transparent, convert a monochrome image as a 2 bit greyscale using the image converter
return require("heatshrink").decompress(atob("mE4wUBqAOJgtABZMBGjH/ABALlBhA8LBIJrBBZCDCBZEFqoLJqoLO4BBDgYLcn/wBYcP/gLFCYIbBBY38BYYFBBYVACIILE+EBBYY1BLgX/BYgVBEAQECBYSQCJAQcCRwNVqg8CBYIDCioLDCYQbDBYRUBFYPwBwJ8BBQQ8BCgQaCHQQLNEZQ7LKZZrLQYbKDQYabDAASbFYoQACWYg2DAQrjPNIRtCBYjKCBYLMCBaIKBAAILGAAwLNRwQLHgrJCBY8BRIQLHSoYLJBQ4MDBcYAWNYIAIgKDBABEFA="));
}
function iconRetro() {
// A mac-style loading window
return require("heatshrink").decompress(atob("rk1gP/ABP4DBMDwALJnAWK39/+4tH3EEgIWJoEXC34WZORSghZ1oW/CzkB8AQC4AWFhgEBgOMFowSCjAtGhkPx8HzncuwWE4OMjHY41sDgQWCjHPzOMs3MCwuNzOYCw9Y7IWI5oWE5uwCwUf5+O53es187aJJFogAFFooAEg4HCcv4Wbn//ACnwA"))
}
E.showMenu({
"": {title:/*LANG*/"Loading Screen"},
"Default" : () => {require("Storage").erase(".loading");goBack()},
"No Screen" : () => {require("Storage").write(".loading","NO");goBack()}, // less than 3 chars and nothing is rendered
"Hourglass" : () => {require("Storage").write(".loading",iconHourglass());goBack()},
"Retro" : () => {require("Storage").write(".loading",iconRetro());goBack()},
"Stripes" : () => savePattern(`
XX..XX..
.XX..XX.
..XX..XX
X..XX..X
XX..XX..
.XX..XX.
..XX..XX
X..XX..X
`),
"Lines" : () => savePattern(`
XXXXXXXX
........
XXXXXXXX
........
XXXXXXXX
........
XXXXXXXX
........
`),
"Dots" : () => savePattern(`
......
..XX..
.XXXX.
.XXXX.
..XX..
......
`)
});
/* For testing, this generates an image with a different colour surrounding on it
require("FontSinclair").add(Graphics);
var b = Graphics.createArrayBuffer(84,12,2);
b.setBgColor(1).clear();
b.transparent = 1;
b.setFont("Sinclair").setColor(0);
for (var y=-2;y<=2;y++) for (var x=-2;x<=2;x++) b.drawString("LOADING...",2+x,2+y);
b.setColor(3).drawString("LOADING...",2,2);
g.drawImage(b.asImage("string"));
*/
})

View File

@ -239,6 +239,8 @@ TODO:
document.getElementById("mapContainer").style.display = ""; document.getElementById("mapContainer").style.display = "";
document.getElementById("maptiles").style.display="none"; document.getElementById("maptiles").style.display="none";
document.getElementById("uploadbuttons").style.display="none"; document.getElementById("uploadbuttons").style.display="none";
map.invalidateSize();
map.locate({setView: true, maxZoom: 16, enableHighAccuracy:true});
} }
// ----------------------------------------------------- // -----------------------------------------------------

View File

@ -1,2 +1,3 @@
0.01: New App! 0.01: New App!
0.02: Do first update request 5s after boot to boot up faster 0.02: Do first update request 5s after boot to boot up faster
0.03: Fix updating weather too often

View File

@ -1,19 +1,21 @@
{ {
let waiting = false; let waiting = false;
let settings = require("Storage").readJSON("owmweather.json", 1) || { let settings = Object.assign(
enabled: false require('Storage').readJSON("owmweather.default.json", true) || {},
}; require('Storage').readJSON("owmweather.json", true) || {}
);
let completion = function(){ let completion = function(){
waiting = false; waiting = false;
settings.updated = Date.now();
require('Storage').writeJSON("owmweather.json", settings);
} }
if (settings.enabled) { if (settings.enabled) {
let weather = require("Storage").readJSON('weather.json') || {}; let weather = require("Storage").readJSON('weather.json') || {};
let lastUpdate;
if (weather && weather.weather && weather.weather.time) lastUpdate = weather.weather.time; if (weather && weather.weather && weather.weather.time) lastUpdate = weather.weather.time;
if (!lastUpdate || lastUpdate + settings.refresh * 1000 * 60 < Date.now()){ if (!settings.updated || settings.updated + settings.refresh * 1000 * 60 < Date.now()){
setTimeout(() => { setTimeout(() => {
if (!waiting){ if (!waiting){
waiting = true; waiting = true;

View File

@ -25,7 +25,7 @@ function parseWeather(response) {
json.weather = weather; json.weather = weather;
require("Storage").writeJSON('weather.json', json); require("Storage").writeJSON('weather.json', json);
require("weather").emit("update", json.weather); if (require("Storage").read("weather")!==undefined) require("weather").emit("update", json.weather);
return undefined; return undefined;
} else { } else {
return /*LANG*/"Not OWM data"; return /*LANG*/"Not OWM data";

View File

@ -1,7 +1,7 @@
{ "id": "owmweather", { "id": "owmweather",
"name": "OpenWeatherMap weather provider", "name": "OpenWeatherMap weather provider",
"shortName":"OWM Weather", "shortName":"OWM Weather",
"version":"0.02", "version":"0.03",
"description": "Pulls weather from OpenWeatherMap (OWM) API", "description": "Pulls weather from OpenWeatherMap (OWM) API",
"icon": "app.png", "icon": "app.png",
"type": "bootloader", "type": "bootloader",

View File

@ -1 +1,3 @@
0.01: First release 0.01: First release
0.02: clock_info now uses app name to maintain settings specifically for this clock face
ensure clockinfo text is usppercase (font doesn't render lowercase)

View File

@ -86,14 +86,16 @@ let clockInfoDraw = (itm, info, options) => {
} }
} }
g.setFontLECO1976Regular22().setFontAlign(0, 0); g.setFontLECO1976Regular22().setFontAlign(0, 0);
g.drawString(info.text, midx,options.y+options.h-12); // draw the text g.drawString(info.text.toString().toUpperCase(), midx,options.y+options.h-12); // draw the text
}; };
let clockInfoMenuA = require("clock_info").addInteractive(clockInfoItems, { let clockInfoMenuA = require("clock_info").addInteractive(clockInfoItems, {
app:"pebblepp",
x : 0, y: 0, w: w/2, h:h/2, x : 0, y: 0, w: w/2, h:h/2,
draw : clockInfoDraw draw : clockInfoDraw
}); });
let clockInfoMenuB = require("clock_info").addInteractive(clockInfoItems, { let clockInfoMenuB = require("clock_info").addInteractive(clockInfoItems, {
app:"pebblepp",
x : w/2, y: 0, w: w/2, h:h/2, x : w/2, y: 0, w: w/2, h:h/2,
draw : clockInfoDraw draw : clockInfoDraw
}); });

View File

@ -2,7 +2,7 @@
"id": "pebblepp", "id": "pebblepp",
"name": "Pebble++ Clock", "name": "Pebble++ Clock",
"shortName": "Pebble++", "shortName": "Pebble++",
"version": "0.01", "version": "0.02",
"description": "A pebble style clock (based on the 'Pebble Clock' app) but with two configurable ClockInfo items at the top", "description": "A pebble style clock (based on the 'Pebble Clock' app) but with two configurable ClockInfo items at the top",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],

View File

@ -1,3 +1,4 @@
0.01: first release 0.01: first release
0.02: removed fast load, minimalism is useful for narrowing down on issues 0.02: removed fast load, minimalism is useful for narrowing down on issues
0.03: Use clock_info module as an app 0.03: Use clock_info module as an app
0.04: clock_info now uses app name to maintain settings specifically for this clock face

View File

@ -5,7 +5,7 @@ function draw() {
var timeStr = require("locale").time(date,1); var timeStr = require("locale").time(date,1);
var h = g.getHeight(); var h = g.getHeight();
var w = g.getWidth(); var w = g.getWidth();
g.reset(); g.reset();
g.setColor(g.theme.bg); g.setColor(g.theme.bg);
g.fillRect(Bangle.appRect); g.fillRect(Bangle.appRect);
@ -34,7 +34,7 @@ function queueDraw() {
/** /**
* clock_info_support * clock_info_support
* this is the callback function that get invoked by clockInfoMenu.redraw(); * this is the callback function that get invoked by clockInfoMenu.redraw();
* *
* We will display the image and text on the same line and centre the combined * We will display the image and text on the same line and centre the combined
* length of the image+text * length of the image+text
* *
@ -42,7 +42,7 @@ function queueDraw() {
function clockInfoDraw(itm, info, options) { function clockInfoDraw(itm, info, options) {
g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg); g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg);
//use info.text.toString(), steps does not have length defined //use info.text.toString(), steps does not have length defined
var text_w = g.stringWidth(info.text.toString()); var text_w = g.stringWidth(info.text.toString());
// gap between image and text // gap between image and text
@ -54,7 +54,7 @@ function clockInfoDraw(itm, info, options) {
// clear the whole info line // clear the whole info line
g.clearRect(0, options.y -1, g.getWidth(), options.y+24); g.clearRect(0, options.y -1, g.getWidth(), options.y+24);
// draw the image if we have one // draw the image if we have one
if (info.img) { if (info.img) {
// image start // image start
@ -82,7 +82,7 @@ let clockInfoItems = require("clock_info").load();
* selected after tapping on it * selected after tapping on it
* *
*/ */
let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} ); let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { app:"simplestpp", x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} );
// Clear the screen once, at startup // Clear the screen once, at startup
g.clear(); g.clear();

View File

@ -2,7 +2,7 @@
"id": "simplestpp", "id": "simplestpp",
"name": "Simplest++ Clock", "name": "Simplest++ Clock",
"shortName": "Simplest++", "shortName": "Simplest++",
"version": "0.03", "version": "0.04",
"description": "The simplest working clock, with clock_info, acts as a tutorial piece", "description": "The simplest working clock, with clock_info, acts as a tutorial piece",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",

View File

@ -10,3 +10,4 @@
0.08: Stability improvements - ensure we continue even if a flat string can't be allocated 0.08: Stability improvements - ensure we continue even if a flat string can't be allocated
Stop ClockInfo text drawing outside the allocated area Stop ClockInfo text drawing outside the allocated area
0.09: Use clock_info module as an app 0.09: Use clock_info module as an app
0.10: Option to hide widgets, tweak top widget width to avoid overlap with hour text at 9am

View File

@ -58,7 +58,8 @@ let draw = function() {
// Now draw this one // Now draw this one
R = Bangle.appRect; R = Bangle.appRect;
x = R.w / 2; x = R.w / 2;
y = R.y + R.h / 2 - 12; // 12 = room for date y = R.y + R.h / 2 - 6;
if (!settings.hideWidgets) y-= 6; // extra room for date
var date = new Date(); var date = new Date();
var local_time = require("locale").time(date, 1); var local_time = require("locale").time(date, 1);
var hourStr = local_time.split(":")[0].trim().padStart(2,'0'); var hourStr = local_time.split(":")[0].trim().padStart(2,'0');
@ -77,6 +78,8 @@ let draw = function() {
g2.setColor(0).fillRect(0,0,g2.getWidth(),g2.getHeight()).setFontAlign(1, 0).setFont("PaytoneOne"); g2.setColor(0).fillRect(0,0,g2.getWidth(),g2.getHeight()).setFontAlign(1, 0).setFont("PaytoneOne");
g2.setColor(1).drawString(minStr, g2.getWidth()-fontBorder, g2.getHeight()/2).setFont("4x6"); // draw and unload custom font g2.setColor(1).drawString(minStr, g2.getWidth()-fontBorder, g2.getHeight()/2).setFont("4x6"); // draw and unload custom font
g2.setColor(0).fillPoly([0,0, g2.getWidth(),0, 0,slope*2]); g2.setColor(0).fillPoly([0,0, g2.getWidth(),0, 0,slope*2]);
// redraw the top widget
clockInfoMenu.redraw();
// start the animation *in* // start the animation *in*
animate(true); animate(true);
}; };
@ -141,8 +144,14 @@ let clockInfoDraw = (itm, info, options) => {
g.setClipRect(0,0,g.getWidth()-1, g.getHeight()-1); g.setClipRect(0,0,g.getWidth()-1, g.getHeight()-1);
}; };
let clockInfoItems = require("clock_info").load(); let clockInfoItems = require("clock_info").load();
let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { app:"slopeclockpp",x:126, y:24, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#f00"/*red*/ }); let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { // top right
let clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { app:"slopeclockpp",x:0, y:115, w:50, h:40, draw : clockInfoDraw, bg : bgColor, fg : g.theme.bg, hl : (bgColor=="#000")?"#f00"/*red*/:g.theme.fg }); app:"slopeclockpp",x:132, y:settings.hideWidgets ? 12 : 24, w:44, h:40,
draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#f00"/*red*/
});
let clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { // bottom left
app:"slopeclockpp",x:0, y:115, w:50, h:40,
draw : clockInfoDraw, bg : bgColor, fg : g.theme.bg, hl : (bgColor=="#000")?"#f00"/*red*/:g.theme.fg
});
// Show launcher when middle button pressed // Show launcher when middle button pressed
Bangle.setUI({ Bangle.setUI({
@ -163,6 +172,7 @@ Bangle.setUI({
}); });
// Load widgets // Load widgets
Bangle.loadWidgets(); Bangle.loadWidgets();
if (settings.hideWidgets) require("widget_utils").swipeOn();
else setTimeout(Bangle.drawWidgets,0);
draw(); draw();
setTimeout(Bangle.drawWidgets,0); }
}

View File

@ -1,6 +1,6 @@
{ "id": "slopeclockpp", { "id": "slopeclockpp",
"name": "Slope Clock ++", "name": "Slope Clock ++",
"version":"0.09", "version":"0.10",
"description": "A clock where hours and minutes are divided by a sloping line. When the minute changes, the numbers slide off the screen. This is a clone of the original Slope Clock which shows extra information and allows the colors to be selected.", "description": "A clock where hours and minutes are divided by a sloping line. When the minute changes, the numbers slide off the screen. This is a clone of the original Slope Clock which shows extra information and allows the colors to be selected.",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -15,6 +15,10 @@
let menu ={ let menu ={
'': { 'title': 'Slope Clock ++' }, '': { 'title': 'Slope Clock ++' },
/*LANG*/'< Back': back, /*LANG*/'< Back': back,
/*LANG*/'Hide Widgets': {
value: !!settings.hideWidgets,
onchange: x => save('hideWidgets', x),
},
/*LANG*/'Red': { /*LANG*/'Red': {
value: !!settings.colorRed, value: !!settings.colorRed,
format: () => (settings.colorRed ? 'Yes' : 'No'), format: () => (settings.colorRed ? 'Yes' : 'No'),

View File

@ -1,2 +1,3 @@
0.01: New app! 0.01: New app!
0.02: Submitted to the app loader 0.02: Submitted to the app loader
0.03: Fix going back from a lap view, and add a main-menu back button

View File

@ -53,7 +53,7 @@ function view(fileName) {
let lapMenu = { let lapMenu = {
'': { '': {
'title': fileNameToDateString(fileName), 'title': fileNameToDateString(fileName),
'back': () => { E.showMenu(mainMenu); } 'back': () => showMainMenu()
}, },
}; };
lapMenu[`Total time: ${msToHumanReadable(fileData[fileData.length - 1])}`] = () => { }; lapMenu[`Total time: ${msToHumanReadable(fileData[fileData.length - 1])}`] = () => { };
@ -89,15 +89,16 @@ function showMainMenu() {
let mainMenu = { let mainMenu = {
'': { '': {
'title': 'Sessions' 'title': 'Sessions',
'back': () => load()
} }
}; };
//I know eval is evil, but I can't think of any other way to do this.
for (let lapFile of LAP_FILES) { for (let lapFile of LAP_FILES) {
mainMenu[fileNameToDateString(lapFile)] = eval(`(function() { // `let` variables in JS have special behaviour in loops,
view('${lapFile}'); // where capturing them captures that instance of the variable,
})`); // but for espruino we need to do a slightly older trick:
mainMenu[fileNameToDateString(lapFile)] = ((lapFile) => () => view(lapFile))(lapFile);
} }
if (LAP_FILES.length == 0) { if (LAP_FILES.length == 0) {

View File

@ -1,7 +1,7 @@
{ {
"id": "stlapview", "id": "stlapview",
"name": "Stopwatch laps", "name": "Stopwatch laps",
"version": "0.02", "version": "0.03",
"description": "Optional lap viewer for my stopwatch app", "description": "Optional lap viewer for my stopwatch app",
"icon": "icon.png", "icon": "icon.png",
"type": "app", "type": "app",

View File

@ -1 +1,2 @@
0.01: New Widget! 0.01: New Widget!
0.02: Now use an app ID (to avoid conflicts with clocks that also use ClockInfo)

View File

@ -1,8 +1,8 @@
{ "id": "widclkinfo", { "id": "widclkinfo",
"name": "Clock Info Widget", "name": "Clock Info Widget",
"version":"0.01", "version":"0.02",
"description": "Use 'Clock Info' in the Widget bar. Tap on the widget to select, then drag up/down/left/right to choose what information is displayed.", "description": "Use 'Clock Info' in the Widget bar. Tap on the widget to select, then drag up/down/left/right to choose what information is displayed.",
"icon": "widget.png", "icon": "widget.png",
"screenshots" : [ { "url":"screenshot.png" }], "screenshots" : [ { "url":"screenshot.png" }],
"type": "widget", "type": "widget",
"tags": "widget,clkinfo", "tags": "widget,clkinfo",

View File

@ -3,6 +3,7 @@ if (!require("clock_info").loadCount) { // don't load if a clock_info was alread
let clockInfoItems = require("clock_info").load(); let clockInfoItems = require("clock_info").load();
// Add the // Add the
let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, {
app : "widclkinfo",
// Add the dimensions we're rendering to here - these are used to detect taps on the clock info area // Add the dimensions we're rendering to here - these are used to detect taps on the clock info area
x : 0, y: 0, w: 72, h:24, x : 0, y: 0, w: 72, h:24,
// You can add other information here you want to be passed into 'options' in 'draw' // You can add other information here you want to be passed into 'options' in 'draw'
@ -19,8 +20,8 @@ if (!require("clock_info").loadCount) { // don't load if a clock_info was alread
let clockInfoInfo; // when clockInfoMenu.draw is called we set this up let clockInfoInfo; // when clockInfoMenu.draw is called we set this up
// The actual widget we're displaying // The actual widget we're displaying
WIDGETS["clkinfo"] = { WIDGETS["clkinfo"] = {
area:"tl", area:"tl",
width: clockInfoMenu.w, width: clockInfoMenu.w,
draw:function(e) { draw:function(e) {
clockInfoMenu.x = e.x; clockInfoMenu.x = e.x;

View File

@ -1,3 +1,5 @@
0.01: New widget - music control via a swipe 0.01: New widget - music control via a swipe
0.02: Improve interactivity - avoid responding to swipes when a menu or 0.02: Improve interactivity - avoid responding to swipes when a menu or
launcher is active. launcher is active.
0.03: Handle errors when sending input over BLE and the special-case of
replacing a single handler

View File

@ -2,7 +2,7 @@
"id": "widhid", "id": "widhid",
"name": "Bluetooth Music Swipe Control Widget", "name": "Bluetooth Music Swipe Control Widget",
"shortName": "BLE Swipe Widget", "shortName": "BLE Swipe Widget",
"version": "0.02", "version": "0.03",
"description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!", "description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!",
"icon": "icon.png", "icon": "icon.png",
"readme": "README.md", "readme": "README.md",

View File

@ -81,7 +81,10 @@
if (!wasActive) { if (!wasActive) {
waitForRelease = true; waitForRelease = true;
Bangle.on("drag", onDrag); Bangle.on("drag", onDrag);
Bangle["#ondrag"] = [onDrag].concat(Bangle["#ondrag"].filter(function (f) { return f !== onDrag; })); var dragHandlers = Bangle["#ondrag"];
if (dragHandlers && typeof dragHandlers !== "function") {
Bangle["#ondrag"] = [onDrag].concat(dragHandlers.filter(function (f) { return f !== onDrag; }));
}
redraw(); redraw();
} }
if (activeTimeout) if (activeTimeout)
@ -120,7 +123,12 @@
redraw(); redraw();
}); });
var sendHid = function (code) { var sendHid = function (code) {
NRF.sendHIDReport([1, code], function () { return NRF.sendHIDReport([1, 0]); }); try {
NRF.sendHIDReport([1, code], function () { return NRF.sendHIDReport([1, 0]); });
}
catch (e) {
console.log("sendHIDReport:", e);
}
}; };
var next = function () { return sendHid(0x01); }; var next = function () { return sendHid(0x01); };
var prev = function () { return sendHid(0x02); }; var prev = function () { return sendHid(0x02); };

View File

@ -23,7 +23,7 @@
const onDrag = (e => { const onDrag = (e => {
// Espruino/35c8cb9be11 // Espruino/35c8cb9be11
(E as any).stopEventPropagation && (E as any).stopEventPropagation(); E.stopEventPropagation && E.stopEventPropagation();
if(e.b === 0){ if(e.b === 0){
// released // released
@ -84,10 +84,15 @@
waitForRelease = true; // wait for first touch up before accepting gestures waitForRelease = true; // wait for first touch up before accepting gestures
Bangle.on("drag", onDrag); Bangle.on("drag", onDrag);
// move our drag to the start of the event listener array // move our drag to the start of the event listener array
(Bangle as any)["#ondrag"] = [onDrag].concat( const dragHandlers = (Bangle as BangleEvents)["#ondrag"]
(Bangle as any)["#ondrag"].filter((f: unknown) => f !== onDrag)
); if(dragHandlers && typeof dragHandlers !== "function"){
(Bangle as BangleEvents)["#ondrag"] = [onDrag as undefined | typeof onDrag].concat(
dragHandlers.filter((f: unknown) => f !== onDrag)
);
}
redraw(); redraw();
} }
@ -140,10 +145,14 @@
//const DEBUG = true; //const DEBUG = true;
const sendHid = (code: number) => { const sendHid = (code: number) => {
//if(DEBUG) return; //if(DEBUG) return;
NRF.sendHIDReport( try{
[1, code], NRF.sendHIDReport(
() => NRF.sendHIDReport([1, 0]), [1, code],
); () => NRF.sendHIDReport([1, 0]),
);
}catch(e){
console.log("sendHIDReport:", e);
}
}; };
const next = () => /*DEBUG ? console.log("next") : */ sendHid(0x01); const next = () => /*DEBUG ? console.log("next") : */ sendHid(0x01);

View File

@ -195,7 +195,7 @@
</footer> </footer>
<script src="webtools/puck.js"></script> <script src="webtools/puck.js"></script>
<script src="webtools/heatshrink.js"></script> <script src="webtools/heatshrink.js"></script>
<script src="core/lib/marked.min.js"></script> <script src="core/lib/marked.min.js"></script>
<script src="core/lib/espruinotools.js"></script> <script src="core/lib/espruinotools.js"></script>
<script src="core/js/utils.js"></script> <script src="core/js/utils.js"></script>

10
typescript/types/bangle_extensions.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
type BangleHandler<T extends (...args: any[]) => any> = T | (T | undefined)[];
type BangleEvents = {
["#ontap"]?: BangleHandler<(data: { dir: "left" | "right" | "top" | "bottom" | "front" | "back", double: boolean, x: TapAxis, y: TapAxis, z: TapAxis }) => void>,
["#ongesture"]?: BangleHandler<(xyz: Int8Array) => void>,
["#onswipe"]?: BangleHandler<SwipeCallback>,
["#ontouch"]?: BangleHandler<TouchCallback>,
["#ondrag"]?: BangleHandler<DragCallback>,
["#onstroke"]?: BangleHandler<(event: { xy: Uint8Array, stroke?: string }) => void>,
};

View File

@ -465,6 +465,46 @@ declare class ESP32 {
*/ */
static deepSleep(us: number): void; static deepSleep(us: number): void;
/**
* Put device in deepsleep state until interrupted by pin "pin".
* Eligible pin numbers are restricted to those [GPIOs designated
* as RTC GPIOs](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html#gpio-summary).
*
* @param {Pin} pin - Pin to trigger wakeup
* @param {number} level - Logic level to trigger
* @url http://www.espruino.com/Reference#l_ESP32_deepSleepExt0
*/
static deepSleepExt0(pin: Pin, level: number): void;
/**
* Put device in deepsleep state until interrupted by pins in the "pinVar" array.
* The trigger "mode" determines the pin state which will wake up the device.
* Valid modes are:
* * `0: ESP_EXT1_WAKEUP_ALL_LOW` - all nominated pins must be set LOW to trigger wakeup
* * `1: ESP_EXT1_WAKEUP_ANY_HIGH` - any of nominated pins set HIGH will trigger wakeup
* Eligible pin numbers are restricted to those [GPIOs designated
* as RTC GPIOs](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html#gpio-summary).
*
* @param {any} pinVar - Array of Pins to trigger wakeup
* @param {number} mode - Trigger mode
* @url http://www.espruino.com/Reference#l_ESP32_deepSleepExt1
*/
static deepSleepExt1(pinVar: any, mode: number): void;
/**
* Returns a variable identifying the cause of wakeup from deep sleep.
* Possible causes include:
* * `0: ESP_SLEEP_WAKEUP_UNDEFINED` - reset was not caused by exit from deep sleep
* * `2: ESP_SLEEP_WAKEUP_EXT0` - Wakeup caused by external signal using RTC_IO
* * `3: ESP_SLEEP_WAKEUP_EXT1` - Wakeup caused by external signal using RTC_CNTL
* * `4: ESP_SLEEP_WAKEUP_TIMER` - Wakeup caused by timer
* * `5: ESP_SLEEP_WAKEUP_TOUCHPAD` - Wakeup caused by touchpad
* * `6: ESP_SLEEP_WAKEUP_ULP` - Wakeup caused by ULP program
* @returns {number} The cause of the ESP32's wakeup from sleep
* @url http://www.espruino.com/Reference#l_ESP32_getWakeupCause
*/
static getWakeupCause(): number;
/** /**
* Returns an object that contains details about the state of the ESP32 with the * Returns an object that contains details about the state of the ESP32 with the
* following fields: * following fields:
@ -5597,7 +5637,9 @@ declare class Graphics<IsBuffer extends boolean = boolean> {
* `width,height,bpp,[transparent,]image_bytes...`. If a transparent colour is * `width,height,bpp,[transparent,]image_bytes...`. If a transparent colour is
* specified the top bit of `bpp` should be set. * specified the top bit of `bpp` should be set.
* * An ArrayBuffer Graphics object (if `bpp<8`, `msb:true` must be set) - this is * * An ArrayBuffer Graphics object (if `bpp<8`, `msb:true` must be set) - this is
* disabled on devices without much flash memory available * disabled on devices without much flash memory available. If a Graphics object
* is supplied, it can also contain transparent/palette fields as if it were
* an image.
* Draw an image at the specified position. * Draw an image at the specified position.
* * If the image is 1 bit, the graphics foreground/background colours will be * * If the image is 1 bit, the graphics foreground/background colours will be
* used. * used.
@ -5678,6 +5720,9 @@ declare class Graphics<IsBuffer extends boolean = boolean> {
* * Is 8 bpp *OR* the `{msb:true}` option was given * * Is 8 bpp *OR* the `{msb:true}` option was given
* * No other format options (zigzag/etc) were 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.
* If the `Graphics` object contains `transparent` or `pelette` fields,
* [as you might find in an image](http://www.espruino.com/Graphics#images-bitmaps),
* those will be included in the generated image too.
* *
* @param {any} type - The type of image to return. Either `object`/undefined to return an image object, or `string` to return an image string * @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` * @returns {any} An Image that can be used with `Graphics.drawImage`
@ -5800,6 +5845,19 @@ declare class Graphics<IsBuffer extends boolean = boolean> {
*/ */
transformVertices(arr: number[], transformation: { x?: number, y?: number, scale?: number, rotate?: number } | [number, number, number, number, number, number]): number[]; transformVertices(arr: number[], transformation: { x?: number, y?: number, scale?: number, rotate?: number } | [number, number, number, number, number, number]): number[];
/**
* Flood fills the given Graphics instance out from a particular point.
* **Note:** This only works on Graphics instances that support readback with `getPixel`. It
* is also not capable of filling over dithered patterns (eg non-solid colours on Bangle.js 2)
*
* @param {number} x - X coordinate to start from
* @param {number} y - Y coordinate to start from
* @param {any} col - The color to fill with (if undefined, foreground is used)
* @returns {any} The instance of Graphics this was called on, to allow call chaining
* @url http://www.espruino.com/Reference#l_Graphics_floodFill
*/
floodFill(x: number, y: number, col: any): Graphics;
/** /**
* Returns an object of the form: * Returns an object of the form:
* ``` * ```
@ -8223,6 +8281,10 @@ declare class E {
/** /**
* Dump any locked variables that aren't referenced from `global` - for debugging * Dump any locked variables that aren't referenced from `global` - for debugging
* memory leaks only. * memory leaks only.
* **Note:** This does a linear scan over memory, finding variables
* that are currently locked. In some cases it may show variables
* like `Unknown 66` which happen when *part* of a string has ended
* up placed in memory ahead of the String that it's part of. See https://github.com/espruino/Espruino/issues/2345
* @url http://www.espruino.com/Reference#l_E_dumpLockedVars * @url http://www.espruino.com/Reference#l_E_dumpLockedVars
*/ */
static dumpLockedVars(): void; static dumpLockedVars(): void;
@ -8655,6 +8717,24 @@ declare class E {
*/ */
static decodeUTF8(str: string, lookup: string[], replaceFn: string | ((charCode: number) => string)): string; static decodeUTF8(str: string, lookup: string[], replaceFn: string | ((charCode: number) => string)): string;
/**
* When using events with `X.on('foo', function() { ... })`
* and then `X.emit('foo')` you might want to stop subsequent
* event handlers from being executed.
* Calling this function doing the execution of events will
* ensure that no subsequent event handlers are executed.
* ```
* var X = {}; // in Espruino all objects are EventEmitters
* X.on('foo', function() { print("A"); })
* X.on('foo', function() { print("B"); E.stopEventPropagation(); })
* X.on('foo', function() { print("C"); })
* X.emit('foo');
* // prints A,B but not C
* ```
* @url http://www.espruino.com/Reference#l_E_stopEventPropagation
*/
static stopEventPropagation(): void;
} }
@ -8959,6 +9039,9 @@ interface Object {
* o.emit('answer', 44); * o.emit('answer', 44);
* // nothing printed * // nothing printed
* ``` * ```
* If you have more than one handler for an event, and you'd
* like that handler to stop the event being passed to other handlers
* then you can call `E.stopEventPropagation()` in that handler.
* *
* @param {any} event - The name of the event, for instance 'data' * @param {any} event - The name of the event, for instance 'data'
* @param {any} listener - The listener to call when this event is received * @param {any} listener - The listener to call when this event is received
@ -10074,6 +10157,12 @@ declare class Serial {
* @url http://www.espruino.com/Reference#l_Serial_pipe * @url http://www.espruino.com/Reference#l_Serial_pipe
*/ */
pipe(destination: any, options?: PipeOptions): void pipe(destination: any, options?: PipeOptions): void
/**
* Flush this serial stream (pause execution until all data has been sent)
* @url http://www.espruino.com/Reference#l_Serial_flush
*/
flush(): void;
} }
interface StringConstructor { interface StringConstructor {