mirror of https://github.com/espruino/BangleApps
Merge branch 'master' of github.com:espruino/BangleApps
commit
2434ac668e
|
@ -1 +1,3 @@
|
|||
0.01: New app!
|
||||
0.01: New app!
|
||||
0.02: Add sensor icons
|
||||
Customize code directly, remove config file
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -39,14 +39,27 @@
|
|||
<a href="https://my.home-assistant.io/redirect/profile/" target="_blank">your user profile</a>.</span></label>
|
||||
</form>
|
||||
<p>
|
||||
<button id="upload" class="btn btn-primary">Upload</button>
|
||||
<button id="upload" class="btn btn-primary" disabled>Upload</button>
|
||||
</p>
|
||||
<script src="../../core/lib/customize.js"></script>
|
||||
<script>
|
||||
const STORAGE_KEY = 'hasensors-config';
|
||||
const fields = ['id', 'name', 'url', 'token'];
|
||||
const form = document.getElementById('sensorform');
|
||||
const STORAGE_KEY = "hasensors-config";
|
||||
const fields = ["id", "name", "url", "token"];
|
||||
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);
|
||||
if (stored) {
|
||||
try {
|
||||
|
@ -62,7 +75,7 @@
|
|||
}
|
||||
|
||||
document.getElementById("upload").addEventListener("click", function () {
|
||||
let config = {};
|
||||
// validate form fields or bail out
|
||||
for (const field of fields) {
|
||||
if (!form[field].validity.valid) {
|
||||
form[field].focus();
|
||||
|
@ -70,18 +83,21 @@
|
|||
return;
|
||||
}
|
||||
}
|
||||
let config = {};
|
||||
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));
|
||||
// replace {placeholders} in library code template
|
||||
const lib = libTpl.replace(/\{(\w+)\}/g, (_,f) => config[f]);
|
||||
console.log("config:", config, JSON.stringify(config));
|
||||
sendCustomizedApp({
|
||||
id: "hasensors",
|
||||
storage: [
|
||||
{name: "hasensors.boot.js", url: "boot.js"},
|
||||
{name: "hasensors", url: "lib.js"},
|
||||
{name: "hasensors.settings.json", content: JSON.stringify(config)},
|
||||
]
|
||||
{name: "hasensors", content: lib},
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
});
|
||||
}
|
|
@ -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"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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); };
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>,
|
||||
};
|
|
@ -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<IsBuffer extends boolean = boolean> {
|
|||
* `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<IsBuffer extends boolean = boolean> {
|
|||
* * 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<IsBuffer extends boolean = boolean> {
|
|||
*/
|
||||
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 {
|
||||
|
|
Loading…
Reference in New Issue