Skip to content

Instantly share code, notes, and snippets.

@biern
Last active March 5, 2018 15:57
Show Gist options
  • Save biern/cead0c0a92cb766c5f04f1a17ea9c45e to your computer and use it in GitHub Desktop.
Save biern/cead0c0a92cb766c5f04f1a17ea9c45e to your computer and use it in GitHub Desktop.
Yeelight Screen Ambience
'use strict';
const Color = require("color");
const Yeelight = require('node-yeelight-wifi');
const robot = require('robotjs');
const net = require('net');
const os = require('os');
const R = require('ramda');
const SERVER_PORT = 32167;
const MY_IP = guessIP();
const updateInterval = 100;
function run() {
const screenSize = robot.getScreenSize();
const effectDuration = updateInterval * 3 / 4;
const sockets = [];
const bulbs = [];
const server = net.createServer((socket) => {
console.log('New socket connection');
sockets.push(socket);
});
server.listen(SERVER_PORT, '0.0.0.0');
const look = new Yeelight.Lookup();
look.on("detected", (light) => {
console.log(`New bulb detected: id ${light.id} name ${light.name}`);
bulbs.push(light);
light.sendCommand('set_music', [1, MY_IP, SERVER_PORT]);
});
setInterval(() => {
const pixels = getScreenStrip(screenSize);
const ambience = getPixelsAmbience(pixels);
updateBulbs(sockets, bulbs, ambience, effectDuration);
}, updateInterval);
}
function updateBulbs(sockets, bulbs, { rgb, brightness }, duration) {
const rgbNumber = Color.rgb(rgb).rgbNumber();
const brightnessPercent = brightness * 100;
for (let socket of sockets) {
for (let bulb of bulbs) {
sendCommand(
socket, bulb, "set_rgb", [rgbNumber, "smooth", duration]);
sendCommand(
socket, bulb, "set_bright", [brightnessPercent, "smooth", duration]);
}
}
}
function sendCommand(socket, bulb, method, params) {
const msg = {
id: bulb.id,
method,
params,
};
socket.write(JSON.stringify(msg) + "\r\n");
}
const easeOutQuad = (t) => t * (2 - t);
function getPixelsAmbience(pixels) {
let r = 0;
let g = 0;
let b = 0;
for (let pixel of pixels) {
r += pixel[0];
g += pixel[1];
b += pixel[2];
}
r /= pixels.length;
g /= pixels.length;
b /= pixels.length;
const brightnessBase = ((r + g + b) / (3 * 255));
const brightness = easeOutQuad(brightnessBase);
console.log('RGB:', [r, g, b]);
console.log('Brightness: ', brightness);
return { brightness, rgb: [r, g, b] };
}
function getScreenStrip({ width, height }) {
const img = robot.screen.capture(0, height / 3, width, 5);
const count = 100;
const result = [];
for (let i = 0; i < count; i++) {
const hex = img.colorAt(Math.floor(img.width * (i / count)), 0);
result.push([
parseInt(hex.slice(0, 2), 16),
parseInt(hex.slice(2, 4), 16),
parseInt(hex.slice(4, 6), 16),
]);
}
return result;
}
function guessIP() {
const external = R.pipe(
R.values,
R.unnest,
R.filter((iface) => 'IPv4' === iface.family && !iface.internal),
)(os.networkInterfaces());
if (!external.length) {
throw new Error("No interfaces found");
}
const ip = external[0].address;
console.log('Guessed host IP address', ip);
return ip;
}
run();
{
"name": "yeelight",
"version": "1.0.0",
"description": "",
"main": "main.js",
"dependencies": {
"desktop-screenshot": "^0.1.1",
"node-yeelight-wifi": "^0.1.2",
"ramda": "^0.25.0",
"robotjs": "^0.4.7",
"yeelight.js": "^1.0.1"
},
"devDependencies": {},
"author": "Marcin Biernat",
"license": "MIT"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment