Initial commit

master
Kuba Orlik 4 months ago
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"
}

@ -0,0 +1,4 @@
const { promisify } = require("node:util");
const sleep = promisify((time, callback) => setTimeout(callback, time));
module.exports = { sleep };
Loading…
Cancel
Save