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 {