Merge pull request #3565 from bobrippling/feat/pace-app

New app: pace
pull/3619/head
thyttan 2024-10-18 13:24:51 +02:00 committed by GitHub
commit 50604037c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 795 additions and 73 deletions

View File

@ -720,7 +720,7 @@ const hook = (enable: boolean) => {
// --- intervals ---
const setIntervals = (
locked: boolean = Bangle.isLocked(),
locked: ShortBoolean = Bangle.isLocked(),
connected: boolean = NRF.getSecurityStatus().connected,
) => {
changeInterval(

1
apps/pace/ChangeLog Normal file
View File

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

11
apps/pace/README.md Normal file
View File

@ -0,0 +1,11 @@
# Description
A running pace app, useful for races. Will also record your splits and display them to you on the pause menu.
Drag up/down on the pause menu to scroll through your splits.
Press the button to pause/resume - when resumed, pressing the button will pause instantly, regardless of whether the screen is locked.
# Todo
- Load splits on app start, button to reset (exs is always reset)
- Show total time on pause screen

1
apps/pace/app-icon.js Normal file
View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwIjgj//Ap8A8AFPgP4jAdEngFCv///AFC/8f+AFC/EBAodggF4FQgdDF4MeFoIhB8EPgEDApEHwAXDAosDApPwAoIdC//j4AFFGoV/AoJCDDogFIDoUAHYIFEKYxlFAAVAnwEDgF8JgaiBAoX8g6PDUIJGDVoJADg/8f74A=="))

175
apps/pace/app.js Normal file
View File

@ -0,0 +1,175 @@
{
var Layout_1 = require("Layout");
var time_utils_1 = require("time_utils");
var exs_1 = require("exstats").getStats(["dist", "pacec"], {
notify: {
dist: {
increment: 1000,
},
},
});
var S_1 = require("Storage");
var drawTimeout_1;
var splits_1 = [];
var splitOffset_1 = 0, splitOffsetPx_1 = 0;
var GPS_TIMEOUT_MS_1 = 30000;
var layout_1 = new Layout_1({
type: "v",
c: [
{
type: "txt",
font: "6x8:2",
label: "Pace",
id: "paceLabel",
pad: 4
},
{
type: "txt",
font: "Vector:40",
label: "",
id: "pace",
halign: 0
},
{
type: "txt",
font: "6x8:2",
label: "Time",
id: "timeLabel",
pad: 4
},
{
type: "txt",
font: "Vector:40",
label: "",
id: "time",
halign: 0
},
]
}, {
lazy: true
});
var draw_1 = function () {
if (!exs_1.state.active) {
drawSplits_1();
return;
}
if (drawTimeout_1)
clearTimeout(drawTimeout_1);
drawTimeout_1 = setTimeout(draw_1, 1000);
var now = Date.now();
var pace;
if ("time" in exs_1.state.thisGPS
&& now - exs_1.state.thisGPS.time < GPS_TIMEOUT_MS_1) {
pace = exs_1.stats.pacec.getString();
}
else {
pace = "No GPS";
}
layout_1["time"].label = formatDuration_1(exs_1.state.duration);
layout_1["pace"].label = pace;
layout_1.render();
};
var pad2_1 = function (n) { return "0".concat(n).substr(-2); };
var formatDuration_1 = function (ms) {
var tm = time_utils_1.decodeTime(ms);
if (tm.h)
return "".concat(tm.h, ":").concat(pad2_1(tm.m), ":").concat(pad2_1(tm.s));
return "".concat(pad2_1(tm.m), ":").concat(pad2_1(tm.s));
};
var calculatePace_1 = function (split) { return formatDuration_1(split.time / split.dist * 1000); };
var drawSplits_1 = function () {
g.clearRect(Bangle.appRect);
var barSize = 20;
var barSpacing = 10;
var w = g.getWidth();
var h = g.getHeight();
var max = splits_1.reduce(function (a, s) { return Math.max(a, s.time); }, 0);
g.setFont("6x8", 2).setFontAlign(-1, -1);
var i = 0;
for (;; i++) {
var split = splits_1[i + splitOffset_1];
if (split == null)
break;
var y_1 = Bangle.appRect.y + i * (barSize + barSpacing) + barSpacing / 2;
if (y_1 > h)
break;
var size = w * split.time / max;
g.setColor("#00f").fillRect(0, y_1, size, y_1 + barSize);
var splitPace = calculatePace_1(split);
drawSplit_1(i, y_1, splitPace);
}
var pace = exs_1.stats.pacec.getString();
var y = Bangle.appRect.y + i * (barSize + barSpacing) + barSpacing / 2;
drawSplit_1(i, y, pace);
};
var drawSplit_1 = function (i, y, pace) {
g
.setColor(g.theme.fg)
.drawString("".concat(i + 1 + splitOffset_1, " ").concat(typeof pace === "number" ? pace.toFixed(2) : pace), 0, y);
};
var pauseRun_1 = function () {
exs_1.stop();
Bangle.setGPSPower(0, "pace");
draw_1();
};
var resumeRun_1 = function () {
exs_1.resume();
Bangle.setGPSPower(1, "pace");
g.clearRect(Bangle.appRect);
layout_1.forgetLazyState();
draw_1();
};
var onButton_1 = function () {
if (exs_1.state.active)
pauseRun_1();
else
resumeRun_1();
};
exs_1.start();
exs_1.stats.dist.on("notify", function (dist) {
var prev = { time: 0, dist: 0 };
for (var _i = 0, splits_2 = splits_1; _i < splits_2.length; _i++) {
var s = splits_2[_i];
prev.time += s.time;
prev.dist += s.dist;
}
var totalDist = dist.getValue();
var thisSplit = totalDist - prev.dist;
var thisTime = exs_1.state.duration - prev.time;
while (thisSplit > 1000) {
splits_1.push({ dist: thisSplit, time: thisTime });
thisTime = 0;
thisSplit -= 1000;
}
exs_1.state.notify.dist.next -= thisSplit;
S_1.writeJSON("pace.json", { splits: splits_1 });
});
Bangle.on('lock', function (locked) {
if (!locked && exs_1.state.active)
onButton_1();
});
setWatch(function () { return onButton_1(); }, BTN1, { repeat: true });
Bangle.on('drag', function (e) {
if (exs_1.state.active || e.b === 0)
return;
splitOffsetPx_1 -= e.dy;
if (splitOffsetPx_1 > 20) {
if (splitOffset_1 < splits_1.length - 3)
splitOffset_1++, Bangle.buzz(30);
splitOffsetPx_1 = 0;
}
else if (splitOffsetPx_1 < -20) {
if (splitOffset_1 > 0)
splitOffset_1--, Bangle.buzz(30);
splitOffsetPx_1 = 0;
}
draw_1();
});
Bangle.on('twist', function () {
Bangle.setBacklight(1);
});
Bangle.loadWidgets();
Bangle.drawWidgets();
g.clearRect(Bangle.appRect);
draw_1();
}

BIN
apps/pace/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

225
apps/pace/app.ts Normal file
View File

@ -0,0 +1,225 @@
{
const Layout = require("Layout");
const time_utils = require("time_utils");
const exs = require("exstats").getStats(
["dist", "pacec"],
{
notify: {
dist: {
increment: 1000,
},
},
},
);
const S = require("Storage");
let drawTimeout: TimeoutId | undefined;
type Dist = number & { brand: 'dist' };
type Time = number & { brand: 'time' };
type Split = {
dist: Dist,
time: Time,
};
const splits: Split[] = []; // times
let splitOffset = 0, splitOffsetPx = 0;
const GPS_TIMEOUT_MS = 30000;
const layout = new Layout({
type: "v",
c: [
{
type: "txt",
font: "6x8:2",
label: "Pace",
id: "paceLabel",
pad: 4
},
{
type: "txt",
font: "Vector:40",
label: "",
id: "pace",
halign: 0
},
{
type: "txt",
font: "6x8:2",
label: "Time",
id: "timeLabel",
pad: 4
},
{
type: "txt",
font: "Vector:40",
label: "",
id: "time",
halign: 0
},
]
}, {
lazy: true
});
const draw = () => {
if (!exs.state.active) {
// no draw-timeout here, only on user interaction
drawSplits();
return;
}
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(draw, 1000);
const now = Date.now();
let pace: string;
if ("time" in exs.state.thisGPS
&& now - (exs.state.thisGPS.time as unknown as number) < GPS_TIMEOUT_MS)
{
pace = exs.stats.pacec.getString()
}else{
pace = "No GPS";
}
layout["time"]!.label = formatDuration(exs.state.duration);
layout["pace"]!.label = pace;
layout.render();
};
const pad2 = (n: number) => `0${n}`.substr(-2);
const formatDuration = (ms: number) => {
const tm = time_utils.decodeTime(ms);
if(tm.h)
return `${tm.h}:${pad2(tm.m)}:${pad2(tm.s)}`;
return `${pad2(tm.m)}:${pad2(tm.s)}`;
};
// divide by actual distance, scale to milliseconds
const calculatePace = (split: Split) => formatDuration(split.time / split.dist * 1000);
const drawSplits = () => {
g.clearRect(Bangle.appRect);
const barSize = 20;
const barSpacing = 10;
const w = g.getWidth();
const h = g.getHeight();
const max = splits.reduce((a, s) => Math.max(a, s.time), 0);
g.setFont("6x8", 2).setFontAlign(-1, -1);
let i = 0;
for(; ; i++) {
const split = splits[i + splitOffset];
if (split == null) break;
const y = Bangle.appRect.y + i * (barSize + barSpacing) + barSpacing / 2;
if (y > h) break;
const size = w * split.time / max; // Scale bar height based on pace
g.setColor("#00f").fillRect(0, y, size, y + barSize);
const splitPace = calculatePace(split); // Pace per km
drawSplit(i, y, splitPace);
}
const pace = exs.stats.pacec.getString();
const y = Bangle.appRect.y + i * (barSize + barSpacing) + barSpacing / 2;
drawSplit(i, y, pace);
};
const drawSplit = (i: number, y: number, pace: number | string) => {
g
.setColor(g.theme.fg)
.drawString(
`${i + 1 + splitOffset} ${typeof pace === "number" ? pace.toFixed(2) : pace}`,
0,
y
);
};
const pauseRun = () => {
exs.stop();
Bangle.setGPSPower(0, "pace")
draw();
};
const resumeRun = () => {
exs.resume();
Bangle.setGPSPower(1, "pace");
g.clearRect(Bangle.appRect); // splits -> layout, clear. layout -> splits, fine
layout.forgetLazyState();
draw();
};
const onButton = () => {
if (exs.state.active)
pauseRun();
else
resumeRun();
};
exs.start(); // aka reset
exs.stats.dist.on("notify", (dist) => {
const prev = { time: 0, dist: 0 };
for(const s of splits){
prev.time += s.time;
prev.dist += s.dist;
}
const totalDist = dist.getValue();
let thisSplit = totalDist - prev.dist;
let thisTime = exs.state.duration - prev.time;
while(thisSplit > 1000) {
splits.push({ dist: thisSplit as Dist, time: thisTime as Time });
thisTime = 0; // if we've jumped more than 1k, credit the time to the first split
thisSplit -= 1000;
}
// subtract <how much we're over> off the next split notify
exs.state.notify.dist.next -= thisSplit;
S.writeJSON("pace.json", { splits });
});
Bangle.on('lock', locked => {
// treat an unlock (while running) as a pause
if(!locked && exs.state.active) onButton();
});
setWatch(() => onButton(), BTN1, { repeat: true });
Bangle.on('drag', e => {
if (exs.state.active || e.b === 0) return;
splitOffsetPx -= e.dy;
if (splitOffsetPx > 20) {
if (splitOffset < splits.length-3) splitOffset++, Bangle.buzz(30);
splitOffsetPx = 0;
} else if (splitOffsetPx < -20) {
if (splitOffset > 0) splitOffset--, Bangle.buzz(30);
splitOffsetPx = 0;
}
draw();
});
Bangle.on('twist', () => {
Bangle.setBacklight(1);
});
Bangle.loadWidgets();
Bangle.drawWidgets();
g.clearRect(Bangle.appRect);
draw();
}

14
apps/pace/metadata.json Normal file
View File

@ -0,0 +1,14 @@
{
"id": "pace",
"name": "Pace",
"version": "0.01",
"description": "Show pace and time running splits",
"icon": "app.png",
"tags": "run,running,fitness,outdoors",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{ "name": "pace.app.js","url": "app.js" },
{ "name": "pace.img","url": "app-icon.js","evaluate": true }
]
}

View File

@ -158,8 +158,8 @@ Bangle.on("GPS", function(fix) {
if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]);
if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]);
if (state.notify.dist.increment > 0 && state.notify.dist.next <= state.distance) {
stats["dist"].emit("notify",stats["dist"]);
state.notify.dist.next = state.notify.dist.next + state.notify.dist.increment;
stats["dist"].emit("notify",stats["dist"]);
}
});
@ -169,8 +169,8 @@ Bangle.on("step", function(steps) {
state.stepHistory[0] += steps-state.lastSteps;
state.lastSteps = steps;
if (state.notify.step.increment > 0 && state.notify.step.next <= steps) {
stats["step"].emit("notify",stats["step"]);
state.notify.step.next = state.notify.step.next + state.notify.step.increment;
stats["step"].emit("notify",stats["step"]);
}
});
Bangle.on("HRM", function(h) {
@ -336,8 +336,8 @@ exports.getStats = function(statIDs, options) {
if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]);
}
if (state.notify.time.increment > 0 && state.notify.time.next <= now) {
stats["time"].emit("notify",stats["time"]);
state.notify.time.next = state.notify.time.next + state.notify.time.increment;
stats["time"].emit("notify",stats["time"]);
}
}, 1000);
function reset() {

83
typescript/types/exstats.d.ts vendored Normal file
View File

@ -0,0 +1,83 @@
declare module ExStats {
type StatsId = "time" | "dist" | "step" | "bpm" | "maxbpm" | "pacea" | "pacec" | "speed" | "caden" | "altg" | "altb";
function getList(): { name: string, id: StatsId }[];
function getStats<Ids extends StatsId>(
ids: Ids[],
options?: Options<Ids>
): StatsInst<Ids>;
type Options<Ids> = {
paceLength?: number,
notify?: NotifyInput<Ids>,
};
type Notify<Ids> = {
[key in Ids & ("dist" | "step" | "time")]: {
increment: number,
next: number,
}
};
type NotifyInput<Ids> = {
[K in keyof Notify<Ids>]?:
Omit<
Notify<Ids>[K], "next"
> & {
next?: number,
};
};
type StatsInst<Ids extends StatsId> = {
stats: Stats<Ids>,
state: State<Ids>,
start(): void,
stop(): void,
resume(): void,
};
type State<Ids> = {
notify: Notify<Ids>,
active: boolean,
duration: number,
startTime: number,
lastTime: number,
BPM: number,
BPMage: number,
maxBPM: number,
alt: number | undefined,
alti: number,
avrSpeed: number,
curSpeed: number,
distance: number,
startSteps: number,
lastSteps: number,
stepHistory: Uint8Array,
stepsPerMin: number,
thisGPS: GPSFix | {},
lastGPS: GPSFix | {},
};
type Stats<Ids extends StatsId> = {
[key in Ids]: Stat
};
type Stat = {
title: string,
getValue(): number,
getString(): string,
id: StatsId,
on(what: "changed", cb: (stat: Stat) => void): void;
// emitted by dist|step|time
on(what: "notify", cb: (stat: Stat) => void): void;
};
}

View File

@ -7,7 +7,16 @@ type ExtractIds<T extends Layout.Hierarchy, Depth extends Prev[number] = 9> =
[Depth] extends [never]
? never
: (T extends { id?: infer Id extends string }
? { [k in Id]: { -readonly [P in keyof T]: T[P] extends string ? string : T[P] } }
? {
[k in Id]: {
-readonly [P in keyof T]:
T[P] extends string
? string
: T[P] extends number
? number | undefined
: T[P]
}
}
: never)
|
(

View File

@ -586,7 +586,7 @@ declare class ESP32 {
* @param {boolean} enable - switches Bluetooth on or off
* @url http://www.espruino.com/Reference#l_ESP32_enableBLE
*/
static enableBLE(enable: boolean): void;
static enableBLE(enable: ShortBoolean): void;
/**
* Switches Wifi off/on, removes saved code from Flash, resets the board, and on
@ -595,7 +595,7 @@ declare class ESP32 {
* @param {boolean} enable - switches Wifi on or off
* @url http://www.espruino.com/Reference#l_ESP32_enableWifi
*/
static enableWifi(enable: boolean): void;
static enableWifi(enable: ShortBoolean): void;
/**
* This function is useful for ESP32 [OTA Updates](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/ota.html)
@ -609,7 +609,7 @@ declare class ESP32 {
* @param {boolean} isValid - Set whether this app is valid or not. If `isValid==false` the device will reboot.
* @url http://www.espruino.com/Reference#l_ESP32_setOTAValid
*/
static setOTAValid(isValid: boolean): void;
static setOTAValid(isValid: ShortBoolean): void;
}
@ -934,11 +934,11 @@ declare class NRF {
/**
* Called when Bluetooth advertising starts or stops on Espruino
* @param {string} event - The event to listen to.
* @param {(isAdvertising: boolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* @param {(isAdvertising: ShortBoolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `isAdvertising` Whether we are advertising or not
* @url http://www.espruino.com/Reference#l_NRF_advertising
*/
static on(event: "advertising", callback: (isAdvertising: boolean) => void): void;
static on(event: "advertising", callback: (isAdvertising: ShortBoolean) => void): void;
/**
* Called during the bonding process to update on status
@ -1064,7 +1064,7 @@ declare class NRF {
* @returns {any} MAC address - a string of the form 'aa:bb:cc:dd:ee:ff'
* @url http://www.espruino.com/Reference#l_NRF_getAddress
*/
static getAddress(current: boolean): any;
static getAddress(current: ShortBoolean): any;
/**
* Set this device's default Bluetooth MAC address:
@ -1643,7 +1643,7 @@ declare class NRF {
* @param {boolean} lowPower - Whether the connection is low power or not
* @url http://www.espruino.com/Reference#l_NRF_setLowPowerConnection
*/
static setLowPowerConnection(lowPower: boolean): void;
static setLowPowerConnection(lowPower: ShortBoolean): void;
/**
* Enables NFC and starts advertising the given URL. For example:
@ -1770,7 +1770,7 @@ declare class NRF {
* @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): void;
static ancsAction(uid: number, positive: ShortBoolean): void;
/**
* Get ANCS info for a notification event received via `E.ANCS`, e.g.:
@ -2059,7 +2059,7 @@ declare class NRF {
* @param {boolean} whitelisting - Are we using a whitelist? (default false)
* @url http://www.espruino.com/Reference#l_NRF_setWhitelist
*/
static setWhitelist(whitelisting: boolean): void;
static setWhitelist(whitelisting: ShortBoolean): void;
/**
* When connected, Bluetooth LE devices communicate at a set interval. Lowering the
@ -2245,7 +2245,7 @@ declare class NRF {
* @returns {any} A promise
* @url http://www.espruino.com/Reference#l_NRF_startBonding
*/
static startBonding(forceRepair: boolean): any;
static startBonding(forceRepair: ShortBoolean): any;
}
@ -2350,7 +2350,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): void;
static setLCDPower(isOn: ShortBoolean): void;
/**
* Writes a command directly to the ST7567 LCD controller
@ -2480,7 +2480,7 @@ declare class url {
* @returns {any} An object containing options for ```http.request``` or ```http.get```. Contains `method`, `host`, `path`, `pathname`, `search`, `port` and `query`
* @url http://www.espruino.com/Reference#l_url_parse
*/
static parse(urlStr: any, parseQuery: boolean): any;
static parse(urlStr: any, parseQuery: ShortBoolean): any;
}
@ -3730,7 +3730,7 @@ declare class Qwiic {
* @returns {any} The same Qwiic object (for call chaining)
* @url http://www.espruino.com/Reference#l_Qwiic_setPower
*/
setPower(isOn: boolean): any;
setPower(isOn: ShortBoolean): any;
/**
* @returns {any} An I2C object using this Qwiic connector, already set up
@ -3800,11 +3800,11 @@ declare class Bangle {
/**
* Has the watch been moved so that it is face-up, or not face up?
* @param {string} event - The event to listen to.
* @param {(up: boolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* @param {(up: ShortBoolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `up` `true` if face-up
* @url http://www.espruino.com/Reference#l_Bangle_faceUp
*/
static on(event: "faceUp", callback: (up: boolean) => void): void;
static on(event: "faceUp", callback: (up: ShortBoolean) => void): void;
/**
* This event happens when the watch has been twisted around it's axis - for
@ -3819,11 +3819,11 @@ declare class Bangle {
/**
* Is the battery charging or not?
* @param {string} event - The event to listen to.
* @param {(charging: boolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* @param {(charging: ShortBoolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `charging` `true` if charging
* @url http://www.espruino.com/Reference#l_Bangle_charging
*/
static on(event: "charging", callback: (charging: boolean) => void): void;
static on(event: "charging", callback: (charging: ShortBoolean) => void): void;
/**
* Magnetometer/Compass data available with `{x,y,z,dx,dy,dz,heading}` object as a
@ -3848,7 +3848,7 @@ declare class Bangle {
* 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)`.
* @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:
* @param {(nmea: any, dataLoss: ShortBoolean) => 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
@ -3942,31 +3942,31 @@ declare class Bangle {
* 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:
* @param {(on: ShortBoolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `on` `true` if screen is on
* @url http://www.espruino.com/Reference#l_Bangle_lcdPower
*/
static on(event: "lcdPower", callback: (on: boolean) => void): void;
static on(event: "lcdPower", callback: (on: ShortBoolean) => void): void;
/**
* Has the backlight been turned on or off? Can be used to stop tasks that are no
* longer useful if want to see in sun screen only. Also see `Bangle.isBacklightOn()`
* @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:
* @param {(on: ShortBoolean) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `on` `true` if backlight is on
* @url http://www.espruino.com/Reference#l_Bangle_backlight
*/
static on(event: "backlight", callback: (on: boolean) => void): void;
static on(event: "backlight", callback: (on: ShortBoolean) => void): void;
/**
* Has the screen been locked? Also see `Bangle.isLocked()`
* @param {string} event - The event to listen to.
* @param {(on: boolean, reason: string) => void} callback - A function that is executed when the event occurs. Its arguments are:
* @param {(on: ShortBoolean, reason: string) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `on` `true` if screen is locked, `false` if it is unlocked and touchscreen/buttons will work
* * `reason` (2v20 onwards) If known, the reason for locking/unlocking - 'button','js','tap','doubleTap','faceUp','twist','timeout'
* @url http://www.espruino.com/Reference#l_Bangle_lock
*/
static on(event: "lock", callback: (on: boolean, reason: string) => void): void;
static on(event: "lock", callback: (on: ShortBoolean, reason: string) => void): void;
/**
* If the watch is tapped, this event contains information on the way it was
@ -4103,7 +4103,7 @@ declare class Bangle {
* @param {boolean} isOn - True if the LCD backlight should be on, false if not
* @url http://www.espruino.com/Reference#l_Bangle_setBacklight
*/
static setBacklight(isOn: boolean): void;
static setBacklight(isOn: ShortBoolean): void;
/**
* This function can be used to turn Bangle.js's LCD off or on.
@ -4122,7 +4122,7 @@ declare class Bangle {
* @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): void;
static setLCDPower(isOn: ShortBoolean): void;
/**
* This function can be used to adjust the brightness of Bangle.js's display, and
@ -4309,6 +4309,9 @@ declare class Bangle {
* off
* * `btnLoadTimeout` how many milliseconds does the home button have to be pressed
* for before the clock is reloaded? 1500ms default, or 0 means never.
* * `manualWatchdog` if set, this disables automatic kicking of the watchdog timer
* from the interrupt (when the button isn't held). You will then have to manually
* call `E.kickWatchdog()` from your code or the watch will reset after ~5 seconds.
* * `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
@ -4362,7 +4365,7 @@ declare class Bangle {
* @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): void;
static setLocked(isLocked: ShortBoolean): void;
/**
* Also see the `Bangle.lock` event
@ -4925,7 +4928,7 @@ declare class Bangle {
* @param {boolean} noReboot - Do not reboot the watch when done (default false, so will reboot)
* @url http://www.espruino.com/Reference#l_Bangle_factoryReset
*/
static factoryReset(noReboot: boolean): void;
static factoryReset(noReboot: ShortBoolean): void;
/**
* Returns the rectangle on the screen that is currently reserved for the app.
@ -5170,7 +5173,7 @@ 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<void>;
startBonding(forceRePair: ShortBoolean): Promise<void>;
/**
* Return an object with information about the security state of the current
@ -5453,9 +5456,10 @@ declare class Graphics<IsBuffer extends boolean = boolean> {
* An object of other options. `{ zigzag : true/false(default), vertical_byte : true/false(default), msb : true/false(default), color_order: 'rgb'(default),'bgr',etc }`
* `zigzag` = whether to alternate the direction of scanlines for rows
* `vertical_byte` = whether to align bits in a byte vertically or not
* `msb` = when bits<8, store pixels most significant bit first, when bits>8, store most significant byte first
* `msb` = when bits<8, store pixels most significant bit first, when bits>8, store most significant byte first (as of 2v25, msb:true is default)
* `interleavex` = Pixels 0,2,4,etc are from the top half of the image, 1,3,5,etc from the bottom half. Used for P3 LED panels.
* `color_order` = re-orders the colour values that are supplied via setColor
* `buffer` = if specified, createArrayBuffer won't create a new buffer but will use the given one
* @returns {any} The new Graphics object
* @url http://www.espruino.com/Reference#l_Graphics_createArrayBuffer
*/
@ -5586,7 +5590,7 @@ declare class Graphics<IsBuffer extends boolean = boolean> {
* @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): void;
flip(all?: ShortBoolean): void;
/**
* On Graphics instances with an offscreen buffer, this is an `ArrayBuffer` that
@ -5650,7 +5654,7 @@ declare class Graphics<IsBuffer extends boolean = boolean> {
* @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?: ShortBoolean): Graphics;
/**
* Fill a rectangular area in the Foreground Color
@ -6584,7 +6588,7 @@ declare class WioLTE {
* @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): void;
static setGrovePower(onoff: ShortBoolean): void;
/**
* Turn power to the WIO's LED on or off.
@ -6594,7 +6598,7 @@ declare class WioLTE {
* @param {boolean} onoff - true = on, false = off
* @url http://www.espruino.com/Reference#l_WioLTE_setLEDPower
*/
static setLEDPower(onoff: boolean): void;
static setLEDPower(onoff: ShortBoolean): void;
/**
* @returns {any}
@ -6641,33 +6645,83 @@ declare class WioLTE {
* @url http://www.espruino.com/Reference#Waveform
*/
declare class Waveform {
/**
* Event emitted when playback has finished
* @param {string} event - The event to listen to.
* @param {(buffer: any) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `buffer` the last played buffer
* @url http://www.espruino.com/Reference#l_Waveform_finish
*/
static on(event: "finish", callback: (buffer: any) => void): void;
/**
* When in double-buffered mode, this event is emitted when the `Waveform` class swaps to playing a new buffer - so you should then fill this current buffer up with new data.
* @param {string} event - The event to listen to.
* @param {(buffer: any) => void} callback - A function that is executed when the event occurs. Its arguments are:
* * `buffer` the last played buffer (which now needs to be filled ready for playback)
* @url http://www.espruino.com/Reference#l_Waveform_buffer
*/
static on(event: "buffer", callback: (buffer: any) => void): void;
/**
* 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.
* Options can contain:
* ```JS
* {
* doubleBuffer : bool // whether to allocate two buffers or not (default false)
* bits : 8/16 // the amount of bits to use (default 8).
* }
* ```
* 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).
* ```JS
* // Output a sine wave
* var w = new Waveform(1000);
* for (var i=0;i<1000;i++) w.buffer[i]=128+120*Math.sin(i/2);
* analogWrite(H0, 0.5, {freq:80000}); // set up H0 to output an analog value by PWM
* w.on("finish", () => print("Done!"))
* w.startOutput(H0,8000); // start playback
* // On 2v25, from Storage
* var f = require("Storage").read("sound.pcm");
* var w = new Waveform(E.toArrayBuffer(f));
* w.on("finish", () => print("Done!"))
* w.startOutput(H0,8000); // start playback
* ```
* See https://www.espruino.com/Waveform for more examples.
* @constructor
*
* @param {number} samples - The number of samples
* @param {any} options - Optional options struct `{doubleBuffer:bool, bits : 8/16}` where: `doubleBuffer` is whether to allocate two buffers or not (default false), and bits is the amount of bits to use (default 8).
* @param {any} samples - The number of samples to allocate as an integer, *or* an arraybuffer (2v25+) containing the samples
* @param {any} [options] - [optional] options struct `{ doubleBuffer:bool, bits : 8/16 }` (see below)
* @returns {any} An Waveform object
* @url http://www.espruino.com/Reference#l_Waveform_Waveform
*/
static new(samples: number, options: any): any;
static new(samples: any, 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.
* ```
* {
* time : float, // the that the waveform with start output at, e.g. `getTime()+1` (otherwise it is immediate)
* repeat : bool, // whether to repeat the given sample
* npin : Pin, // If specified, the waveform is output across two pins (see below)
* }
* ```
* Using `npin` allows you to split the Waveform output between two pins and hence avoid
* any DC bias (or need to capacitor), for instance you could attach a speaker to `H0` and
* `H1` on Jolt.js. When the value in the waveform was at 50% both outputs would be 0,
* below 50% the signal would be on `npin` with `pin` as 0, and above 50% it would be on `pin` with `npin` as 0.
*
* @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
* @param {any} [options] - [optional] options struct `{time:float, repeat:bool, npin:Pin}` (see below)
* @url http://www.espruino.com/Reference#l_Waveform_startOutput
*/
startOutput(output: Pin, freq: number, options: any): void;
startOutput(output: Pin, freq: number, options?: any): void;
/**
* Will start inputting the waveform on the given pin that supports analog. If not
@ -6675,10 +6729,10 @@ declare class Waveform {
*
* @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
* @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): void;
startInput(output: Pin, freq: number, options?: any): void;
/**
* Stop a waveform that is currently outputting
@ -7869,11 +7923,24 @@ interface MathConstructor {
pow(x: number, y: number): number;
/**
* @returns {number} A random number between 0 and 1
* @returns {number} A random number X, where `0 <= X < 1`
* @url http://www.espruino.com/Reference#l_Math_random
*/
random(): number;
/**
* (Added in 2v25) Returns a random integer `X`, where `0 <= X < range`, or `-2147483648 <= X <= 2147483647` if `range <= 0` or `undefined`
* If `range` is supplied, this value is created using `modulo` of a 31 bit integer, so as `val` gets larger (24+ bits)
* the values produced will be less randomly distributed, and no values above `0x7FFFFFFF` will ever be returned.
* If `val==undefined` or `val<=0` a **32 bit** random number will be returned as an int (`-2147483648` .. `2147483647`).
* **Note:** this is not part of the JS spec, but is included in Espruino as it makes a lot of sense on embedded targets
*
* @param {number} range - How big a random number do we want
* @returns {number} A random integer
* @url http://www.espruino.com/Reference#l_Math_randInt
*/
randInt(range: number): number;
/**
*
* @param {number} x - The value to round
@ -8294,6 +8361,10 @@ declare class E {
* menu is removed
* * (Bangle.js 2) `scroll : int` - an integer specifying how much the initial
* menu should be scrolled by
* * (Bangle.js 2) The mapped functions can consider the touch event that interacted with the entry:
* `"Entry" : function(touch) { ... }`
* * This is also true of `onchange` mapped functions in entry objects:
* `onchange : (value, touch) => { ... }`
* * 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
@ -8397,6 +8468,7 @@ declare class E {
* draw : function(idx, rect) { ... }
* // a function to call when the item is selected, touch parameter is only relevant
* // for Bangle.js 2 and contains the coordinates touched inside the selected item
* // as well as the type of the touch - see `Bangle.touch`.
* select : function(idx, touch) { ... }
* // optional function to be called when 'back' is tapped
* back : function() { ...}
@ -9047,6 +9119,23 @@ declare class E {
*/
static setClock(options: number | { M: number, N: number, P: number, Q: number, latency?: number, PCLK?: number, PCLK2?: number }): number;
/**
* On boards other than STM32 this currently just returns `undefined`
* ### STM32
* See `E.setClock` for more information.
* Returns:
* ```
* {
* sysclk, hclk, pclk1, pclk2, // various clocks in Hz
* M, N, P, Q, PCLK1, PCLK2 // STM32F4: currently set divisors
* RTCCLKSource : "LSI/LSE/HSE_Div#" // STM32F4 source for RTC clock
* }
* ```
* @returns {any} An object containing information about the current clock
* @url http://www.espruino.com/Reference#l_E_getClock
*/
static getClock(): any;
/**
* 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
@ -9186,7 +9275,7 @@ declare class E {
* @returns {number} The address of the given variable
* @url http://www.espruino.com/Reference#l_E_getAddressOf
*/
static getAddressOf(v: any, flatAddress: boolean): number;
static getAddressOf(v: any, flatAddress: ShortBoolean): number;
/**
* Take each element of the `from` array, look it up in `map` (or call
@ -9519,7 +9608,7 @@ declare class E {
* @returns {number} The RTC prescaler's current value
* @url http://www.espruino.com/Reference#l_E_getRTCPrescaler
*/
static getRTCPrescaler(calibrate: boolean): number;
static getRTCPrescaler(calibrate: ShortBoolean): number;
/**
* This function returns an object detailing the current **estimated** power usage
@ -9646,7 +9735,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): void;
write(data: any, power: ShortBoolean): void;
/**
* Read a byte
@ -10140,6 +10229,8 @@ interface Array<T> {
/**
* Return an array which is made from the following: ```A.map(function) =
* [function(A[0]), function(A[1]), ...]```
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.map(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} function - Function used to map one item to another
* @param {any} [thisArg] - [optional] If specified, the function is called with 'this' set to thisArg
@ -10150,6 +10241,8 @@ interface Array<T> {
/**
* Executes a provided function once per array element.
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.forEach(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} function - Function to be executed
* @param {any} [thisArg] - [optional] If specified, the function is called with 'this' set to thisArg
@ -10160,6 +10253,8 @@ interface Array<T> {
/**
* Return an array which contains only those elements for which the callback
* function returns 'true'
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.filter(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} function - Function to be executed
* @param {any} [thisArg] - [optional] If specified, the function is called with 'this' set to thisArg
@ -10176,6 +10271,8 @@ interface Array<T> {
* ["Hello","There","World"].find(a=>a[0]=="T")
* // returns "There"
* ```
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.find(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} function - Function to be executed
* @returns {any} The array element where `function` returns `true`, or `undefined`
@ -10191,6 +10288,8 @@ interface Array<T> {
* ["Hello","There","World"].findIndex(a=>a[0]=="T")
* // returns 1
* ```
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.findIndex(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} function - Function to be executed
* @returns {any} The array element's index where `function` returns `true`, or `-1`
@ -10201,6 +10300,8 @@ interface Array<T> {
/**
* Return 'true' if the callback returns 'true' for any of the elements in the
* array
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.some(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} function - Function to be executed
* @param {any} [thisArg] - [optional] If specified, the function is called with 'this' set to thisArg
@ -10211,6 +10312,8 @@ interface Array<T> {
/**
* Return 'true' if the callback returns 'true' for every element in the array
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.every(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} function - Function to be executed
* @param {any} [thisArg] - [optional] If specified, the function is called with 'this' set to thisArg
@ -10223,13 +10326,15 @@ interface Array<T> {
* Execute `previousValue=initialValue` and then `previousValue =
* callback(previousValue, currentValue, index, array)` for each element in the
* array, and finally return previousValue.
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.reduce(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @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: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T;
reduce<O>(callback: (previousValue: O, currentValue: T, currentIndex: number, array: T[]) => O, initialValue?: O): O;
/**
* Both remove and add items to an array
@ -10274,6 +10379,8 @@ interface Array<T> {
/**
* Do an in-place quicksort of the array
* **Note:** Do not modify the array you're iterating over from inside the callback (`a.sort(()=>a.push(0))`).
* It will cause non-spec-compliant behaviour.
*
* @param {any} var - A function to use to compare array elements (or undefined)
* @returns {any} This array object
@ -10339,8 +10446,6 @@ 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.
*
* @param {any} string - A JSON string
* @returns {any} The JavaScript object created by parsing the data string
@ -10922,7 +11027,7 @@ declare class Serial {
* @param {boolean} force - Whether to force the console to this port
* @url http://www.espruino.com/Reference#l_Serial_setConsole
*/
setConsole(force: boolean): void;
setConsole(force: ShortBoolean): void;
/**
* Setup this Serial port with the given baud rate and options.
@ -11595,7 +11700,7 @@ declare class Pin {
* @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): void;
write(value: ShortBoolean): void;
/**
* Sets the output state of the pin to the parameter given at the specified time.
@ -11603,10 +11708,10 @@ declare class Pin {
* 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
* @param {number} time - Time at which to write (in seconds)
* @url http://www.espruino.com/Reference#l_Pin_writeAtTime
*/
writeAtTime(value: boolean, time: number): void;
writeAtTime(value: ShortBoolean, time: number): void;
/**
* Return the current mode of the given pin. See `pinMode` for more information.
@ -11646,7 +11751,7 @@ declare class Pin {
* @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_Pin_pulse
*/
pulse(value: boolean, time: any): void;
pulse(value: ShortBoolean, time: any): void;
/**
* (Added in 2v20) Get the analogue value of the given pin. See `analogRead` for more information.
@ -11678,6 +11783,8 @@ declare class Pin {
* {
* "port" : "A", // the Pin's port on the chip
* "num" : 12, // the Pin's number
* "mode" : (2v25+) // string: the pin's mode (same as Pin.getMode())
* "output" : (2v25+) // 0/1: the state of the pin's output register
* "in_addr" : 0x..., // (if available) the address of the pin's input address in bit-banded memory (can be used with peek)
* "out_addr" : 0x..., // (if available) the address of the pin's output address in bit-banded memory (can be used with poke)
* "analog" : { ADCs : [1], channel : 12 }, // If analog input is available
@ -11716,6 +11823,67 @@ declare const Boolean: BooleanConstructor
// GLOBALS
/**
* @returns {any} An object containing the pins for the Qwiic connector on Curio `{sda,scl}`
* @url http://www.espruino.com/Reference#l__global_Q
*/
declare const Q: Qwiic;
/**
* @returns {Pin} The pin for the servo motor
* @url http://www.espruino.com/Reference#l__global_SERVO
*/
declare const SERVO: Pin;
/**
* @returns {Pin} The pin for the IR LED
* @url http://www.espruino.com/Reference#l__global_IRLED
*/
declare const IRLED: Pin;
/**
* @returns {Pin} The pin for the left IR sensor
* @url http://www.espruino.com/Reference#l__global_IRL
*/
declare const IRL: Pin;
/**
* @returns {Pin} The pin for the left motor
* @url http://www.espruino.com/Reference#l__global_ML1
*/
declare const ML1: Pin;
/**
* @returns {Pin} The pin for the left motor
* @url http://www.espruino.com/Reference#l__global_ML2
*/
declare const ML2: Pin;
/**
* @returns {Pin} The pin for the right IR sensor
* @url http://www.espruino.com/Reference#l__global_IRR
*/
declare const IRR: Pin;
/**
* @returns {Pin} The pin for the right motor
* @url http://www.espruino.com/Reference#l__global_MR1
*/
declare const MR1: Pin;
/**
* @returns {Pin} The pin for the right motor
* @url http://www.espruino.com/Reference#l__global_MR2
*/
declare const MR2: Pin;
/**
*
* @param {any} col - The colours to use, a 24 element array (8 x RGB)
* @url http://www.espruino.com/Reference#l__global_led
*/
declare function led(col: any): void;
/**
* The pin marked SDA on the Arduino pin footprint. This is connected directly to
* pin A4.
@ -12042,7 +12210,7 @@ declare function setSleepIndicator(pin: any): void;
* @param {boolean} sleep
* @url http://www.espruino.com/Reference#l__global_setDeepSleep
*/
declare function setDeepSleep(sleep: boolean): void;
declare function setDeepSleep(sleep: ShortBoolean): void;
/**
* Output current interpreter state in a text form such that it can be copied to a
@ -12120,7 +12288,7 @@ declare function save(): void;
* @param {boolean} clearFlash - Remove saved code from flash as well
* @url http://www.espruino.com/Reference#l__global_reset
*/
declare function reset(clearFlash: boolean): void;
declare function reset(clearFlash: ShortBoolean): void;
/**
* Fill the console with the contents of the given function, so you can edit it.
@ -12140,7 +12308,7 @@ declare function edit(funcName: any): void;
* @param {boolean} echoOn
* @url http://www.espruino.com/Reference#l__global_echo
*/
declare function echo(echoOn: boolean): void;
declare function echo(echoOn: ShortBoolean): void;
/**
* Return the current system time in Seconds (as a floating point number)
@ -12541,7 +12709,7 @@ declare function shiftOut(pins: Pin | Pin[], options: { clk?: Pin, clkPol?: bool
* // setting irq:true will call that function in the interrupt itself
* irq : false(default)
* // Advanced: If specified, the given pin will be read whenever the watch is called
* // and the state will be included as a 'data' field in the callback
* // and the state will be included as a 'data' field in the callback (`debounce:0` is required)
* data : pin
* // Advanced: On Nordic devices, a watch may be 'high' or 'low' accuracy. By default low
* // accuracy is used (which is better for power consumption), but this means that
@ -12558,7 +12726,7 @@ declare function shiftOut(pins: Pin | Pin[], options: { clk?: Pin, clkPol?: bool
* 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
* used for reading in clocked data. It will only work if `debounce:0` is used
* 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
@ -12597,6 +12765,16 @@ declare function clearWatch(id: number): void;
declare function clearWatch(): void;
declare const global: {
Q: typeof Q;
SERVO: typeof SERVO;
IRLED: typeof IRLED;
IRL: typeof IRL;
ML1: typeof ML1;
ML2: typeof ML2;
IRR: typeof IRR;
MR1: typeof MR1;
MR2: typeof MR2;
led: typeof led;
SDA: typeof SDA;
SCL: typeof SCL;
show: typeof show;
@ -13032,7 +13210,7 @@ declare module "ESP8266" {
* @param {boolean} enable - Enable or disable the debug logging.
* @url http://www.espruino.com/Reference#l_ESP8266_logDebug
*/
function logDebug(enable: boolean): void;
function logDebug(enable: ShortBoolean): void;
/**
* Set the debug logging mode. It can be disabled (which frees ~1.2KB of heap),
@ -14590,7 +14768,7 @@ declare module "Storage" {
* @param {boolean} [showMessage] - [optional] If true, an overlay message will be displayed on the screen while compaction is happening. Default is false.
* @url http://www.espruino.com/Reference#l_Storage_compact
*/
function compact(showMessage?: boolean): void;
function compact(showMessage?: ShortBoolean): void;
/**
* This writes information about all blocks in flash memory to the console - and is
@ -14609,7 +14787,7 @@ declare module "Storage" {
* @returns {number} The amount of free bytes
* @url http://www.espruino.com/Reference#l_Storage_getFree
*/
function getFree(checkInternalFlash: boolean): number;
function getFree(checkInternalFlash: ShortBoolean): number;
/**
* Returns:
@ -14629,7 +14807,7 @@ declare module "Storage" {
* @returns {any} An object containing info about the current Storage system
* @url http://www.espruino.com/Reference#l_Storage_getStats
*/
function getStats(checkInternalFlash: boolean): any;
function getStats(checkInternalFlash: ShortBoolean): any;
/**
* Writes a lookup table for files into Bangle.js's storage. This allows any file

View File

@ -6,3 +6,5 @@ declare function require(moduleName: "ClockFace"): typeof ClockFace_.ClockFace;
declare function require(moduleName: "clock_info"): typeof ClockInfo;
declare function require(moduleName: "Layout"): typeof Layout.Layout;
declare function require(moduleName: "power_usage"): PowerUsageModule;
declare function require(moduleName: "exstats"): typeof ExStats;
declare function require(moduleName: "time_utils"): typeof TimeUtils;

18
typescript/types/time_utils.d.ts vendored Normal file
View File

@ -0,0 +1,18 @@
declare module TimeUtils {
type TimeObj = {
d: number,
h: number,
m: number,
s: number,
};
function encodeTime(time: TimeObj): number;
function decodeTime(millis: number): TimeObj;
function formatTime(value: number | TimeObj): string
function formatDuration(value: number | TimeObj, compact?: boolean): string;
function getCurrentTimeMillis(): number;
}

5
typescript/types/utility.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};