Skip to content
This repository has been archived by the owner on Apr 15, 2021. It is now read-only.

Commit

Permalink
🔖 First release.
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobias Möritz committed Jan 29, 2019
0 parents commit 74876ad
Show file tree
Hide file tree
Showing 17 changed files with 1,984 additions and 0 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Home Assistant for Elgato Stream Deck
> Use the Elgato Stream Deck as Home Assistant controller. Call any available service and toggle lights or resume your music.
Should work cross-platform. Tested with macOS Mojave and HassOS on RPi0W.

Not using Home Assistant but still want to control your devices without a server? Check out my other repositories and try the IFTTT Integration [here](https://github.com/tobimori/streamdeck-ifttt).
## How to use

This Integration uses the Home Assistant REST API and Service Calls.

### General installation & setup

Download the latest release [here](https://github.com/tobimori/streamdeck-homeassistant/releases/latest "Hello from the other side...") and execute the file. The Stream Deck software should ask you to continue the installation.

![Installation](resources/readme/installation.png)

### Creating a new action

Drag and drop the Home Assistant action from the Action list to the Canvas area. Select it and configure it.

You can get a long-live access token by creating on your profile in Home Assistant. (Just add "/profile" to your url if you don't find it)

For configuring the other required options, check [here](https://www.home-assistant.io/docs/scripts/service-calls/).
Service data should be served in json like [here](https://www.home-assistant.io/docs/scripts/service-calls/#using-the-services-developer-tool).

To test out your service calls, check the Service development tool on your Home Assistant instance.

## Support

Feel free to ask your questions/report bugs on the [community-ran Elgato Discord Server](https://discord.gg/aWVu2eM). I'm there too ;)
8 changes: 8 additions & 0 deletions de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Description": "\uD83C\uDFE0 Verwende das Elgato Stream Deck als Home Assistant-Steuerzentrale. Rufe jeden beliebigen Dienst ab und schalte deine Lampen um oder spiele Musik ab.",
"Name": "Home Assistant",
"de.tobimori.streamdeck.homeassistant.action": {
"Name": "Home Assistant-Knopf",
"Tooltip": "Erwecke dein Zuhause mit Home Assistant und dem Stream Deck!"
}
}
42 changes: 42 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"Actions": [
{
"Icon": "resources/actionIcon",
"Name": "Home Assistant Button",
"States": [
{
"Image": "resources/actionDefaultImage",
"TitleAlignment": "bottom",
"FontSize": "10"
}
],
"SupportedInMultiActions": true,
"Tooltip": "Awaken your home using Home Assistant and Stream Deck!",
"UUID": "de.tobimori.streamdeck.homeassistant.action"
}
],
"Author": "tobimori",
"CodePath": "plugin/main.html",
"Description": "\uD83C\uDFE0 Use the Elgato Stream Deck as Home Assistant controller. Call any available service and toggle lights or resume your music.",
"Name": "Home Assistant",
"Icon": "resources/pluginIcon",
"URL": "https://streamdeck.tobimori.de",
"PropertyInspectorPath": "propertyinspector/main_pi.html",
"Version": "1.0",
"Category": "tobimori",
"CategoryIcon": "resources/categoryIcon",
"OS": [
{
"MinimumVersion" : "10.12",
"Platform": "mac"
},
{
"Platform": "windows",
"MinimumVersion" : "10"
}
],
"Software":
{
"MinimumVersion" : "4.0.2"
}
}
13 changes: 13 additions & 0 deletions plugin/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>

<head>
<title>de.tobimori.streamdeck.homeassistant</title>
<meta charset="utf-8" />
<script src="main.js"></script>
</head>

<body></body>

</html>

139 changes: 139 additions & 0 deletions plugin/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
let websocket = null;
let pluginUUID = null;
let settingsCache = {};

const webhookAction = {

type : "de.tobimori.streamdeck.homeassistant.action",

onKeyUp : function(context, settings, coordinates, userDesiredState) {
let ip = "";
let authtoken = "";
let domain = "";
let service = "";
let data = "";

if(settings['ip'] != null){
ip = settings["ip"];
}
if(settings['authtoken'] != null){
authtoken = settings["authtoken"];
}
if(settings['domain'] != null){
domain = settings["domain"];
}
if(settings['service'] != null){
service = settings["service"];
}
if(settings['data'] != null){
data = settings["data"];
}
if(!ip || !authtoken || !domain || !service) {
this.ShowReaction(context, "Alert")
} else {
const request = new XMLHttpRequest();
const url = `${ip}/api/services/${domain}/${service}`;
request.open("POST", url);
request.setRequestHeader("Authorization", `Bearer ${authtoken}`);
if(data !== "") {
request.setRequestHeader("Content-Type", "application/json");
request.send(data);
} else {
request.send();
}
}

},

onWillAppear : function(context, settings, coordinates) {
settingsCache[context] = settings;
},

ShowReaction : function(context, type) {
const json = {
"event": "show" + type,
"context": context,
};
websocket.send(JSON.stringify(json));
},

SetSettings : function(context, settings) {
const json = {
"event": "setSettings",
"context": context,
"payload": settings
};
websocket.send(JSON.stringify(json));
},

SendSettings : function(action, context) {
const json = {
"action": action,
"event": "sendToPropertyInspector",
"context": context,
"payload": settingsCache[context]
};

websocket.send(JSON.stringify(json));
}
};

function connectSocket(inPort, inPluginUUID, inRegisterEvent, inInfo)
{
pluginUUID = inPluginUUID;

// Open the web socket
websocket = new WebSocket("ws://localhost:" + inPort);

function registerPlugin(inPluginUUID)
{
const json = {
"event": inRegisterEvent,
"uuid": inPluginUUID
};

websocket.send(JSON.stringify(json));
};

websocket.onopen = function()
{
// WebSocket is connected, send message
registerPlugin(pluginUUID);
};

websocket.onmessage = function (evt)
{
// Received message from Stream Deck
const jsonObj = JSON.parse(evt.data);
const event = jsonObj['event'];
const action = jsonObj['action'];
const context = jsonObj['context'];
const jsonPayload = jsonObj['payload'];

if(event == "keyUp")
{
const settings = jsonPayload['settings'];
const coordinates = jsonPayload['coordinates'];
const userDesiredState = jsonPayload['userDesiredState'];
webhookAction.onKeyUp(context, settings, coordinates, userDesiredState);
}
else if(event == "willAppear")
{
const settings = jsonPayload['settings'];
const coordinates = jsonPayload['coordinates'];
webhookAction.onWillAppear(context, settings, coordinates);
}
else if(event == "sendToPlugin") {

if(jsonPayload['type'] == "updateSettings") {

webhookAction.SetSettings(context, jsonPayload);
settingsCache[context] = jsonPayload;

} else if(jsonPayload['type'] == "requestSettings") {

webhookAction.SendSettings(action, context);
}
}
};
};
3 changes: 3 additions & 0 deletions propertyinspector/caret.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions propertyinspector/main_pi.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8" />
<title>de.tobimori.streamdeck.homeassistant.pi</title>
<link rel="stylesheet" href="sdpi.css">
<script src="main_pi.js"></script>
</head>

<body>
<div class="sdpi-wrapper hidden">

<div class="sdpi-heading">SETTINGS</div>

<div class="sdpi-item">
<div class="sdpi-item-label">Home Assistant Address</div>
<input class="sdpi-item-value" id="ip" value="" onchange="updateSettings()" placeholder="Enter the URL to your Home Assistant frontend" required>
</div>
<div class="sdpi-item">
<div class="sdpi-item-label">Authorization Token</div>
<input class="sdpi-item-value" id="authtoken" value="" onchange="updateSettings()" placeholder="Enter a long-live auth token" required>
</div>
<div class="sdpi-item">
<div class="sdpi-item-label">Service Domain</div>
<input class="sdpi-item-value" id="domain" value="" onchange="updateSettings()" placeholder="Enter the service domain (e.g. light)" required>
</div>
<div class="sdpi-item">
<div class="sdpi-item-label">Service</div>
<input class="sdpi-item-value" id="service" value="" onchange="updateSettings()" placeholder="Enter the service to be called (e.g. toggle)" required>
</div>
<div class="sdpi-item">
<div class="sdpi-item-label">Service Data</div>
<input class="sdpi-item-value" id="data" value="" onchange="updateSettings()" placeholder="Optional: Enter the service data (e.g. the entity id)">
</div>
</div>
</body>

</html>
105 changes: 105 additions & 0 deletions propertyinspector/main_pi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
let websocket = null,
uuid = null,
actionInfo = {};

function connectSocket(inPort, inUUID, inRegisterEvent, inInfo, inActionInfo) {
uuid = inUUID;

actionInfo = JSON.parse(inActionInfo);
websocket = new WebSocket('ws://localhost:' + inPort);

websocket.onopen = function () {
const json = {
event: inRegisterEvent,
uuid: inUUID
};
websocket.send(JSON.stringify(json));
requestSettings();
};

websocket.onmessage = function (evt) {
// Received message from Stream Deck
const jsonObj = JSON.parse(evt.data);
if (jsonObj.event === 'sendToPropertyInspector') {
const payload = jsonObj.payload;
if (payload.error) {
return;
}

const ip = document.getElementById('ip');
ip.value = payload.ip;

const authtoken = document.getElementById('authtoken');
authtoken.value = payload.authtoken;

const domain = document.getElementById('domain');
domain.value = payload.domain;

const service = document.getElementById('service');
service.value = payload.service;

const data = document.getElementById('data');
data.value = payload.data;

if(ip.value == "undefined" || authtoken.value == "undefined" || domain.value == "undefined" || service.value == "undefined") {
ip.value = "";
authtoken.value = "";
domain.value = "";
service.value = "";
}
if(data.value == "undefined") {
data.value = "";
}

const el = document.querySelector('.sdpi-wrapper');
el && el.classList.remove('hidden');
}
};

}

function requestSettings() {
if (websocket) {
let payload = {};
payload.type = "requestSettings";
const json = {
"action": actionInfo['action'],
"event": "sendToPlugin",
"context": uuid,
"payload": payload,
};
websocket.send(JSON.stringify(json));
}
}

function updateSettings() {
if (websocket) {
let payload = {};

payload.type = "updateSettings";

const ip = document.getElementById('ip');
payload.ip = ip.value;

const authtoken = document.getElementById('authtoken');
payload.authtoken = authtoken.value;

const domain = document.getElementById('domain');
payload.domain = domain.value;

const service = document.getElementById('service');
payload.service = service.value;

const data = document.getElementById('data');
payload.data = data.value;

console.log(payload);
const json = {
"action": actionInfo['action'],
"event": "sendToPlugin",
"context": uuid,
"payload": payload,
};
websocket.send(JSON.stringify(json));
}
}
Loading

0 comments on commit 74876ad

Please sign in to comment.