diff --git a/apps/hasensors/ChangeLog b/apps/hasensors/ChangeLog
index 759f68777..7b3a63039 100644
--- a/apps/hasensors/ChangeLog
+++ b/apps/hasensors/ChangeLog
@@ -1 +1,3 @@
-0.01: New app!
\ No newline at end of file
+0.01: New app!
+0.02: Add sensor icons
+ Customize code directly, remove config file
diff --git a/apps/hasensors/boot.js b/apps/hasensors/boot.js
index a9122be5d..efafbc8a3 100644
--- a/apps/hasensors/boot.js
+++ b/apps/hasensors/boot.js
@@ -1,5 +1,5 @@
(function () {
- const sb = () => require('hasensors').sendBattery();
+ const sb = () => require("hasensors").sendBattery();
Bangle.on("charging", sb);
NRF.on("connect", () => setTimeout(sb, 2000));
setInterval(sb, 10 * 60 * 1000);
diff --git a/apps/hasensors/custom.html b/apps/hasensors/custom.html
index 805001701..265f80f46 100644
--- a/apps/hasensors/custom.html
+++ b/apps/hasensors/custom.html
@@ -39,14 +39,27 @@
your user profile.
-
+
diff --git a/apps/hasensors/lib.js b/apps/hasensors/lib.js
index 60cfb6da4..83072262c 100644
--- a/apps/hasensors/lib.js
+++ b/apps/hasensors/lib.js
@@ -1,35 +1,43 @@
// split out into a separate file to keep bootcode short.
-function s(key) {
- return (require('Storage').readJSON('hasensors.settings.js', true) || {})[key];
-}
-
+// placeholders are replaced by custom.html before upload
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, {
- method: 'POST',
+ method: "POST",
body: JSON.stringify(data),
headers: {
- 'Content-Type': 'application/json',
- Authorization: 'Bearer ' + s('token'),
+ "Content-Type": "application/json",
+ Authorization: "Bearer {token}",
}
});
}
exports.sendBattery = function () {
if (!NRF.getSecurityStatus().connected) return;
- post('battery_level', {
- state: E.getBattery(),
+ const b = E.getBattery(),
+ c = Bangle.isCharging();
+ let i = "mdi:battery";
+ if (c) i += "-charging";
+
+ post("battery_state", {
+ state: c ? "charging" : "discharging",
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: "%",
device_class: "battery",
state_class: "measurement",
- }
- });
- post('battery_state', {
- state: Bangle.isCharging() ? 'charging' : 'discharging',
- attributes: {
- friendly_name: s('name') + " Battery State",
+ icon: i,
}
});
}
\ No newline at end of file
diff --git a/apps/hasensors/metadata.json b/apps/hasensors/metadata.json
index 7713fadc7..106f11407 100644
--- a/apps/hasensors/metadata.json
+++ b/apps/hasensors/metadata.json
@@ -2,7 +2,7 @@
"id": "hasensors",
"name": "Home Assistant Sensors",
"shortName": "HA sensors",
- "version": "0.01",
+ "version": "0.02",
"description": "Send sensor values to Home Assistant using the Android Integration.",
"icon": "ha.png",
"type": "bootloader",
@@ -14,8 +14,5 @@
"storage": [
{"name":"hasensors","url":"lib.js"},
{"name":"hasensors.boot.js","url":"boot.js"}
- ],
- "data": [
- {"name":"hasensors.settings.json"}
]
}
diff --git a/apps/widhid/ChangeLog b/apps/widhid/ChangeLog
index a6ed84766..b0e479108 100644
--- a/apps/widhid/ChangeLog
+++ b/apps/widhid/ChangeLog
@@ -1,3 +1,5 @@
0.01: New widget - music control via a swipe
0.02: Improve interactivity - avoid responding to swipes when a menu or
launcher is active.
+0.03: Handle errors when sending input over BLE and the special-case of
+ replacing a single handler
diff --git a/apps/widhid/metadata.json b/apps/widhid/metadata.json
index 84334636b..b819c9b64 100644
--- a/apps/widhid/metadata.json
+++ b/apps/widhid/metadata.json
@@ -2,7 +2,7 @@
"id": "widhid",
"name": "Bluetooth Music Swipe Control 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!",
"icon": "icon.png",
"readme": "README.md",
diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js
index dd411513e..06ef0cea4 100644
--- a/apps/widhid/wid.js
+++ b/apps/widhid/wid.js
@@ -81,7 +81,10 @@
if (!wasActive) {
waitForRelease = true;
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();
}
if (activeTimeout)
@@ -120,7 +123,12 @@
redraw();
});
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 prev = function () { return sendHid(0x02); };
diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts
index 3291c188d..e788be1a8 100644
--- a/apps/widhid/wid.ts
+++ b/apps/widhid/wid.ts
@@ -23,7 +23,7 @@
const onDrag = (e => {
// Espruino/35c8cb9be11
- (E as any).stopEventPropagation && (E as any).stopEventPropagation();
+ E.stopEventPropagation && E.stopEventPropagation();
if(e.b === 0){
// released
@@ -84,10 +84,15 @@
waitForRelease = true; // wait for first touch up before accepting gestures
Bangle.on("drag", onDrag);
+
// move our drag to the start of the event listener array
- (Bangle as any)["#ondrag"] = [onDrag].concat(
- (Bangle as any)["#ondrag"].filter((f: unknown) => f !== onDrag)
- );
+ const dragHandlers = (Bangle as BangleEvents)["#ondrag"]
+
+ if(dragHandlers && typeof dragHandlers !== "function"){
+ (Bangle as BangleEvents)["#ondrag"] = [onDrag as undefined | typeof onDrag].concat(
+ dragHandlers.filter((f: unknown) => f !== onDrag)
+ );
+ }
redraw();
}
@@ -140,10 +145,14 @@
//const DEBUG = true;
const sendHid = (code: number) => {
//if(DEBUG) return;
- NRF.sendHIDReport(
- [1, code],
- () => NRF.sendHIDReport([1, 0]),
- );
+ try{
+ NRF.sendHIDReport(
+ [1, code],
+ () => NRF.sendHIDReport([1, 0]),
+ );
+ }catch(e){
+ console.log("sendHIDReport:", e);
+ }
};
const next = () => /*DEBUG ? console.log("next") : */ sendHid(0x01);
diff --git a/typescript/types/bangle_extensions.d.ts b/typescript/types/bangle_extensions.d.ts
new file mode 100644
index 000000000..e5d94d079
--- /dev/null
+++ b/typescript/types/bangle_extensions.d.ts
@@ -0,0 +1,10 @@
+type BangleHandler 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,
+ ["#ontouch"]?: BangleHandler,
+ ["#ondrag"]?: BangleHandler,
+ ["#onstroke"]?: BangleHandler<(event: { xy: Uint8Array, stroke?: string }) => void>,
+};
diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts
index 4e4dd224e..59fb18d30 100644
--- a/typescript/types/main.d.ts
+++ b/typescript/types/main.d.ts
@@ -465,6 +465,46 @@ declare class ESP32 {
*/
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
* following fields:
@@ -5597,7 +5637,9 @@ declare class Graphics {
* `width,height,bpp,[transparent,]image_bytes...`. If a transparent colour is
* specified the top bit of `bpp` should be set.
* * An ArrayBuffer Graphics object (if `bpp<8`, `msb:true` must be set) - this is
- * disabled on devices without much flash memory available
+ * 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.
* * If the image is 1 bit, the graphics foreground/background colours will be
* used.
@@ -5678,6 +5720,9 @@ declare class Graphics {
* * Is 8 bpp *OR* the `{msb:true}` option was given
* * No other format options (zigzag/etc) were given
* Otherwise data will be copied, which takes up more space and may be quite slow.
+ * 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
* @returns {any} An Image that can be used with `Graphics.drawImage`
@@ -5800,6 +5845,19 @@ declare class Graphics {
*/
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:
* ```
@@ -8223,6 +8281,10 @@ declare class E {
/**
* Dump any locked variables that aren't referenced from `global` - for debugging
* 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
*/
static dumpLockedVars(): void;
@@ -8655,6 +8717,24 @@ declare class E {
*/
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);
* // 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} 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
*/
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 {