Stream Deck and Homekit update.
I mentioned previously using HomeBridge to help control a fan with the Elgato Stream Deck. It felt like overkill and I later found a much more stable solution for this that I'll talk about below. However, Robert Hawdon sent me an update to the original code I was using that saves the current state of the switch so that it can restore the state through a HomeBridge restart or crash.
const port = 3000;
const express = require('express');
const bodyParser = require('body-parser');
const stateFile = './state.json';
var fs = require('fs');
let app = express();
app.use(bodyParser.text({ type: 'text/*' }))
var switches = {};
function saveState() {
var data = JSON.stringify(switches);
fs.writeFile(stateFile, data, function (err) {
if (err) {
console.log('There has been an error saving the switch state.');
console.log(err.message);
return;
}
console.log('State saved successfully.')
});
}
function loadState() {
if (fs.existsSync(stateFile)) {
var data = fs.readFileSync(stateFile);
try {
switches = JSON.parse(data);
}
catch (err) {
console.log('There has been an error reading the switch state.');
console.log(err);
}
}
}
function getSwitchValue(switchName, trueValue, falseValue) {
let value = switches[switchName];
if (trueValue === undefined) {
trueValue = true;
}
if (falseValue == undefined) {
falseValue = false;
}
if (value === undefined || value == false) {
return falseValue;
} else {
return trueValue;
}
}
function setSwitchValue(switchName, valueAsBoolean) {
// Don't care about current state of switch - or if it exists or not at this point.
switches[switchName] = valueAsBoolean;
saveState();
}
// ==================
// General purpose getter to show the state of all switches in the browser.
app.get('/', (request, response) => {
// return current state of all known switches
response.setHeader('Content-Type', 'application/json');
response.send(JSON.stringify(switches, null, 4));
});
// HomeBridge http switch end points.
app.get('/switches/:switchName/on', (request, response) => {
let switchName = request.params.switchName;
//console.log("switchOn called for switch: ", switchName);
setSwitchValue(switchName, true);
let switchValue = getSwitchValue(switchName, "1", "0");
response.setHeader('Content-Type', 'text/plain');
response.send(switchValue);
});
app.get('/switches/:switchName/off', (request, response) => {
let switchName = request.params.switchName;
//console.log("switchOff called for switch: ", switchName);
setSwitchValue(switchName, false);
let switchValue = getSwitchValue(switchName, "1", "0");
response.setHeader('Content-Type', 'text/plain');
response.send(switchValue);
});
app.get('/switches/:switchName/status', (request, response) => {
let switchName = request.params.switchName;
//console.log("switchStatus called for switch: ", switchName);
let switchValue = getSwitchValue(switchName, "1", "0");
response.setHeader('Content-Type', 'text/plain');
response.send(switchValue);
});
// ==================
// Stream Deck MCControl endpoints.
app.get('/switches/:switchName', (request, response) => {
let switchName = request.params.switchName;
//console.log("got status request for switch: ", switchName);
let switchValue = getSwitchValue(switchName, "ON", "OFF");
response.setHeader('Content-Type', 'application/json');
response.send(JSON.stringify({ state: switchValue }));
});
app.post('/switches/:switchName', (request, response) => {
let switchName = request.params.switchName;
//console.log("switch set post called for switch: ", switchName);
var data = request.body;
console.log("Data: ", data);
if (data == "ON") {
switchState = true;
} else if (data == "OFF") {
switchState = false;
}
setSwitchValue(switchName, switchState);
let switchValue = getSwitchValue(switchName, "ON", "OFF");
response.setHeader('Content-Type', 'application/json');
response.send(JSON.stringify({ state: switchValue }));
});
app.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
loadState();
console.log(`server is listening on ${port}`)
});
These days I'm not using HomeBridge at all. But, I still use the fan and turn it on and off with the StreamDeck. I do this with HomeControl for the Mac. This app lets you control all of your home kit devices and scenes with a menu on your mac. It also lets you use control devices with callback urls via the command line. You can create a script and execute that script with a button on the StreamDeck. However, It doesn't show the current state of the devine on the StreamDeck button with this technique.
#!/bin/bash
open -g "homecontrol://x-callback-url/run-action?action-type=switch-device-status&item-type=device&item-name=Fan&home-name=Home&activation-mode=toggle&authentication-token=1234"
You need to get the url to use here with the HomeControl app. There is an auth token that will be unique to your computer. I hope this update helps anyone trying to do something simmilar.