Initial commit
commit
52f9b6bd6a
@ -0,0 +1,16 @@
|
||||
# Use any Home Assistant lights with Hyperion
|
||||
|
||||
## Setup:
|
||||
|
||||
1. Clone this respository;
|
||||
|
||||
2. Edit `config.js` to your liking. There are two light types: `rgb` and
|
||||
`dim`. The names of the lights must represent light entity id that are
|
||||
present in Home Assistant;
|
||||
|
||||
3. Generate a Home Assistant Token using the /profile view (scroll to the bottom
|
||||
of the view);
|
||||
4. Setup a new LED instance in Hyperion using the `udpraw` controller. Set the
|
||||
number of lights to the amount of lights you've specified in the `config.js`
|
||||
file;
|
||||
5. Run `HA_TOKEN=your_token12341234123432 node .`
|
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
lights: [
|
||||
{ id: "lampa_na_parapecie_rgb_light", type: "rgb" },
|
||||
{
|
||||
id: "ikea_of_sweden_tradfribulbe27wsglobeopal1055lm_light" /* lampa stojąca */,
|
||||
type: "dim",
|
||||
},
|
||||
],
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
const TOKEN = process.env.HA_TOKEN;
|
||||
const HA_URL = process.env.HA_URL || "http://127.0.0.1:8123";
|
||||
const PORT = parseInt(process.env.HA_BRIDGE_PORT || "41234");
|
||||
|
||||
module.exports = { TOKEN, HA_URL, PORT };
|
@ -0,0 +1,42 @@
|
||||
const dgram = require("node:dgram");
|
||||
const server = dgram.createSocket("udp4");
|
||||
|
||||
const { lights } = require("./config.js");
|
||||
const light_loop = require("./light-loop.js");
|
||||
const latest_color = require("./latest_color.js");
|
||||
const { TOKEN, PORT } = require("./env.js");
|
||||
|
||||
server.on("error", (err) => {
|
||||
console.error(`server error:\n${err.stack}`);
|
||||
server.close();
|
||||
});
|
||||
|
||||
const debug = false;
|
||||
const max_brightness = 0.8;
|
||||
|
||||
if (!TOKEN) {
|
||||
throw new Error(
|
||||
"Provide the Home Assistant Long Lived Token as a HA_TOKEN environment variable. Go to /profile in Home Assistant and scroll down.",
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Remember to set the Hyperion output controller type to UDPRAW and set it to output ${lights.length} lights`,
|
||||
);
|
||||
|
||||
server.on("message", (msg, rinfo) => {
|
||||
latest_color.set(Array.from(msg).map((e) => parseInt(e)));
|
||||
if (debug) {
|
||||
console.log("Received colors:", latest_color.get());
|
||||
}
|
||||
});
|
||||
|
||||
server.on("listening", async () => {
|
||||
const address = server.address();
|
||||
console.log(`server listening ${address.address}:${address.port}`);
|
||||
for (let i in lights) {
|
||||
light_loop(i, max_brightness, debug);
|
||||
}
|
||||
});
|
||||
|
||||
server.bind(PORT);
|
@ -0,0 +1,20 @@
|
||||
const { lights } = require("./config.js");
|
||||
|
||||
let latest_color = [];
|
||||
|
||||
// initialize
|
||||
for (let i in lights) {
|
||||
for (let j = 1; j <= 3; j++) {
|
||||
latest_color.push(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: () => {
|
||||
return latest_color;
|
||||
},
|
||||
|
||||
set: (new_color) => {
|
||||
latest_color = new_color;
|
||||
},
|
||||
};
|
@ -0,0 +1,59 @@
|
||||
const { HA_URL, TOKEN } = require("./env.js");
|
||||
|
||||
const { sleep } = require("./util.js");
|
||||
const latest_color = require("./latest_color.js");
|
||||
const { lights } = require("./config.js");
|
||||
|
||||
async function send_color(light_data, color, max_brightness, debug) {
|
||||
const brightness = (color[0] + color[1] + color[2]) / 3 / 255;
|
||||
let body = { entity_id: `light.${light_data.id}`, transition: 0.18 };
|
||||
|
||||
if (light_data.type == "rgb") {
|
||||
body.rgb_color = color;
|
||||
body.brightness = Math.floor(
|
||||
Math.max(...latest_color.get()) * max_brightness,
|
||||
);
|
||||
} else {
|
||||
// body.brightness = Math.max(1, Math.round(255 * brightness)); // 0 seems to turn it off and make it slower to react
|
||||
body.brightness = Math.floor(
|
||||
Math.max(...latest_color.get()) * max_brightness,
|
||||
);
|
||||
}
|
||||
|
||||
return fetch(`${HA_URL}/api/services/light/turn_on`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${TOKEN}`,
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
}).then(async (response) => {
|
||||
if (debug) {
|
||||
console.log(await response.text());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = async function light_loop(light_index, max_brightness, debug) {
|
||||
let last_time = 0;
|
||||
let last_color = [0, 0, 0];
|
||||
while (true) {
|
||||
last_time = Date.now();
|
||||
const from = 3 * light_index;
|
||||
const to = 3 * (light_index + 1);
|
||||
const current_color = latest_color.get().slice(from, to);
|
||||
let is_changed = false;
|
||||
for (i in last_color) {
|
||||
if (last_color[i] != current_color[i]) {
|
||||
is_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_changed) {
|
||||
await send_color(lights[light_index], current_color);
|
||||
last_color = current_color;
|
||||
} else {
|
||||
await sleep(10);
|
||||
}
|
||||
}
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "hyperion-ha",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
Loading…
Reference in New Issue