Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Home Assistant Control app #3721

Closed
wants to merge 12 commits into from
2 changes: 2 additions & 0 deletions apps/hasscontrol/ChangeLog
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0.01: Initial version.
0.02: Implement web editor for config file.
1 change: 1 addition & 0 deletions apps/hasscontrol/app-icon.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions apps/hasscontrol/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/* https://www.espruino.com/Bangle.js+Fast+Load:
* "We're recommending you only use this on Clocks and Launchers right now - the potential improvement for apps is small (as it only affects loading the next app after" yours), and the potential for things to break is much higher!"
*/

Bangle.loadWidgets();
Bangle.drawWidgets();

function showErrorAndQuit(error) {
E.showMessage("No HASS config!");
setTimeout(function() {
load()

}, 2000);
}

var config = require("Storage").readJSON("hasscontrol.hass.json", true);
if (config == undefined) showErrorAndQuit("No HASS config!"); // are all these errors necessary?
config = config[0];
if (!config.hass_url) showErrorAndQuit("No HASS URL!");
if (!config.hass_token) showErrorAndQuit("No HASS token!");

/* not used in v0.02.
function hassGetState(entityId) {
return Bangle.http(config.hass_url + "/states/" + entityId, {
"method":"GET",
"headers": {
"Authorization":"Bearer " + config.hass_token,
"Content-Type":"application/json"
}
}
);
}

function hassSetState(entityId, state) {
Bangle.http(config.hass_url + "/states/" + entityId, {
"method":"PUSH",
"headers": {
"Authorization":"Bearer " + config.hass_token,
"Content-Type":"application/json"
},
"body":`{"state":"${state}"}`
}
);
}
*/

function hassActivateService(service, data) {
Bangle.http(config.hass_url + "/services/" + service.replace(".", "/"), {
"method":"POST",
"headers": {
"Authorization":"Bearer " + config.hass_token,
"Content-Type":"application/json"
},
"body":data
}
);
}

var menus = {
"entitiesListMenu": {
"": {title: "Entities"},
"< Back": function () { load(); }
},
"entities": {}
}

config.entities.forEach((entity) => {
let entityMenu = {
"": { title: entity.name },
"< Back": function () { E.showMenu(menus.entitiesListMenu); }
}

entity.actions.forEach((action) => {

if (action.type == "button") {

entityMenu[action.name] = function() {
hassActivateService(action.action, `{ "entity_id": "${entity.entity_id}" }`);
}

} else if (action.type == "number") {

entityMenu[action.name] = {
value: action.placeholder, // placeholder! get the state of the entity and put it here?
min: action.min,
max: action.max,
step: 1,
onchange: number => {
hassActivateService(action.action, `{ "entity_id": "${entity.entity_id}", "${action.argument}": ${number} }`)
}
}

} else if (action.type == "selector") {

let selectorMenu = {
"": { title: action.name },
"< Back": function () { E.showMenu(menus.entitiesListMenu) } // this dumps you back to the main list instead of going up one level :(
}

action.options.forEach((option) => {
selectorMenu[option] = function () {
hassActivateService(action.action, `{ "entity_id": "${entity.entity_id}", "${action.argument}": "${option}" }`);
}
});

entityMenu[action.name] = function() { E.showMenu(selectorMenu); }

}
});

menus.entities[entity.entity_id] = entityMenu; // put the constructed menu into the entities list

menus.entitiesListMenu[entity.name] = function () {
E.showMenu(menus.entities[entity.entity_id]); // put the link to the new menu into the home screen
};
});

E.showMenu(menus.entitiesListMenu);
Binary file added apps/hasscontrol/app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
83 changes: 83 additions & 0 deletions apps/hasscontrol/hass.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
[{
"hass_url":"https://homeassistant.yourdomain.com/api",
"hass_token":"nonsensenonsensenonsensenonsensenonsensenonsensenonsensenonsensenonsensenonsensenonsensenonsensenonsensenonsense",
"entities": [
{
"entity_id": "light.example_light",
"name": "Example Light",
"actions": [
{
"action": "light.toggle",
"name": "Toggle",
"type": "button"
},
{
"action": "light.turn_on",
"name": "Set brightness",
"type": "number",
"argument": "brightness_pct",
"min": 0,
"max": 100,
"placeholder": 100
},
{
"action": "light.turn_on",
"name": "Turn on",
"type": "button"
},
{
"action": "light.turn_off",
"name": "Turn off",
"type": "button"
}
]
},
{
"entity_id": "climate.example_ac",
"name": "Example AC",
"actions": [
{
"action": "climate.set_hvac_mode",
"name": "Mode",
"type": "selector",
"argument": "hvac_mode",
"options": [
"off",
"cool",
"heat",
"auto",
"dry",
"fan_only",
"heat_cool"
]
},
{
"action": "climate.set_temperature",
"name": "Temperature",
"type": "number",
"argument": "temperature",
"min": 18,
"max": 30,
"placeholder": 20
}
]
},
{
"entity_id": "lock.example_lock",
"name": "Example Lock",
"type": "button",
"actions": [
{
"action": "lock.unlock",
"name": "Unlock",
"type": "button",
},
{
"action": "lock.lock",
"name": "Lock",
"type": "button"
}
]
}
]
}]
50 changes: 50 additions & 0 deletions apps/hasscontrol/interface.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<textarea cols=60 rows=45 placeholder="Home Assistant Control config (JSON)" id="config"></textarea>
<button class="btn btn-default" id="btnSave">Save config to Bangle</button>
<button class="btn btn-default" id="btnLoad">Reload config from Bangle</button>
<button class="btn btn-default" id="btnLoadExample">Load example config</button>

<script src="../../core/lib/interface.js"></script>
<script>
// tyvm for the info https://www.espruino.com/Bangle.js+Storage

var configElement = document.getElementById("config");

function saveConfigToBangle() {
Util.writeStorage("hasscontrol.hass.json", configElement.value);
}

function loadConfigFromBangle() {
Util.readStorage("hasscontrol.hass.json", config => {
configElement.value = config;
});
}

function loadExampleConfig() {
// this doesnt look like the right way to grab a file but im not a web developer so
fetch("./hass.json").then(response => response.text()).then(data => { configElement.value = data; });
}

document.getElementById("btnSave").addEventListener("click", function() {
saveConfigToBangle();
});

document.getElementById("btnLoad").addEventListener("click", function() {
loadConfigFromBangle();
});

document.getElementById("btnLoadExample").addEventListener("click", function() {
loadExampleConfig();
});

function onInit() {
loadConfigFromBangle();
}

</script>
</body>
</html>
23 changes: 23 additions & 0 deletions apps/hasscontrol/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{ "id": "hasscontrol",
"name": "Home Assistant Control",
"shortName":"HASS Control",
"version":"0.02",
"description": "Control your Home Assistant instance from your Bangle. Uses GadgetBridge's HTTP capability to send API requests directly from your watch.",
"icon": "app.png",
"tags": "tool,bluetooth",
"supports" : ["BANGLEJS2"],
"interface": "interface.html",
"storage": [
{"name":"hasscontrol.app.js","url":"app.js"},
{"name":"hasscontrol.img","url":"app-icon.js","evaluate":true},
{"name":"hasscontrol.hass.json","url":"hass.json"}
],
"data": [
{"name":"hass.json"}
],
"screenshots": [
{"url":"screenshot_mainlist.png"},
{"url":"screenshot_light.png"},
{"url":"screenshot_ac.png"}
]
}
Binary file added apps/hasscontrol/screenshot_ac.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/hasscontrol/screenshot_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/hasscontrol/screenshot_mainlist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading