From ce51b0b0ba869900c54686516241301d47dfb082 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 20 Jun 2022 10:25:57 +0200 Subject: [PATCH 01/57] Add homeassistant app --- apps/cassioWatch/app.js | 100 +++++++++++++++++++++-- apps/homeassistant/ChangeLog | 1 + apps/homeassistant/README.md | 17 ++++ apps/homeassistant/homeassistant.app.js | 34 ++++++++ apps/homeassistant/homeassistant.icon.js | 1 + apps/homeassistant/homeassistant.png | Bin 0 -> 1548 bytes apps/homeassistant/metadata.json | 19 +++++ apps/homeassistant/screenshot_1.png | Bin 0 -> 3552 bytes apps/homeassistant/screenshot_2.png | Bin 0 -> 3334 bytes apps/homeassistant/screenshot_3.png | Bin 0 -> 3455 bytes 10 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 apps/homeassistant/ChangeLog create mode 100644 apps/homeassistant/README.md create mode 100644 apps/homeassistant/homeassistant.app.js create mode 100644 apps/homeassistant/homeassistant.icon.js create mode 100644 apps/homeassistant/homeassistant.png create mode 100644 apps/homeassistant/metadata.json create mode 100644 apps/homeassistant/screenshot_1.png create mode 100644 apps/homeassistant/screenshot_2.png create mode 100644 apps/homeassistant/screenshot_3.png diff --git a/apps/cassioWatch/app.js b/apps/cassioWatch/app.js index 6bbb9e823..3f5cfee40 100644 --- a/apps/cassioWatch/app.js +++ b/apps/cassioWatch/app.js @@ -4,8 +4,11 @@ require("Font6x12").add(Graphics); require("Font8x12").add(Graphics); require("Font7x11Numeric7Seg").add(Graphics); + +const TIMER_IDX = "cassioWatch"; + + function bigThenSmall(big, small, x, y) { - g.setFont("7x11Numeric7Seg", 2); g.drawString(big, x, y); x += g.stringWidth(big); g.setFont("8x12"); @@ -71,6 +74,7 @@ function drawClock() { } function drawBattery() { + g.setFont("7x11Numeric7Seg", 2); bigThenSmall(E.getBattery(), "%", 135, 21); } @@ -117,6 +121,59 @@ function getSteps() { return steps + "k"; } +function isAlarmEnabled(){ + try{ + var alarm = require('sched'); + var alarmObj = alarm.getAlarm(TIMER_IDX); + if(alarmObj===undefined || !alarmObj.on){ + return false; + } + + return true; + + } catch(ex){ } + return false; +} + +function getAlarmMinutes(){ + if(!isAlarmEnabled()){ + return -1; + } + + var alarm = require('sched'); + var alarmObj = alarm.getAlarm(TIMER_IDX); + return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000)); +} + +function increaseAlarm(){ + try{ + var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0; + var alarm = require('sched') + alarm.setAlarm(TIMER_IDX, { + timer : (minutes+5)*60*1000, + }); + alarm.reload(); + } catch(ex){ } +} + +function decreaseAlarm(){ + try{ + var minutes = getAlarmMinutes(); + minutes -= 5; + + var alarm = require('sched') + alarm.setAlarm(TIMER_IDX, undefined); + + if(minutes > 0){ + alarm.setAlarm(TIMER_IDX, { + timer : minutes*60*1000, + }); + } + + alarm.reload(); + } catch(ex){ } +} + function draw() { queueDraw(); @@ -128,10 +185,17 @@ function draw() { let background = getBackgroundImage(); g.drawImage(background, 0, 0, { scale: 1 }); g.setColor(0, 0, 0); - g.setFont("6x12"); - g.drawString("Launching Process", 30, 20); - g.setFont("8x12"); - g.drawString("ACTIVATE", 40, 35); + + if(!isAlarmEnabled()){ + g.setFont("6x12"); + g.drawString("Launching Process", 30, 20); + g.setFont("8x12"); + g.drawString("ACTIVATE", 40, 35); + } else { + g.setFont("8x12", 2); + // g.drawString("T-" + getAlarmMinutes()+ "min", 30, 23); + bigThenSmall("T-" + getAlarmMinutes(), " min.", 30, 23); + } g.setFontAlign(0,-1); g.setFont("8x12", 2); @@ -166,6 +230,32 @@ Bangle.on("lock", (locked) => { }); +Bangle.on('touch', function(btn, e){ + var left = parseInt(g.getWidth() * 0.2); + var right = g.getWidth() - left; + var upper = parseInt(g.getHeight() * 0.2); + var lower = g.getHeight() - upper; + + var is_left = e.x < left; + var is_right = e.x > right; + var is_upper = e.y < upper; + var is_lower = e.y > lower; + + if(is_upper){ + Bangle.buzz(40, 0.6); + increaseAlarm(); + draw(); + } + + if(is_lower){ + Bangle.buzz(40, 0.6); + decreaseAlarm(); + draw(); + } +}); + + + // Load widgets, but don't show them Bangle.loadWidgets(); Bangle.setUI("clock"); diff --git a/apps/homeassistant/ChangeLog b/apps/homeassistant/ChangeLog new file mode 100644 index 000000000..07afedd21 --- /dev/null +++ b/apps/homeassistant/ChangeLog @@ -0,0 +1 @@ +0.01: Release \ No newline at end of file diff --git a/apps/homeassistant/README.md b/apps/homeassistant/README.md new file mode 100644 index 000000000..6466febe3 --- /dev/null +++ b/apps/homeassistant/README.md @@ -0,0 +1,17 @@ +# Info + +A very simple app that shows information on 3 different screens. +Go to the next screen via tab right, go to the previous screen +via tab left and reload the data via tab in the middle of the +screen. Very useful if combined with pattern launcher ;) + +![](screenshot_1.png) +![](screenshot_2.png) +![](screenshot_3.png) + + +## Creator +- [David Peer](https://github.com/peerdavid). + +## Thanks To +Info icons created by Freepik - Flaticon diff --git a/apps/homeassistant/homeassistant.app.js b/apps/homeassistant/homeassistant.app.js new file mode 100644 index 000000000..e0a59547c --- /dev/null +++ b/apps/homeassistant/homeassistant.app.js @@ -0,0 +1,34 @@ +var W = g.getWidth(), H = g.getHeight(); + + +function draw() { + g.reset().clearRect(Bangle.appRect); + + // Header + g.setFont("Vector", 22).setFontAlign(0,-1); + g.drawString("", W/2, H/2); +} + + +draw(); +setWatch(_=>load(), BTN1); + +Bangle.on('touch', function(btn, e){ + var left = parseInt(g.getWidth() * 0.3); + var right = g.getWidth() - left; + var isLeft = e.x < left; + var isRight = e.x > right; + + if(isRight){ + + } + + if(isLeft){ + + } + + draw(); +}); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/homeassistant/homeassistant.icon.js b/apps/homeassistant/homeassistant.icon.js new file mode 100644 index 000000000..8dbab8357 --- /dev/null +++ b/apps/homeassistant/homeassistant.icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcBkmSpICDBwcJBYwCDpAhFggRJGg8SCI+ABgU//gSDCI4JBj//AAX4JRAIBg4QDAAPgBIJWGgIQFAAI+BLglAgEPCI/wEgJoEgYQHAAPANwhWFAApcBCIWQgAQJAAMAgSMDCJiSCwB6GQA6eCn5TFL4q5BUgIRF/wuBv4RGkCeGO4IREUgMBCJCVGCISwIWw0BYRLIICLBHHCJRrGCIQIFR44I5LIoRaPpARcdIwRJfYMBCJuACKUkgE/a5f8gEJCJD7FCIeAg78FAAvggFJCIMACJZOBCIOQCJsCCIOSgEfCBP4gESCIZTFOIwRDoDIGaguSCIVIgCkFTwcAggRDpIYBQAx6BgAOCAQYIBLghWBTwQRFFgIABXIIFDBwgCDBYQAENAYCFLgIAEKwpKIIhA=")) diff --git a/apps/homeassistant/homeassistant.png b/apps/homeassistant/homeassistant.png new file mode 100644 index 0000000000000000000000000000000000000000..c73813025950aaccc31b7476b67ceb6326b5f915 GIT binary patch literal 1548 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 literal 0 HcmV?d00001 diff --git a/apps/homeassistant/screenshot_2.png b/apps/homeassistant/screenshot_2.png new file mode 100644 index 0000000000000000000000000000000000000000..2d25dd4e6ce4166d5a6b48ad7f50231bf643cc95 GIT binary patch literal 3334 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 literal 0 HcmV?d00001 diff --git a/apps/homeassistant/screenshot_3.png b/apps/homeassistant/screenshot_3.png new file mode 100644 index 0000000000000000000000000000000000000000..782e4a1952f1dc3205f20852edf88e9493edd6d8 GIT binary patch literal 3455 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 Xk+%_!CsMW>72tTx)$W-M?(+Wt^h|>m literal 0 HcmV?d00001 From 2044fa9df3b9d95c648d54f938bd5f9b069c0214 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 20 Jun 2022 13:36:49 +0200 Subject: [PATCH 02/57] Renaming --- apps/{homeassistant => ha}/ChangeLog | 0 apps/ha/README.md | 8 +++ apps/ha/ha.app.js | 59 ++++++++++++++++++ .../homeassistant.icon.js => ha/ha.icon.js} | 0 .../homeassistant.png => ha/ha.png} | Bin apps/{homeassistant => ha}/metadata.json | 8 +-- apps/{homeassistant => ha}/screenshot_1.png | Bin apps/{homeassistant => ha}/screenshot_2.png | Bin apps/{homeassistant => ha}/screenshot_3.png | Bin apps/homeassistant/README.md | 17 ----- apps/homeassistant/homeassistant.app.js | 34 ---------- 11 files changed, 71 insertions(+), 55 deletions(-) rename apps/{homeassistant => ha}/ChangeLog (100%) create mode 100644 apps/ha/README.md create mode 100644 apps/ha/ha.app.js rename apps/{homeassistant/homeassistant.icon.js => ha/ha.icon.js} (100%) rename apps/{homeassistant/homeassistant.png => ha/ha.png} (100%) rename apps/{homeassistant => ha}/metadata.json (64%) rename apps/{homeassistant => ha}/screenshot_1.png (100%) rename apps/{homeassistant => ha}/screenshot_2.png (100%) rename apps/{homeassistant => ha}/screenshot_3.png (100%) delete mode 100644 apps/homeassistant/README.md delete mode 100644 apps/homeassistant/homeassistant.app.js diff --git a/apps/homeassistant/ChangeLog b/apps/ha/ChangeLog similarity index 100% rename from apps/homeassistant/ChangeLog rename to apps/ha/ChangeLog diff --git a/apps/ha/README.md b/apps/ha/README.md new file mode 100644 index 000000000..520d562d8 --- /dev/null +++ b/apps/ha/README.md @@ -0,0 +1,8 @@ +# Home Assistant + + +## Creator +- [David Peer](https://github.com/peerdavid). + +## Thanks To +Info icons created by Freepik - Flaticon diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js new file mode 100644 index 000000000..f919d3797 --- /dev/null +++ b/apps/ha/ha.app.js @@ -0,0 +1,59 @@ +var W = g.getWidth(), H = g.getHeight(); +var position=0; +var response="..."; + +function draw() { + g.reset().clearRect(Bangle.appRect); + + // Header + g.setFont("Vector", 32).setFontAlign(0,0); + var text = ""; + if(position == 0){ + text = "Door"; + } else if(position == 1){ + text = "Light"; + } + + g.drawString(text, W/2, H/3); + g.setFont("Vector", 24); + g.drawString(response, W/2, H/3+34); +} + + +draw(); +setWatch(_=>load(), BTN1); + +Bangle.on('touch', function(btn, e){ + var left = parseInt(g.getWidth() * 0.3); + var right = g.getWidth() - left; + var isLeft = e.x < left; + var isRight = e.x > right; + + if(isRight){ + position += 1; + position = position > 1 ? 0 : position; + draw(); + } + + if(isLeft){ + position -= 1; + position = position < 0 ? 1 : position; + draw(); + } + + if(!isRight && !isLeft){ + Bangle.buzz(40, 0.6); + + // Trigger HA bridge + response = "sending..."; + draw(); + + var url = "https://www.google.com/"; + response = Bluetooth.println(JSON.stringify({t:"http", url:url})); + } + + draw(); +}); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/homeassistant/homeassistant.icon.js b/apps/ha/ha.icon.js similarity index 100% rename from apps/homeassistant/homeassistant.icon.js rename to apps/ha/ha.icon.js diff --git a/apps/homeassistant/homeassistant.png b/apps/ha/ha.png similarity index 100% rename from apps/homeassistant/homeassistant.png rename to apps/ha/ha.png diff --git a/apps/homeassistant/metadata.json b/apps/ha/metadata.json similarity index 64% rename from apps/homeassistant/metadata.json rename to apps/ha/metadata.json index 4b17722f9..d112fa297 100644 --- a/apps/homeassistant/metadata.json +++ b/apps/ha/metadata.json @@ -1,9 +1,9 @@ { - "id": "homeassistant", + "id": "ha", "name": "HomeAssistant", "version": "0.01", "description": "An application that displays information such as battery level, steps etc.", - "icon": "homeassistant.png", + "icon": "ha.png", "type": "app", "tags": "tool", "readme": "README.md", @@ -13,7 +13,7 @@ {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}], "storage": [ - {"name":"homeassistant.app.js","url":"homeassistant.app.js"}, - {"name":"homeassistant.img","url":"homeassistant.icon.js","evaluate":true} + {"name":"ha.app.js","url":"ha.app.js"}, + {"name":"ha.img","url":"ha.icon.js","evaluate":true} ] } diff --git a/apps/homeassistant/screenshot_1.png b/apps/ha/screenshot_1.png similarity index 100% rename from apps/homeassistant/screenshot_1.png rename to apps/ha/screenshot_1.png diff --git a/apps/homeassistant/screenshot_2.png b/apps/ha/screenshot_2.png similarity index 100% rename from apps/homeassistant/screenshot_2.png rename to apps/ha/screenshot_2.png diff --git a/apps/homeassistant/screenshot_3.png b/apps/ha/screenshot_3.png similarity index 100% rename from apps/homeassistant/screenshot_3.png rename to apps/ha/screenshot_3.png diff --git a/apps/homeassistant/README.md b/apps/homeassistant/README.md deleted file mode 100644 index 6466febe3..000000000 --- a/apps/homeassistant/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Info - -A very simple app that shows information on 3 different screens. -Go to the next screen via tab right, go to the previous screen -via tab left and reload the data via tab in the middle of the -screen. Very useful if combined with pattern launcher ;) - -![](screenshot_1.png) -![](screenshot_2.png) -![](screenshot_3.png) - - -## Creator -- [David Peer](https://github.com/peerdavid). - -## Thanks To -Info icons created by Freepik - Flaticon diff --git a/apps/homeassistant/homeassistant.app.js b/apps/homeassistant/homeassistant.app.js deleted file mode 100644 index e0a59547c..000000000 --- a/apps/homeassistant/homeassistant.app.js +++ /dev/null @@ -1,34 +0,0 @@ -var W = g.getWidth(), H = g.getHeight(); - - -function draw() { - g.reset().clearRect(Bangle.appRect); - - // Header - g.setFont("Vector", 22).setFontAlign(0,-1); - g.drawString("", W/2, H/2); -} - - -draw(); -setWatch(_=>load(), BTN1); - -Bangle.on('touch', function(btn, e){ - var left = parseInt(g.getWidth() * 0.3); - var right = g.getWidth() - left; - var isLeft = e.x < left; - var isRight = e.x > right; - - if(isRight){ - - } - - if(isLeft){ - - } - - draw(); -}); - -Bangle.loadWidgets(); -Bangle.drawWidgets(); \ No newline at end of file From ce90666725a9b4a29315cd7b05c4b2c2a45944b0 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 18:51:37 +0200 Subject: [PATCH 03/57] Minor changes --- apps/ha/ha.app.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index f919d3797..25f5e0580 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -1,7 +1,23 @@ +var _GB = global.GB; + + var W = g.getWidth(), H = g.getHeight(); var position=0; var response="..."; + +function GB(msg) { + if (msg.t == "http" || msg.t == "intent") { + response = JSON.stringify(msg); + draw(); + } + + if (_GB) { + _GB(msg); + } +} + + function draw() { g.reset().clearRect(Bangle.appRect); @@ -32,13 +48,11 @@ Bangle.on('touch', function(btn, e){ if(isRight){ position += 1; position = position > 1 ? 0 : position; - draw(); } if(isLeft){ position -= 1; position = position < 0 ? 1 : position; - draw(); } if(!isRight && !isLeft){ @@ -46,10 +60,7 @@ Bangle.on('touch', function(btn, e){ // Trigger HA bridge response = "sending..."; - draw(); - - var url = "https://www.google.com/"; - response = Bluetooth.println(JSON.stringify({t:"http", url:url})); + Bluetooth.println(JSON.stringify({t:"int­ent",action:"com.espruino.gadgetbridge.banglejs.TOGGLE_LIGHT",extra:{}})); } draw(); From 21cc7a07ccb9da9c32aa13dcbfacecf253a7d5c2 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:06:53 +0200 Subject: [PATCH 04/57] First working version :D --- apps/ha/README.md | 21 ++++++++++++--- apps/ha/actions.html | 31 +++++++++++++++++++++ apps/ha/ha.app.js | 57 +++++++++++++++++++-------------------- apps/ha/ha.icon.js | 2 +- apps/ha/ha.png | Bin 1548 -> 980 bytes apps/ha/metadata.json | 7 ++--- apps/ha/screenshot.png | Bin 0 -> 1873 bytes apps/ha/screenshot_1.png | Bin 3552 -> 0 bytes apps/ha/screenshot_2.png | Bin 3334 -> 0 bytes apps/ha/screenshot_3.png | Bin 3455 -> 0 bytes 10 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 apps/ha/actions.html create mode 100644 apps/ha/screenshot.png delete mode 100644 apps/ha/screenshot_1.png delete mode 100644 apps/ha/screenshot_2.png delete mode 100644 apps/ha/screenshot_3.png diff --git a/apps/ha/README.md b/apps/ha/README.md index 520d562d8..2a037cd68 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -1,8 +1,23 @@ # Home Assistant +This app integrates your BangleJs into the HomeAssistant. +# Setup +1.) First of all, make sure that HomeAssistant is working and +the HomeAssistant, as well as BangleJS Android App, is running on your device + +2.) Enable intent access in your BangleJS Android App. + +3.) Upload this app to your BangleJS and set the actions that you want to trigger from your +BangleJs within the app store. + +4.) Set all the actions on your HomeAssistant Android app with preceding "com.espruino.gadgetbridge.banglejs.ha." + +5.) The HomeAssistant Android app must be restarted in order to listen for those actions + -- a "Force Stop" is necessary! + +6.) Set the corresponding actions in HomeAssistant Web UI + +Thats it! ## Creator - [David Peer](https://github.com/peerdavid). - -## Thanks To -Info icons created by Freepik - Flaticon diff --git a/apps/ha/actions.html b/apps/ha/actions.html new file mode 100644 index 000000000..cb0ed9db1 --- /dev/null +++ b/apps/ha/actions.html @@ -0,0 +1,31 @@ + + + + + + +

Actions:

+

Click

+ + + + + + diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index 25f5e0580..029165dea 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -1,38 +1,31 @@ -var _GB = global.GB; - - +var storage = require("Storage"); var W = g.getWidth(), H = g.getHeight(); var position=0; -var response="..."; -function GB(msg) { - if (msg.t == "http" || msg.t == "intent") { - response = JSON.stringify(msg); - draw(); - } +// Try to read custom actions, otherwise use default +var actions = [ + "No Actions", +]; - if (_GB) { - _GB(msg); - } +try{ + actions = storage.read("ha.actions.txt").split(","); +} catch(e) { + // In case there are no user actions yet, we show the default... } function draw() { g.reset().clearRect(Bangle.appRect); - // Header - g.setFont("Vector", 32).setFontAlign(0,0); - var text = ""; - if(position == 0){ - text = "Door"; - } else if(position == 1){ - text = "Light"; - } + var h = 26; + g.setFont("Vector", h).setFontAlign(0,0); + var action = actions[position]; + var w = g.stringWidth(action); - g.drawString(text, W/2, H/3); - g.setFont("Vector", 24); - g.drawString(response, W/2, H/3+34); + + g.fillRect(W/2-w/2-8, H/2-h/2-8, W/2+w/2+2, H/2+h/2+2); + g.setColor(g.theme.bg).drawString(action, W/2, H/2); } @@ -46,21 +39,25 @@ Bangle.on('touch', function(btn, e){ var isRight = e.x > right; if(isRight){ + Bangle.buzz(40, 0.6); position += 1; - position = position > 1 ? 0 : position; + position = position >= actions.length ? 0 : position; } if(isLeft){ + Bangle.buzz(40, 0.6); position -= 1; - position = position < 0 ? 1 : position; + position = position < 0 ? actions.length-1 : position; } if(!isRight && !isLeft){ - Bangle.buzz(40, 0.6); - - // Trigger HA bridge - response = "sending..."; - Bluetooth.println(JSON.stringify({t:"int­ent",action:"com.espruino.gadgetbridge.banglejs.TOGGLE_LIGHT",extra:{}})); + Bangle.buzz(80, 0.6).then(()=>{ + action = "com.espruino.gadgetbridge.banglejs.ha." + actions[position]; + Bluetooth.println(JSON.stringify({t:"intent", action:action, extra:{}})); + setTimeout(()=>{ + Bangle.buzz(80, 0.6); + }, 250); + }); } draw(); diff --git a/apps/ha/ha.icon.js b/apps/ha/ha.icon.js index 8dbab8357..0b71898f3 100644 --- a/apps/ha/ha.icon.js +++ b/apps/ha/ha.icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwcBkmSpICDBwcJBYwCDpAhFggRJGg8SCI+ABgU//gSDCI4JBj//AAX4JRAIBg4QDAAPgBIJWGgIQFAAI+BLglAgEPCI/wEgJoEgYQHAAPANwhWFAApcBCIWQgAQJAAMAgSMDCJiSCwB6GQA6eCn5TFL4q5BUgIRF/wuBv4RGkCeGO4IREUgMBCJCVGCISwIWw0BYRLIICLBHHCJRrGCIQIFR44I5LIoRaPpARcdIwRJfYMBCJuACKUkgE/a5f8gEJCJD7FCIeAg78FAAvggFJCIMACJZOBCIOQCJsCCIOSgEfCBP4gESCIZTFOIwRDoDIGaguSCIVIgCkFTwcAggRDpIYBQAx6BgAOCAQYIBLghWBTwQRFFgIABXIIFDBwgCDBYQAENAYCFLgIAEKwpKIIhA=")) +require("heatshrink").decompress(atob("mEwwMB/4Ae/1/Aof4j4FD+EPAofgAonAgYFDwA/EgOBFAcH8FDAoP8h/wDAX4h1wAoXwhkwAoXgBYnAC4mAEYIwCgED4EAFwIFE/gFDn/4h/D4fwj5dBAokc8fHnEP8EYsfGjEH/4FDF4MfCIP4AoMP+fP+AFBg/77/gIIV/HwIFCn4+BAoUf/AFDL4IFDL4IFDLIYFkAEQ=")) \ No newline at end of file diff --git a/apps/ha/ha.png b/apps/ha/ha.png index c73813025950aaccc31b7476b67ceb6326b5f915..8fce958e47d8f0a5ba2fda55f346b052ffe3ca8c 100644 GIT binary patch delta 943 zcmV;g15o^o4AcjZGk*h%NklxlBv|z+t{{eBO8xc2((3QpC3l~MvgMq`NFd+=C%{}d}j+<$A}7{@F4Gvo!dw$-8< z7{@%8&8!@({F^N+)8lQLKbj;b2Xi3JexY_tjR&de|45w~kQzknuoO*>#FDC{P zPP;d`zJ-_YvW;PJ4IkqzoW(M3xBja)@u(D1Ux#iMw_!i_#hM$Nw67=1!sarLN%ug8 z7LLYP@g!cy-GBHTKZksQJBDd|S=h93BIY!4IHVc66EP>h<}c}_7IV5wI5aHddsUks zq)>q8@H>9Pv!R=fImLBrQn(D=fqvEIlbF-QM>+k6p&O4m{gS-01G{P%KPe^a^Oz`^ zlO=;TWsJ z(Z-twaM|6;CDp-~n9lJ`OQo?6$EGj4s$o+l2@i#?E>GXyX{@g2UA z9z+l0p&ndisKV2f-W7YL)A+jzaj&qsh8L}eM*{~!_lN2yP?aYiPN!4|r+#5GFZEB2 z*nB#^?|+W5sty!+W=eSSaviVg6HX_kCaN33Pu5G@llV5|iO}7P3l$uw!&8)HDYUzW z>nzSmHTV)PO3hc+yPT6QurYj)BYi(~6EUZs19f=XVZ+5(zaUk!yE5XuCs*-|bVM2H zLA)n*hAkwjT#6;H=lBczRAyE(9iUkaNwLJtq% zh}6r><4Wk?j?e4(9*^{K;C#$g!gD0{%51tK{qnbjV)C7pPNfX9ct?uiI}1D)@UHZ* zDZ|0oqpTRzM$v&A(g_@u;_yBx>GFS&9l#kk=fIg5%diU%;{M<|7Tg1EtIKZCCF$j~ zh<_h3S6DY?;{~|KdPA3CPO3v8{1HHnjuJPOEKu4 z-hqDa*sL3DNL8T<8nI?AryCSc*GauFCMcD_v6>sNO1=E*fO$q3VTAu0{sE4eC~3Kb R0O0@t002ovPDHLkV1j|R)CB+l delta 1515 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 KmmAlWa_etnmSL*^ literal 0 HcmV?d00001 diff --git a/apps/ha/screenshot_1.png b/apps/ha/screenshot_1.png deleted file mode 100644 index 97d42a89636e01437a6397075db1dc453ca22fe8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3552 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 diff --git a/apps/ha/screenshot_2.png b/apps/ha/screenshot_2.png deleted file mode 100644 index 2d25dd4e6ce4166d5a6b48ad7f50231bf643cc95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3334 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 diff --git a/apps/ha/screenshot_3.png b/apps/ha/screenshot_3.png deleted file mode 100644 index 782e4a1952f1dc3205f20852edf88e9493edd6d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3455 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 Xk+%_!CsMW>72tTx)$W-M?(+Wt^h|>m From 4966143cefbe6353165f9aa5d24869e2b4b8e5a2 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:11:07 +0200 Subject: [PATCH 05/57] Added custom html page --- apps/ha/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index 065bb0fa7..1931b72a0 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -8,6 +8,7 @@ "tags": "tool", "readme": "README.md", "supports": ["BANGLEJS2"], + "custom": "actions.html", "screenshots": [ {"url":"screenshot.png"}], "data": [ From 23da906d511585614b7a74623746eb1830159760 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:23:20 +0200 Subject: [PATCH 06/57] Use extra of intent rather than intents -- much easier to configure. --- apps/ha/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/ha/README.md b/apps/ha/README.md index 2a037cd68..41c90c616 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -1,21 +1,21 @@ # Home Assistant This app integrates your BangleJs into the HomeAssistant. -# Setup +# First Setup 1.) First of all, make sure that HomeAssistant is working and the HomeAssistant, as well as BangleJS Android App, is running on your device 2.) Enable intent access in your BangleJS Android App. -3.) Upload this app to your BangleJS and set the actions that you want to trigger from your -BangleJs within the app store. +3.) Set the "com.espruino.gadgetbridge.banglejs.HA" intent in your HomeAssistant android app -4.) Set all the actions on your HomeAssistant Android app with preceding "com.espruino.gadgetbridge.banglejs.ha." - -5.) The HomeAssistant Android app must be restarted in order to listen for those actions +4.) The HomeAssistant Android app must be restarted in order to listen for those actions -- a "Force Stop" is necessary! -6.) Set the corresponding actions in HomeAssistant Web UI +# Setup Trigger + +1.) Upload the app and all corresponding trigger +1.) Set the corresponding actions in HomeAssistant Web UI using the trigger data and intent. Thats it! From 23e892559553633fb9b69e2c55e28eb54b67b438 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:23:30 +0200 Subject: [PATCH 07/57] Minor changes --- apps/ha/ha.app.js | 9 +++++++-- apps/ha/metadata.json | 4 ++-- apps/ha/{actions.html => trigger.html} | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) rename apps/ha/{actions.html => trigger.html} (81%) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index 029165dea..d60ede1bb 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -52,8 +52,13 @@ Bangle.on('touch', function(btn, e){ if(!isRight && !isLeft){ Bangle.buzz(80, 0.6).then(()=>{ - action = "com.espruino.gadgetbridge.banglejs.ha." + actions[position]; - Bluetooth.println(JSON.stringify({t:"intent", action:action, extra:{}})); + Bluetooth.println(JSON.stringify({ + t:"intent", + action:"com.espruino.gadgetbridge.banglejs.HA", + extra:{ + trigger: actions[position] + }}) + ); setTimeout(()=>{ Bangle.buzz(80, 0.6); }, 250); diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index 1931b72a0..0b7424b92 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -8,11 +8,11 @@ "tags": "tool", "readme": "README.md", "supports": ["BANGLEJS2"], - "custom": "actions.html", + "custom": "trigger.html", "screenshots": [ {"url":"screenshot.png"}], "data": [ - {"name":"ha.actions.txt" } + {"name":"ha.trigger.txt" } ], "storage": [ {"name":"ha.app.js","url":"ha.app.js"}, diff --git a/apps/ha/actions.html b/apps/ha/trigger.html similarity index 81% rename from apps/ha/actions.html rename to apps/ha/trigger.html index cb0ed9db1..77008a5fa 100644 --- a/apps/ha/actions.html +++ b/apps/ha/trigger.html @@ -4,7 +4,7 @@ -

Actions:

+

Actions:

Click

@@ -20,10 +20,10 @@ // send finished app (in addition to contents of app.json) sendCustomizedApp({ storage:[ - {name:"ha.actions.txt", url:"ha.actions.txt", content:app}, + {name:"ha.trigger.txt", url:"ha.trigger.txt", content:app}, ] }); - console.log("Sent actions.txt!"); + console.log("Sent ha.trigger.txt!"); }); From 0c0fb6089c653ee9902665756654c2ce21cc6db5 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:24:32 +0200 Subject: [PATCH 08/57] Fixed Icon Color --- apps/ha/ha.icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ha/ha.icon.js b/apps/ha/ha.icon.js index 0b71898f3..9bf6af796 100644 --- a/apps/ha/ha.icon.js +++ b/apps/ha/ha.icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwMB/4Ae/1/Aof4j4FD+EPAofgAonAgYFDwA/EgOBFAcH8FDAoP8h/wDAX4h1wAoXwhkwAoXgBYnAC4mAEYIwCgED4EAFwIFE/gFDn/4h/D4fwj5dBAokc8fHnEP8EYsfGjEH/4FDF4MfCIP4AoMP+fP+AFBg/77/gIIV/HwIFCn4+BAoUf/AFDL4IFDL4IFDLIYFkAEQ=")) \ No newline at end of file +require("heatshrink").decompress(atob("mEwwIjggOAAocH8AFDh/wAocfAok//gFDv/+Aof+vwoD/Ef3gFBgfwh4YCg/xx4FCh/z54FCj4LEn4XEv4jBGAX//k//4uBAokDAofAg/wnk8h/gLoIFE8ccnHH+Ef8+cnPn/EAAoYvB8ARBg4FB+EMmEPAoP4gkgj5BCwA+BAoXAHwIFC8EHAoZfBAoZfBAoZZDAsgAiA==")) \ No newline at end of file From ee2d45ebd64056ade0a087f9d5b79727adb1c852 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:26:25 +0200 Subject: [PATCH 09/57] Better description --- apps/ha/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index 0b7424b92..eea1b6905 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -2,7 +2,7 @@ "id": "ha", "name": "HomeAssistant", "version": "0.01", - "description": "An application that displays information such as battery level, steps etc.", + "description": "Integrates your BangleJS into HomeAssistant.", "icon": "ha.png", "type": "app", "tags": "tool", From 9c6178df7d0a9633d1ce0b3ca936845619e4f520 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:32:39 +0200 Subject: [PATCH 10/57] Minor fixes --- apps/ha/ha.app.js | 4 ++-- apps/ha/trigger.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index d60ede1bb..bea3a142c 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -9,7 +9,7 @@ var actions = [ ]; try{ - actions = storage.read("ha.actions.txt").split(","); + actions = storage.read("ha.trigger.txt").split(","); } catch(e) { // In case there are no user actions yet, we show the default... } @@ -18,7 +18,7 @@ try{ function draw() { g.reset().clearRect(Bangle.appRect); - var h = 26; + var h = 22; g.setFont("Vector", h).setFontAlign(0,0); var action = actions[position]; var w = g.stringWidth(action); diff --git a/apps/ha/trigger.html b/apps/ha/trigger.html index 77008a5fa..54f57f683 100644 --- a/apps/ha/trigger.html +++ b/apps/ha/trigger.html @@ -4,8 +4,8 @@ -

Actions:

-

Click

+

Trigger - seperate list with ',':

+

From a3e8fb5b776f7a890e08095822cbf431c379fc6e Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 20:52:20 +0200 Subject: [PATCH 11/57] Finished readme --- apps/ha/README.md | 29 ++++++++++++++++++++--------- apps/ha/ha_automation.png | Bin 0 -> 72312 bytes 2 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 apps/ha/ha_automation.png diff --git a/apps/ha/README.md b/apps/ha/README.md index 41c90c616..685946a47 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -2,22 +2,33 @@ This app integrates your BangleJs into the HomeAssistant. # First Setup -1.) First of all, make sure that HomeAssistant is working and -the HomeAssistant, as well as BangleJS Android App, is running on your device +1.) First of all, make sure that HomeAssistant and the HomeAssistant Android App works. -2.) Enable intent access in your BangleJS Android App. +2.) Open your BangleJs Gadgetbridge App, click on the Settings icon of your BangleJs and enable "Allow Intent Access" -3.) Set the "com.espruino.gadgetbridge.banglejs.HA" intent in your HomeAssistant android app +3.) Enable sensor in HomeAssistant Andoird App/Configuration/Companion App/Manage Sensors/LastUpdate Trigger -4.) The HomeAssistant Android app must be restarted in order to listen for those actions - -- a "Force Stop" is necessary! +4.) At the bottom of the same screen click on "Add New Intent" and enter "com.espruino.gadgetbridge.banglejs.HA" + +5.) The HomeAssistant Android app must be restarted in order to listen for those actions + -- a "Force Stop" is necessary (through Android App settings) or restart your phone! + +This setup must be done only once -- now you are ready to configure your BangleJS to +control some devices or entities in your HomeAssistant :) # Setup Trigger +1.) Upload the app and all corresponding triggers through the AppStore UI. For example I entered "DOOR,LIGHT,OVEN". The list will be shown in your BangleJs in the corresponding order so enter more important triggers first. -1.) Upload the app and all corresponding trigger -1.) Set the corresponding actions in HomeAssistant Web UI using the trigger data and intent. +2.) Create an "automation" in the HomeAssistant WebUI for each trigger that you created on your BangleJs in order to tell HomeAssistant what you want to control. A sample configuration is shown in the image below -- I use this trigger to open the door: -Thats it! +![](ha_automation.png) + +3.) Don't forget to select the action that should be executed at the bottom of each automation. + +# Error Handling + +While playing and testing a bit I found that it is very important that you allow the android HomeAssistant app, as well as BangleJs Gadgetbridge app to (1) run in background and (2), disable energy optimizations for both apps. +Otherwise, Android could stop one of both apps and the trigger will never be sent to HomeAssistant... ## Creator - [David Peer](https://github.com/peerdavid). diff --git a/apps/ha/ha_automation.png b/apps/ha/ha_automation.png new file mode 100644 index 0000000000000000000000000000000000000000..9372cfa1525912a8ef0c5c759a72b695ea327aac GIT binary patch literal 72312 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 x3Co)99L*qz`u(1+rmUq@@zna`e*xTPmYo0q literal 0 HcmV?d00001 From a3f192c3d9336db5eb7b6442866fc003be5a4651 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 23 Jun 2022 21:03:32 +0200 Subject: [PATCH 12/57] Minor change --- apps/ha/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/ha/README.md b/apps/ha/README.md index 685946a47..c1f0bc3a6 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -1,6 +1,10 @@ # Home Assistant This app integrates your BangleJs into the HomeAssistant. +# How to use +Click on the left and right side of the screen to select the triggers that you +configured. Click in the middle of the screen to send the trigger to HomeAssistant. + # First Setup 1.) First of all, make sure that HomeAssistant and the HomeAssistant Android App works. From 5af5f5a7d0e8f215c22306feeb03767bd9409ff1 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 08:19:08 +0200 Subject: [PATCH 13/57] Undo other changes... --- apps/cassioWatch/app.js | 100 ++-------------------------------------- 1 file changed, 5 insertions(+), 95 deletions(-) diff --git a/apps/cassioWatch/app.js b/apps/cassioWatch/app.js index 3f5cfee40..6bbb9e823 100644 --- a/apps/cassioWatch/app.js +++ b/apps/cassioWatch/app.js @@ -4,11 +4,8 @@ require("Font6x12").add(Graphics); require("Font8x12").add(Graphics); require("Font7x11Numeric7Seg").add(Graphics); - -const TIMER_IDX = "cassioWatch"; - - function bigThenSmall(big, small, x, y) { + g.setFont("7x11Numeric7Seg", 2); g.drawString(big, x, y); x += g.stringWidth(big); g.setFont("8x12"); @@ -74,7 +71,6 @@ function drawClock() { } function drawBattery() { - g.setFont("7x11Numeric7Seg", 2); bigThenSmall(E.getBattery(), "%", 135, 21); } @@ -121,59 +117,6 @@ function getSteps() { return steps + "k"; } -function isAlarmEnabled(){ - try{ - var alarm = require('sched'); - var alarmObj = alarm.getAlarm(TIMER_IDX); - if(alarmObj===undefined || !alarmObj.on){ - return false; - } - - return true; - - } catch(ex){ } - return false; -} - -function getAlarmMinutes(){ - if(!isAlarmEnabled()){ - return -1; - } - - var alarm = require('sched'); - var alarmObj = alarm.getAlarm(TIMER_IDX); - return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000)); -} - -function increaseAlarm(){ - try{ - var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0; - var alarm = require('sched') - alarm.setAlarm(TIMER_IDX, { - timer : (minutes+5)*60*1000, - }); - alarm.reload(); - } catch(ex){ } -} - -function decreaseAlarm(){ - try{ - var minutes = getAlarmMinutes(); - minutes -= 5; - - var alarm = require('sched') - alarm.setAlarm(TIMER_IDX, undefined); - - if(minutes > 0){ - alarm.setAlarm(TIMER_IDX, { - timer : minutes*60*1000, - }); - } - - alarm.reload(); - } catch(ex){ } -} - function draw() { queueDraw(); @@ -185,17 +128,10 @@ function draw() { let background = getBackgroundImage(); g.drawImage(background, 0, 0, { scale: 1 }); g.setColor(0, 0, 0); - - if(!isAlarmEnabled()){ - g.setFont("6x12"); - g.drawString("Launching Process", 30, 20); - g.setFont("8x12"); - g.drawString("ACTIVATE", 40, 35); - } else { - g.setFont("8x12", 2); - // g.drawString("T-" + getAlarmMinutes()+ "min", 30, 23); - bigThenSmall("T-" + getAlarmMinutes(), " min.", 30, 23); - } + g.setFont("6x12"); + g.drawString("Launching Process", 30, 20); + g.setFont("8x12"); + g.drawString("ACTIVATE", 40, 35); g.setFontAlign(0,-1); g.setFont("8x12", 2); @@ -230,32 +166,6 @@ Bangle.on("lock", (locked) => { }); -Bangle.on('touch', function(btn, e){ - var left = parseInt(g.getWidth() * 0.2); - var right = g.getWidth() - left; - var upper = parseInt(g.getHeight() * 0.2); - var lower = g.getHeight() - upper; - - var is_left = e.x < left; - var is_right = e.x > right; - var is_upper = e.y < upper; - var is_lower = e.y > lower; - - if(is_upper){ - Bangle.buzz(40, 0.6); - increaseAlarm(); - draw(); - } - - if(is_lower){ - Bangle.buzz(40, 0.6); - decreaseAlarm(); - draw(); - } -}); - - - // Load widgets, but don't show them Bangle.loadWidgets(); Bangle.setUI("clock"); From 27eaa5beed65ce140f7c0406836a65538c6826a4 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 08:33:14 +0200 Subject: [PATCH 14/57] Improved UI --- apps/ha/ha.app.js | 37 ++++++++++++++++++++++++++++++------- apps/ha/screenshot.png | Bin 1873 -> 2574 bytes 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index bea3a142c..73915d731 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -3,6 +3,12 @@ var W = g.getWidth(), H = g.getHeight(); var position=0; +var icon = { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA==")) +}; + // Try to read custom actions, otherwise use default var actions = [ "No Actions", @@ -19,19 +25,22 @@ function draw() { g.reset().clearRect(Bangle.appRect); var h = 22; - g.setFont("Vector", h).setFontAlign(0,0); + g.setFont("Vector", h); var action = actions[position]; var w = g.stringWidth(action); + g.setFontAlign(-1,-1); + g.setColor(g.theme.fg).drawImage(icon, 12, H/5-2); + g.drawString("Home", icon.width + 20, H/5); + g.drawString("Assistant", icon.width + 18, H/5+24); - g.fillRect(W/2-w/2-8, H/2-h/2-8, W/2+w/2+2, H/2+h/2+2); - g.setColor(g.theme.bg).drawString(action, W/2, H/2); + g.setFontAlign(0,0); + var ypos = H/5*3+20; + g.fillRect(W/2-w/2-8, ypos-h/2-8, W/2+w/2+2, ypos+h/2+2); + g.setColor(g.theme.bg).drawString(action, W/2, ypos); } -draw(); -setWatch(_=>load(), BTN1); - Bangle.on('touch', function(btn, e){ var left = parseInt(g.getWidth() * 0.3); var right = g.getWidth() - left; @@ -68,5 +77,19 @@ Bangle.on('touch', function(btn, e){ draw(); }); +// Send a startup trigger such that we could also execute +// an action when the app is started :) +Bluetooth.println(JSON.stringify({ + t:"intent", + action:"com.espruino.gadgetbridge.banglejs.HA", + extra:{ + trigger: "APP_STARTED" + }}) +); + +// Next load the widgets and draw the app Bangle.loadWidgets(); -Bangle.drawWidgets(); \ No newline at end of file +Bangle.drawWidgets(); + +draw(); +setWatch(_=>load(), BTN1); diff --git a/apps/ha/screenshot.png b/apps/ha/screenshot.png index 4125df314fab20e5ba5eb6827940d8ddc38f3bf1..e92b7e97d156cec5e07b421735c3ebf0df8919ca 100644 GIT binary patch literal 2574 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 KmmAlWa_etnmSL*^ From b4ce80db862b0bb8f98af04fcd8cdbb2b16ba937 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 08:33:44 +0200 Subject: [PATCH 15/57] Added screenshot --- apps/ha/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/ha/README.md b/apps/ha/README.md index c1f0bc3a6..67f5a83ce 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -5,6 +5,8 @@ This app integrates your BangleJs into the HomeAssistant. Click on the left and right side of the screen to select the triggers that you configured. Click in the middle of the screen to send the trigger to HomeAssistant. +![](screenshot.png) + # First Setup 1.) First of all, make sure that HomeAssistant and the HomeAssistant Android App works. From dee0ca3aef69eda950e1b0b375ba6a238db69420 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 08:36:08 +0200 Subject: [PATCH 16/57] Added APP_STARTED to Readme --- apps/ha/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/ha/README.md b/apps/ha/README.md index 67f5a83ce..35a90ea88 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -31,8 +31,12 @@ control some devices or entities in your HomeAssistant :) 3.) Don't forget to select the action that should be executed at the bottom of each automation. -# Error Handling +*Note: There is also an automatic trigger send when the app is started (APP_STARTED) -- so you could +add an action also for that.* +# FAQ + +## Sometimes the trigger is not executed While playing and testing a bit I found that it is very important that you allow the android HomeAssistant app, as well as BangleJs Gadgetbridge app to (1) run in background and (2), disable energy optimizations for both apps. Otherwise, Android could stop one of both apps and the trigger will never be sent to HomeAssistant... From d5557ee508e0ef5611fc205543409e18e4951870 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 08:46:31 +0200 Subject: [PATCH 17/57] Minor design changes --- apps/ha/ha.app.js | 3 ++- apps/ha/screenshot.png | Bin 2574 -> 2677 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index 73915d731..65524036f 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -36,7 +36,8 @@ function draw() { g.setFontAlign(0,0); var ypos = H/5*3+20; - g.fillRect(W/2-w/2-8, ypos-h/2-8, W/2+w/2+2, ypos+h/2+2); + g.drawRect(W/2-w/2-8, ypos-h/2-8, W/2+w/2+5, ypos+h/2+5); + g.fillRect(W/2-w/2-6, ypos-h/2-6, W/2+w/2+3, ypos+h/2+3); g.setColor(g.theme.bg).drawString(action, W/2, ypos); } diff --git a/apps/ha/screenshot.png b/apps/ha/screenshot.png index e92b7e97d156cec5e07b421735c3ebf0df8919ca..ea5a41ed912c3f98ca7beb880c7ff8b00f6c2ab8 100644 GIT binary patch literal 2677 zcmc&$=~ohX7yf|@1uivVy}6F1qhV@kR+d{TnM)R_fJ;c0ORm_aCZkxHdrnTdMwYmP zf|-gNl4(v>I^&Y1rpTmaijoE@ZZGo}%%}IfAMSn5x#v9het7OZ&rLb&>YxZ$g#!Q- z9Z%VxlOpS%*di~@%!bbdDL}5CbFc-~J?hf{z>OX4Pq;@D1k{PX5q$;pYU`$5R2Nmm zcmr)}&!X}A3p2Lyzu~t$I&9q*w=P*vv(^`uz}J8?}O`i$e4@SKFwm;>noZ9Z^?**{#?Nb~mj06MtI+0AM^x5 zFpvKH(BKO~z;s!)N|WdPdS#{iArKn$b9##)(S<&oE4pB<`}urr5E#?TVft(ZZ6<=% z{i>9u*OLY~DEHrK;a6hTj}?l>$(nY7hgXT`qI7`*_xdz)kAa-fbKS~wu$&7uOLTDp z7LuJCdN%Sr+iUQrWOd?9;cpg-2LWOLX|kfv-PuxjR0l%RK9+daN}dIsH`^#fMIyNZ z$<6P*huFggoNBKaft+i1K3SG%+){S)jLmFDRfc2Y0{-_XqnQNp+w<9{0*RS2jO4Y~ zcGO)cWp0@BXDa=jfZ9lX^uR10Ni@ziU1fyzAqIo!nUdArKcc4eor_IbT|nF(TWu$Y zs%&NV%k;hyTP+SZoMz|7c_+Y z1ENfEJL-HjAI^gMGKc4|2@c9=ETYD{-~i29ktj!)M57;Q)ya-laJvU{uLy(J)5FyU zypyR3t`K};&+rCqtz78E^I3mXQ?X5?`Th@hsHH`-t-2CxSJUZ9GsqVUO$`jp{#(RzN!_c$8x!H1^=C4&>((+M&$z%D%_vme^)vGR}X1@Re#(dB~?|1 zdpGO-yAJbFgk84p{7Zhuad?ZqHBgsj1vcX*M9a@9Z1I#wR(L0aOz=0vM3RdWg`saW zqiG<#Q%Ehm4!y=>mTys2f};t90k3@Kh} za@)@Aaad$ZSbVqVI50Qav7@&0>{d!^+9N|$kwa^}@)w^d2*H!Kz&x`5&w=>I{=e=j zDQkq2ns0!|+sM0!C4Hi)+^~uFG6$Vla;&JHhtx}A@B`HQiIK8&N%m!JY-N8?S;J6{7Z`NP`ZkY@}Q{H`VFG0}nuXQ+k(+lmmFo)`DknK>9eaEw=~&1JngKECd)8 zs6yS4fQZ%&?M4BvzndK~6$%*TcTRiC0d{Ec78eYls61rtqXUq0S}|cC9I%RhI_$3k zc+V=d51=9c_(CZI3VaTm$(Bl;0%%mp^v1&8%d7JX*Ihs6;EaBF(_mbja zf_jkaG#e|cM1p)M^Gp@x$pZ0f1lOvyj{%83?F9(^hGZmQI>NajO^KOMo|&Vx+#tk& zmS6S(=JZZ0IAusjj%W6%-N6&kt?}jZr5iy{CL=n}eD(q#y8pB*9EU6`U>a|^8Lic> z+jo)}Y7{N#K>jaK-bJNeBIU>)7$@bYqj7R>-f_f8YE$_E-I?l)4>27!MCyM>TRyu_m%Nd3!F`cqQ+-kd2U` zq!r6jhJJ$lyLJ#^elch%^-6M!!vZxvFcXHmpv_uv3!(JbJuy&O1-@$va$0JtlvrglY8@JQdNdQrOa z;D~m$ueK%L`Y+z$;d}r9 literal 2574 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 u0j?xN1Z~~OA_L|vyjCOJSoWV;yawMObPcj Date: Fri, 24 Jun 2022 08:59:51 +0200 Subject: [PATCH 18/57] First test with display name and json file --- apps/ha/ha.app.js | 21 +++++++++++---------- apps/ha/trigger.html | 11 ++++++----- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index 65524036f..4b85fbf56 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -10,14 +10,15 @@ var icon = { }; // Try to read custom actions, otherwise use default -var actions = [ - "No Actions", +var triggers = [ + {display: "Not found.", trigger: "NOP", icon: null}, ]; try{ - actions = storage.read("ha.trigger.txt").split(","); + triggers = storage.read("ha.trigger.json"); + triggers = JSON.parse(triggers); } catch(e) { - // In case there are no user actions yet, we show the default... + // In case there are no user triggers yet, we show the default... } @@ -26,8 +27,8 @@ function draw() { var h = 22; g.setFont("Vector", h); - var action = actions[position]; - var w = g.stringWidth(action); + var trigger = triggers[position]; + var w = g.stringWidth(trigger.display); g.setFontAlign(-1,-1); g.setColor(g.theme.fg).drawImage(icon, 12, H/5-2); @@ -38,7 +39,7 @@ function draw() { var ypos = H/5*3+20; g.drawRect(W/2-w/2-8, ypos-h/2-8, W/2+w/2+5, ypos+h/2+5); g.fillRect(W/2-w/2-6, ypos-h/2-6, W/2+w/2+3, ypos+h/2+3); - g.setColor(g.theme.bg).drawString(action, W/2, ypos); + g.setColor(g.theme.bg).drawString(trigger.display, W/2, ypos); } @@ -51,13 +52,13 @@ Bangle.on('touch', function(btn, e){ if(isRight){ Bangle.buzz(40, 0.6); position += 1; - position = position >= actions.length ? 0 : position; + position = position >= triggers.length ? 0 : position; } if(isLeft){ Bangle.buzz(40, 0.6); position -= 1; - position = position < 0 ? actions.length-1 : position; + position = position < 0 ? triggers.length-1 : position; } if(!isRight && !isLeft){ @@ -66,7 +67,7 @@ Bangle.on('touch', function(btn, e){ t:"intent", action:"com.espruino.gadgetbridge.banglejs.HA", extra:{ - trigger: actions[position] + trigger: triggers[position].trigger }}) ); setTimeout(()=>{ diff --git a/apps/ha/trigger.html b/apps/ha/trigger.html index 54f57f683..bcb3c72b7 100644 --- a/apps/ha/trigger.html +++ b/apps/ha/trigger.html @@ -3,8 +3,9 @@ - -

Trigger - seperate list with ',':

+ triggers +

Json file [{display: "Text", trigger: "TRIGGER_1", icon: null}, ...]

+

@@ -13,17 +14,17 @@ // When the 'upload' button is clicked... document.getElementById("upload").addEventListener("click", function() { // get the text to add - var text = document.getElementById("subjects").value; + var text = document.getElementById("triggers").value; console.log(text); // build the app's text using a templated String var app = text; // send finished app (in addition to contents of app.json) sendCustomizedApp({ storage:[ - {name:"ha.trigger.txt", url:"ha.trigger.txt", content:app}, + {name:"ha.trigger.json", url:"ha.trigger.json", content:app}, ] }); - console.log("Sent ha.trigger.txt!"); + console.log("Sent ha.trigger.json!"); }); From bd1a6459b213867d870e2d76cffea494c748f8e5 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 09:29:49 +0200 Subject: [PATCH 19/57] Support display name and icons. --- apps/ha/README.md | 12 +++++++++++- apps/ha/ha.app.js | 35 ++++++++++++++++++++++++++++++----- apps/ha/metadata.json | 4 +++- apps/ha/screenshot.png | Bin 2677 -> 2402 bytes apps/ha/screenshot_2.png | Bin 0 -> 2695 bytes apps/ha/screenshot_3.png | Bin 0 -> 2679 bytes apps/ha/trigger.html | 12 +++++++++--- 7 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 apps/ha/screenshot_2.png create mode 100644 apps/ha/screenshot_3.png diff --git a/apps/ha/README.md b/apps/ha/README.md index 35a90ea88..c51da967a 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -23,7 +23,14 @@ This setup must be done only once -- now you are ready to configure your BangleJ control some devices or entities in your HomeAssistant :) # Setup Trigger -1.) Upload the app and all corresponding triggers through the AppStore UI. For example I entered "DOOR,LIGHT,OVEN". The list will be shown in your BangleJs in the corresponding order so enter more important triggers first. +1.) Upload the app and all corresponding triggers through the AppStore UI. You must specify +the display name, the trigger as well as an icon. +The following icons are currently supported: +- ha (default) +- light +- door +- fire + 2.) Create an "automation" in the HomeAssistant WebUI for each trigger that you created on your BangleJs in order to tell HomeAssistant what you want to control. A sample configuration is shown in the image below -- I use this trigger to open the door: @@ -40,5 +47,8 @@ add an action also for that.* While playing and testing a bit I found that it is very important that you allow the android HomeAssistant app, as well as BangleJs Gadgetbridge app to (1) run in background and (2), disable energy optimizations for both apps. Otherwise, Android could stop one of both apps and the trigger will never be sent to HomeAssistant... +## Thanks to +
Icons created by Flaticon + ## Creator - [David Peer](https://github.com/peerdavid). diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index 4b85fbf56..ee30a66e9 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -3,15 +3,39 @@ var W = g.getWidth(), H = g.getHeight(); var position=0; -var icon = { - width : 48, height : 48, bpp : 1, - transparent : 0, - buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA==")) +// Note: All icons should have 48x48 pixels +function getIcon(icon){ + if(icon == "light"){ + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AAMBwAFE4AFDgYFJjgFBnAFBjwXBvAFBh4jBuAFCAQPwAQMHAQPgEQQCBEgcf/AvDn/8Aof//5GDAoJOBh+BAoOB+EP8YFB4fwgfnAoPnGANHAoPjHYQFBHYQFd44pDg47C4/gh/DIIZNFLIplGgF//wFIgZ9BRIUHRII7Ch4FBUIUOAoKzCjwFEhgCBmDpIVooFFh4oCAA4LFC5b7BAob1BAYI=")) + }; + } else if(icon == "door"){ + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AAM4Aok/4AED///Aov4Aon8DgQGBAv4FpnIFKJv4FweAQFFAgQFB8AFDnADC")) + }; + } else if (icon == "fire"){ + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("ABsDAokBwAFE4AFE8AFE+AFE/AFJgf8Aon+AocHAokP/8QAokYAoUfAok//88ApF//4kDAo//AgMQAgIFCjgFEjwFCOYIFFHQIFDn/+AoJ/BAoIqBAoN//xCBAoI5BDIPAgP//gFB8AFChYFBgf//EJAogOBAoSgBAoMHAQIFEFgXAAoJEBv4FCNoQFGVYd/wAFEYYIFIvwCBDoV8UwQCBcgUPwDwDfQMBaIYADA")) + }; + } + + // Default is always the HA icon + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA==")) + }; }; // Try to read custom actions, otherwise use default var triggers = [ - {display: "Not found.", trigger: "NOP", icon: null}, + {display: "Not found.", trigger: "NOP", icon: "ha"}, ]; try{ @@ -31,6 +55,7 @@ function draw() { var w = g.stringWidth(trigger.display); g.setFontAlign(-1,-1); + var icon = getIcon(trigger.icon); g.setColor(g.theme.fg).drawImage(icon, 12, H/5-2); g.drawString("Home", icon.width + 20, H/5); g.drawString("Assistant", icon.width + 18, H/5+24); diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index eea1b6905..c7ba2f46b 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -11,8 +11,10 @@ "custom": "trigger.html", "screenshots": [ {"url":"screenshot.png"}], + {"url":"screenshot_2.png"}], + {"url":"screenshot_3.png"}], "data": [ - {"name":"ha.trigger.txt" } + {"name":"ha.trigger.json" } ], "storage": [ {"name":"ha.app.js","url":"ha.app.js"}, diff --git a/apps/ha/screenshot.png b/apps/ha/screenshot.png index ea5a41ed912c3f98ca7beb880c7ff8b00f6c2ab8..dc059e2de43b614bdab4a70e86d6cf8edf4203ac 100644 GIT binary patch literal 2402 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 diff --git a/apps/ha/screenshot_2.png b/apps/ha/screenshot_2.png new file mode 100644 index 0000000000000000000000000000000000000000..55019c3b1d54754ce027f6a390d8085881bde42c GIT binary patch literal 2695 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 b)l6)+-*~{493hDFSpsIJ)+Q7q&-i}<6_ws= literal 0 HcmV?d00001 diff --git a/apps/ha/screenshot_3.png b/apps/ha/screenshot_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b9eae0b74de95ce232a67b1e6e898928ce6b7a10 GIT binary patch literal 2679 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 WeFV>U7j26_Nnmg5Xv46^J@^-jYWLj$ literal 0 HcmV?d00001 diff --git a/apps/ha/trigger.html b/apps/ha/trigger.html index bcb3c72b7..60fedda7a 100644 --- a/apps/ha/trigger.html +++ b/apps/ha/trigger.html @@ -3,9 +3,15 @@ - triggers -

Json file [{display: "Text", trigger: "TRIGGER_1", icon: null}, ...]

-

+

Upload Tiggers

+

You must upload a list of json objects -- an example is given below

+

From 96c247944b768f9308ff98924a18258b2d74a7ea Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 09:33:02 +0200 Subject: [PATCH 20/57] Fixed metadata --- apps/ha/metadata.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index c7ba2f46b..9b4ca54af 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -10,9 +10,10 @@ "supports": ["BANGLEJS2"], "custom": "trigger.html", "screenshots": [ - {"url":"screenshot.png"}], - {"url":"screenshot_2.png"}], - {"url":"screenshot_3.png"}], + {"url":"screenshot.png"}, + {"url":"screenshot_2.png"}, + {"url":"screenshot_3.png"} + ], "data": [ {"name":"ha.trigger.json" } ], From 2f29c9ada2c7f48a0ff5dfa81a17e5ebca091157 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 09:37:49 +0200 Subject: [PATCH 21/57] Minor changes --- apps/ha/trigger.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/ha/trigger.html b/apps/ha/trigger.html index 60fedda7a..3c4673c3c 100644 --- a/apps/ha/trigger.html +++ b/apps/ha/trigger.html @@ -6,11 +6,11 @@

Upload Tiggers

You must upload a list of json objects -- an example is given below

From b974887c4b91379ddcb6349915d701ad2cdf7dfd Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 09:39:56 +0200 Subject: [PATCH 22/57] Remove Unnecessary semicolon no-extra-semi --- apps/ha/ha.app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index ee30a66e9..a6d45f056 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -10,19 +10,19 @@ function getIcon(icon){ width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("AAMBwAFE4AFDgYFJjgFBnAFBjwXBvAFBh4jBuAFCAQPwAQMHAQPgEQQCBEgcf/AvDn/8Aof//5GDAoJOBh+BAoOB+EP8YFB4fwgfnAoPnGANHAoPjHYQFBHYQFd44pDg47C4/gh/DIIZNFLIplGgF//wFIgZ9BRIUHRII7Ch4FBUIUOAoKzCjwFEhgCBmDpIVooFFh4oCAA4LFC5b7BAob1BAYI=")) - }; + } } else if(icon == "door"){ return { width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("AAM4Aok/4AED///Aov4Aon8DgQGBAv4FpnIFKJv4FweAQFFAgQFB8AFDnADC")) - }; + } } else if (icon == "fire"){ return { width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("ABsDAokBwAFE4AFE8AFE+AFE/AFJgf8Aon+AocHAokP/8QAokYAoUfAok//88ApF//4kDAo//AgMQAgIFCjgFEjwFCOYIFFHQIFDn/+AoJ/BAoIqBAoN//xCBAoI5BDIPAgP//gFB8AFChYFBgf//EJAogOBAoSgBAoMHAQIFEFgXAAoJEBv4FCNoQFGVYd/wAFEYYIFIvwCBDoV8UwQCBcgUPwDwDfQMBaIYADA")) - }; + } } // Default is always the HA icon @@ -30,7 +30,7 @@ function getIcon(icon){ width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA==")) - }; + } }; // Try to read custom actions, otherwise use default From f7247753c024ba8cee19f9b75fae2ba3fc782f51 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 09:40:20 +0200 Subject: [PATCH 23/57] Minor fix; --- apps/ha/ha.app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index a6d45f056..9e12f491a 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -10,19 +10,19 @@ function getIcon(icon){ width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("AAMBwAFE4AFDgYFJjgFBnAFBjwXBvAFBh4jBuAFCAQPwAQMHAQPgEQQCBEgcf/AvDn/8Aof//5GDAoJOBh+BAoOB+EP8YFB4fwgfnAoPnGANHAoPjHYQFBHYQFd44pDg47C4/gh/DIIZNFLIplGgF//wFIgZ9BRIUHRII7Ch4FBUIUOAoKzCjwFEhgCBmDpIVooFFh4oCAA4LFC5b7BAob1BAYI=")) - } + }; } else if(icon == "door"){ return { width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("AAM4Aok/4AED///Aov4Aon8DgQGBAv4FpnIFKJv4FweAQFFAgQFB8AFDnADC")) - } + }; } else if (icon == "fire"){ return { width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("ABsDAokBwAFE4AFE8AFE+AFE/AFJgf8Aon+AocHAokP/8QAokYAoUfAok//88ApF//4kDAo//AgMQAgIFCjgFEjwFCOYIFFHQIFDn/+AoJ/BAoIqBAoN//xCBAoI5BDIPAgP//gFB8AFChYFBgf//EJAogOBAoSgBAoMHAQIFEFgXAAoJEBv4FCNoQFGVYd/wAFEYYIFIvwCBDoV8UwQCBcgUPwDwDfQMBaIYADA")) - } + }; } // Default is always the HA icon @@ -30,8 +30,8 @@ function getIcon(icon){ width : 48, height : 48, bpp : 1, transparent : 0, buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA==")) - } -}; + }; +} // Try to read custom actions, otherwise use default var triggers = [ From 649ecf495206c747c2da9f256173e75bd2835ee8 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 11:29:25 +0200 Subject: [PATCH 24/57] Add trick how to start HomeAssistant automatically. --- apps/ha/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/ha/README.md b/apps/ha/README.md index c51da967a..46c3b8afe 100644 --- a/apps/ha/README.md +++ b/apps/ha/README.md @@ -47,6 +47,12 @@ add an action also for that.* While playing and testing a bit I found that it is very important that you allow the android HomeAssistant app, as well as BangleJs Gadgetbridge app to (1) run in background and (2), disable energy optimizations for both apps. Otherwise, Android could stop one of both apps and the trigger will never be sent to HomeAssistant... +If you still have problems, you can try another trick: +Install "MacroDroid" from the Android AppStore and start the HomeAssistant App +each time the "com.espruino.gadgetbridge.banglejs.HA" intent is send together +with the extra trigger: APP_STARTED. Then whenever you open the app on your BangleJs +it is ensured that HomeAssistant is running... + ## Thanks to Icons created by Flaticon From c0f3d9b8a9760ddbe43623195f115114b699c2cb Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 12:45:11 +0200 Subject: [PATCH 25/57] Retry logic for sending intents --- apps/ha/ha.app.js | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js index 9e12f491a..17290ab26 100644 --- a/apps/ha/ha.app.js +++ b/apps/ha/ha.app.js @@ -46,6 +46,29 @@ try{ } +function sendIntent(trigger){ + var retries=3; + + while(retries > 0){ + try{ + // Send a startup trigger such that we could also execute + // an action when the app is started :) + Bluetooth.println(JSON.stringify({ + t:"intent", + action:"com.espruino.gadgetbridge.banglejs.HA", + extra:{ + trigger: trigger + }}) + ); + retries = -1; + + } catch(e){ + retries--; + } + } +} + + function draw() { g.reset().clearRect(Bangle.appRect); @@ -88,13 +111,7 @@ Bangle.on('touch', function(btn, e){ if(!isRight && !isLeft){ Bangle.buzz(80, 0.6).then(()=>{ - Bluetooth.println(JSON.stringify({ - t:"intent", - action:"com.espruino.gadgetbridge.banglejs.HA", - extra:{ - trigger: triggers[position].trigger - }}) - ); + sendIntent(triggers[position].trigger); setTimeout(()=>{ Bangle.buzz(80, 0.6); }, 250); @@ -104,15 +121,8 @@ Bangle.on('touch', function(btn, e){ draw(); }); -// Send a startup trigger such that we could also execute -// an action when the app is started :) -Bluetooth.println(JSON.stringify({ - t:"intent", - action:"com.espruino.gadgetbridge.banglejs.HA", - extra:{ - trigger: "APP_STARTED" - }}) -); +// Send intent that the we started the app. +sendIntent("APP_STARTED"); // Next load the widgets and draw the app Bangle.loadWidgets(); From 6efb06a8333f13a057f43e1c758019a0dfbf89de Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 24 Jun 2022 12:47:56 +0200 Subject: [PATCH 26/57] Set width of text area --- apps/ha/trigger.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ha/trigger.html b/apps/ha/trigger.html index 3c4673c3c..b57f131b2 100644 --- a/apps/ha/trigger.html +++ b/apps/ha/trigger.html @@ -5,7 +5,7 @@

Upload Tiggers

You must upload a list of json objects -- an example is given below

-

+

+ @@ -13,25 +19,16 @@ + + + + From 9ec50b4d8fcc7505cd1dc668419794789c328e52 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 11:49:45 +0200 Subject: [PATCH 39/57] Remove custom -- interafce.html --- apps/ha/metadata.json | 2 +- apps/ha/trigger.html | 50 ------------------------------------------- 2 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 apps/ha/trigger.html diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index 9b4ca54af..c1e6a0392 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -8,7 +8,7 @@ "tags": "tool", "readme": "README.md", "supports": ["BANGLEJS2"], - "custom": "trigger.html", + "interface": "interface.html", "screenshots": [ {"url":"screenshot.png"}, {"url":"screenshot_2.png"}, diff --git a/apps/ha/trigger.html b/apps/ha/trigger.html deleted file mode 100644 index 8ee4419e4..000000000 --- a/apps/ha/trigger.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - -

Upload Tiggers

-

You must upload a list of json objects -- an example is given below

-

-

- - - - - - - From cb2d2657d6aa0d8f1e019af3129f5c1db79c4a6b Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 11:52:13 +0200 Subject: [PATCH 40/57] onInit needed --- apps/ha/interface.html | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/ha/interface.html b/apps/ha/interface.html index eca0f3a14..4c69692fb 100644 --- a/apps/ha/interface.html +++ b/apps/ha/interface.html @@ -17,10 +17,12 @@ From 189b85301b90f211a0b7c6f61c6504bc13cf3056 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 12:14:06 +0200 Subject: [PATCH 41/57] Write and load data --- apps/ha/interface.html | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/apps/ha/interface.html b/apps/ha/interface.html index 4c69692fb..7ba08e4c7 100644 --- a/apps/ha/interface.html +++ b/apps/ha/interface.html @@ -14,26 +14,24 @@

- + + + + + + + diff --git a/apps/ha/interface.html b/apps/ha/interface.html deleted file mode 100644 index 76457085b..000000000 --- a/apps/ha/interface.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - -

Upload Tiggers

-

You must upload a list of json objects -- an example is given below

-

-

- - - - - - - diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index c1e6a0392..9b4ca54af 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -8,7 +8,7 @@ "tags": "tool", "readme": "README.md", "supports": ["BANGLEJS2"], - "interface": "interface.html", + "custom": "trigger.html", "screenshots": [ {"url":"screenshot.png"}, {"url":"screenshot_2.png"}, From 5461a7c6f5964b7956231f2f9f104fc7525a6ea6 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 12:41:53 +0200 Subject: [PATCH 47/57] Fixed path to html --- apps/ha/custom.html | 28 ++++++++++++++-------------- apps/ha/metadata.json | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index 6c4bb9077..b0bb39242 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -22,21 +22,21 @@ }); - // When the 'upload' button is clicked... - document.getElementById("upload").addEventListener("click", function() { - // get the text to add - var text = document.getElementById("triggers").value; - console.log(text); - // build the app's text using a templated String - var app = text; - // send finished app (in addition to contents of app.json) - sendCustomizedApp({ - storage:[ - {name:"ha.trigger.json", url:"ha.trigger.json", content:app}, - ] + // When the 'upload' button is clicked... + document.getElementById("upload").addEventListener("click", function() { + // get the text to add + var text = document.getElementById("triggers").value; + console.log(text); + // build the app's text using a templated String + var app = text; + // send finished app (in addition to contents of app.json) + sendCustomizedApp({ + storage:[ + {name:"ha.trigger.json", url:"ha.trigger.json", content:app}, + ] + }); + console.log("Sent ha.trigger.json!"); }); - console.log("Sent ha.trigger.json!"); - }); diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index 9b4ca54af..0f9929d8c 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -8,7 +8,7 @@ "tags": "tool", "readme": "README.md", "supports": ["BANGLEJS2"], - "custom": "trigger.html", + "custom": "custom.html", "screenshots": [ {"url":"screenshot.png"}, {"url":"screenshot_2.png"}, From f98fd1662d6772a45e0f8ade19213e8e92f38b8b Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 12:49:06 +0200 Subject: [PATCH 48/57] Improved custom.html --- apps/ha/custom.html | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index b0bb39242..7d2296003 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -3,8 +3,8 @@ -

Upload Tiggers

-

You must upload a list of json objects -- an example is given below

+

Upload Tigger

+

Status:

+

@@ -20,14 +13,22 @@ /* * Load trigger from BangleJs */ - document.getElementById("status").innerHTML = "Loading trigger from BangleJs..."; + console.log("Loading trigger from BangleJs..."); try { Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{ document.getElementById("triggers").innerHTML = data; - document.getElementById("status").innerHTML = "Loaded trigger from BangleJs."; + console.log("Successfully loaded trigger from BangleJs."); + console.log(data); }); } catch(ex) { - document.getElementById("status").innerHTML = "Could not load trigger from BangleJs."; + console.log("(Warning) Could not load trigger from BangleJs."); + console.log(ex); + document.getElementById("triggers").innerHTML = ` +[ + {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, + {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, + {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} +]` } /* @@ -35,14 +36,11 @@ */ document.getElementById("upload").addEventListener("click", function() { // get the text to add - var text = document.getElementById("triggers").value; - console.log(text); - // build the app's text using a templated String - var app = text; + var triggerText = document.getElementById("triggers").value; // send finished app (in addition to contents of app.json) sendCustomizedApp({ storage:[ - {name:"ha.trigger.json", url:"ha.trigger.json", content:app}, + {name:"ha.trigger.json", url:"ha.trigger.json", content:triggerText}, ] }); console.log("Sent ha.trigger.json!"); From e51967d8d4db724f59965ae93bc6ff0b6bd9f744 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 12:57:33 +0200 Subject: [PATCH 50/57] Improvements --- apps/ha/custom.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index f1597d740..f5021f6b6 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -14,21 +14,25 @@ * Load trigger from BangleJs */ console.log("Loading trigger from BangleJs..."); + var loadedData = false; try { Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{ document.getElementById("triggers").innerHTML = data; console.log("Successfully loaded trigger from BangleJs."); console.log(data); + loadedData = true; }); - } catch(ex) { - console.log("(Warning) Could not load trigger from BangleJs."); - console.log(ex); - document.getElementById("triggers").innerHTML = ` + } finally { + if(!loadedData){ + console.log("(Warning) Could not load trigger from BangleJs."); + console.log(ex); + document.getElementById("triggers").innerHTML = ` [ {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} ]` + } } /* From 701e1c58ef2f74a1519a74db9c4cf260ac9505c9 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 13:01:29 +0200 Subject: [PATCH 51/57] Minor changes --- apps/ha/custom.html | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index f5021f6b6..3c52794ad 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -4,7 +4,12 @@

Upload Tigger

-

+

@@ -22,17 +27,9 @@ console.log(data); loadedData = true; }); - } finally { - if(!loadedData){ - console.log("(Warning) Could not load trigger from BangleJs."); - console.log(ex); - document.getElementById("triggers").innerHTML = ` -[ - {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, - {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, - {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} -]` - } + } catch { + console.log("(Warning) Could not load trigger from BangleJs."); + console.log(ex); } /* From 6c1b48bcbad7e66b20fb41731ee01f431c8d09cf Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 13:04:13 +0200 Subject: [PATCH 52/57] Test --- apps/ha/custom.html | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index 3c52794ad..f5021f6b6 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -4,12 +4,7 @@

Upload Tigger

-

+

@@ -27,9 +22,17 @@ console.log(data); loadedData = true; }); - } catch { - console.log("(Warning) Could not load trigger from BangleJs."); - console.log(ex); + } finally { + if(!loadedData){ + console.log("(Warning) Could not load trigger from BangleJs."); + console.log(ex); + document.getElementById("triggers").innerHTML = ` +[ + {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, + {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, + {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} +]` + } } /* From 3543cc68581a85d120f928a1c4d33db4b3bca266 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 13:09:02 +0200 Subject: [PATCH 53/57] Better default entries handling --- apps/ha/custom.html | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index f5021f6b6..7de7bd8b6 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -14,27 +14,35 @@ * Load trigger from BangleJs */ console.log("Loading trigger from BangleJs..."); - var loadedData = false; + + function setDefaultEntries(){ + console.log("Set default trigger entries."); + document.getElementById("triggers").innerHTML = ` +[ +{"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, +{"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, +{"display": "Living Room", "trigger": "OVEN", "icon":"fire"} +]` + } + try { Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{ document.getElementById("triggers").innerHTML = data; - console.log("Successfully loaded trigger from BangleJs."); - console.log(data); - loadedData = true; + if(data != ""){ + console.log("Successfully loaded trigger from BangleJs."); + console.log(data); + loadedData = true; + } else { + setDefaultEntries(); + } }); - } finally { - if(!loadedData){ - console.log("(Warning) Could not load trigger from BangleJs."); - console.log(ex); - document.getElementById("triggers").innerHTML = ` -[ - {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, - {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, - {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} -]` - } + } catch(ex) { + console.log("(Warning) Could not load trigger from BangleJs."); + console.log(ex); + setDefaultEntries(); } + /* * Upload trigger to BangleJs */ From 49eb18df0b463e95dec04b6d4d969da790281578 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 13:12:21 +0200 Subject: [PATCH 54/57] Working verision. --- apps/ha/custom.html | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index 7de7bd8b6..90ba6e10c 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -4,7 +4,13 @@

Upload Tigger

-

+

@@ -14,35 +20,16 @@ * Load trigger from BangleJs */ console.log("Loading trigger from BangleJs..."); - - function setDefaultEntries(){ - console.log("Set default trigger entries."); - document.getElementById("triggers").innerHTML = ` -[ -{"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, -{"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, -{"display": "Living Room", "trigger": "OVEN", "icon":"fire"} -]` - } - try { Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{ document.getElementById("triggers").innerHTML = data; - if(data != ""){ - console.log("Successfully loaded trigger from BangleJs."); - console.log(data); - loadedData = true; - } else { - setDefaultEntries(); - } + console.log("Loaded trigger from BangleJs."); }); } catch(ex) { console.log("(Warning) Could not load trigger from BangleJs."); console.log(ex); - setDefaultEntries(); } - /* * Upload trigger to BangleJs */ From 8ee12fc5e83f45ab9fbfd911c7b9a9d8ea5c6bae Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 15:56:41 +0200 Subject: [PATCH 55/57] Minor fix if nothing is installed yet --- apps/ha/custom.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index 90ba6e10c..49f5a2eb8 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -9,8 +9,7 @@ {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} -] -

+]

@@ -22,8 +21,10 @@ console.log("Loading trigger from BangleJs..."); try { Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{ + if(data.length > 0){ document.getElementById("triggers").innerHTML = data; console.log("Loaded trigger from BangleJs."); + } }); } catch(ex) { console.log("(Warning) Could not load trigger from BangleJs."); From 8eb1f230103ac53cd04ce52e07f9c6b6f2f14334 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 15:59:40 +0200 Subject: [PATCH 56/57] Show template if nothing is on bangle yet... --- apps/ha/custom.html | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index 49f5a2eb8..095c2959c 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -4,12 +4,7 @@

Upload Tigger

-

+

@@ -22,8 +17,15 @@ try { Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{ if(data.length > 0){ + console.log("Load trigger from BangleJs."); document.getElementById("triggers").innerHTML = data; - console.log("Loaded trigger from BangleJs."); + } else { + console.log("Load trigger from Template."); + document.getElementById("triggers").innerHTML = `[ + {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, + {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, + {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} +]` } }); } catch(ex) { From d6a1c6b07fbccfabb945e529f5c3e876cbea61b5 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 26 Jun 2022 16:02:33 +0200 Subject: [PATCH 57/57] Fix template --- apps/ha/custom.html | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/ha/custom.html b/apps/ha/custom.html index 095c2959c..49f5a2eb8 100644 --- a/apps/ha/custom.html +++ b/apps/ha/custom.html @@ -4,7 +4,12 @@

Upload Tigger

-

+

@@ -17,15 +22,8 @@ try { Puck.eval(`require("Storage").read(${JSON.stringify("ha.trigger.json")})`,data=>{ if(data.length > 0){ - console.log("Load trigger from BangleJs."); document.getElementById("triggers").innerHTML = data; - } else { - console.log("Load trigger from Template."); - document.getElementById("triggers").innerHTML = `[ - {"display": "Open", "trigger": "OPEN_DOOR", "icon":"door"}, - {"display": "Office", "trigger": "TOGGLE_LIGHT", "icon":"light"}, - {"display": "Living Room", "trigger": "OVEN", "icon":"fire"} -]` + console.log("Loaded trigger from BangleJs."); } }); } catch(ex) {