Thought it would be nice to switch my good old no name TV-wall strip just like a fancy Philips Hue LightStrip with Siri, so here’s a solution.
A quick overview of the realated parts needed to make it work:
RGB Controller - Hardware
A quite simple transistor circuit with voltage drop for the NodeMCU. Not much left to explain except this layout requires a common anode RGB strip. A single TIP122 can drive 5A, which should leave more than enough headroom to power an average 5m LED strip. EDIT: Rather use IRLZ44N MOSFETs instead, as suggested by btidey.
Make sure to use proper wire diameters and a 12V power supply which can provide the total current draw of the attached RGB strip.
To add some fine adjusting, you might use trimmer potentiometers instead of resistors as well.
NOTE: Use pin-headers to mount the NodeMCU and keep it disconnected from the controller circuit while flashing via USB!
RGB Controller - Sketch
The sketch runs a webserver on the NodeMCU that makes the strip switch to the requested color, on/off state and brightness value. Once set, it returns the current values back to HomeKit on http requests.
Basically it’s an Arduino-type counterpart for the Homebridge better-http-rgb plugin by Justin Novack.
A Homebridge configuration example [config.json] that matches the sketch is added below.
I set up the strip using Apples Home App in iOS10 (currently iOS11). Once Homebridge is added as bridge, you can ask Siri to switch your RGB strip on and off, or to set it to a certain color or brightness level (0-100%).
Shared, stability improving user tweaks from along the thread has been added. Works great but feel free to further improve:
NodeMCU Sketch (Ardino IDE)
Tweaks:
-Matched to the NodeMCU's 10bit pwm output as suggested by J6r06n
-Pin modes declared as suggested by daniel_asilva
-Clear remaining buffer to prevent ECONNRESET with homebridge 2.0, suggested by Raptoaaah
-redeclared 'x' as float
-redeclared 'x' as int with max() declaration as intended by Willem S
-Sketch last revised: 23-Oct-2018
-Same sketch with a nonblocking colorfade added here
//NodeMCU RGB-Controller for Homebridge & HomeKit (Siri)
#include <ESP8266WiFi.h>
#define redPin 13 //D7 - Red channel
#define grnPin 12 //D6 - Green channel
#define bluPin 14 //D5 - Blue channel
#define max(a,b) ((a)>(b)?(a):(b)) //added to make max() work with different data types (int | float)
WiFiServer server(80); //Set server port
String readString; //String to hold incoming request
String hexString = "000000"; //Define inititial color here (hex value), 080100 would be a calm warmtone i.e.
int state;
int r, g, b, x, V;
float R, G, B;
///// WiFi SETTINGS - Replace with your values /////////////////
const char* ssid = "YOUR_ROUTER_SSID";
const char* password = "YOUR_ROUTER_PASSWORD";
IPAddress ip(192, 168, 1, 10); // set a fixed IP for the NodeMCU
IPAddress gateway(192, 168, 1, 1); // Your router IP
IPAddress subnet(255, 255, 255, 0); // Subnet mask
////////////////////////////////////////////////////////////////////
void WiFiStart() {
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
WiFi.config(ip, gateway, subnet); //Set a fixed IP. You can comment this out and set it in your router instead.
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print("_");
}
Serial.println();
Serial.println("Done");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("");
server.begin();
}
void allOff() {
state = 0;
analogWrite(redPin, 0);
analogWrite(grnPin, 0);
analogWrite(bluPin, 0);
}
//Write requested hex-color to the pins (10bit pwm)
void setHex() {
state = 1;
long number = (long) strtol( &hexString[0], NULL, 16);
r = number >> 16;
g = number >> 8 & 0xFF;
b = number & 0xFF;
r = map(r, 0, 255, 0, 1023); //added for 10bit pwm
g = map(g, 0, 255, 0, 1023); //added for 10bit pwm
b = map(b, 0, 255, 0, 1023); //added for 10bit pwm
analogWrite(redPin, (r));
analogWrite(grnPin, (g));
analogWrite(bluPin, (b));
}
//Compute current brightness value
void getV() {
R = roundf(r / 10.23); //for 10bit pwm, was (r/2.55);
G = roundf(g / 10.23); //for 10bit pwm, was (g/2.55);
B = roundf(b / 10.23); //for 10bit pwm, was (b/2.55);
x = max(R, G);
V = max(x, B);
}
//For serial debugging only
void showValues() {
Serial.print("Status on/off: ");
Serial.println(state);
Serial.print("RGB color: ");
Serial.print(r);
Serial.print(".");
Serial.print(g);
Serial.print(".");
Serial.println(b);
Serial.print("Hex color: ");
Serial.println(hexString);
getV();
Serial.print("Brightness: ");
Serial.println(V);
Serial.println("");
}
void setup() {
Serial.begin(9600);
delay(1);
pinMode(redPin, OUTPUT); //declaration added
pinMode(grnPin, OUTPUT); //declaration added
pinMode(bluPin, OUTPUT); //declaration added
setHex(); //Set initial color after booting. Value defined above
WiFi.mode(WIFI_STA);
WiFiStart();
//showValues(); //Uncomment for serial output
}
void loop() {
WiFiClient client = server.available();
if (!client) {
return;
}
while (client.connected() && !client.available()) {
delay(1);
}
//Respond on certain Homebridge HTTP requests
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (readString.length() < 100) {
readString += c;
}
if (c == '\n') {
//Serial.print("Request: "); //Uncomment for serial output
//Serial.println(readString); //Uncomment for serial output
//Send reponse:
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
//On:
if (readString.indexOf("on") > 0) {
setHex();
//showValues();
}
//Off:
if (readString.indexOf("off") > 0) {
allOff();
//showValues();
}
//Set color:
if (readString.indexOf("set") > 0) {
hexString = "";
hexString = (readString.substring(9, 15));
setHex();
//showValues();
}
//Status on/off:
if (readString.indexOf("status") > 0) {
client.println(state);
}
//Status color (hex):
if (readString.indexOf("color") > 0) {
client.println(hexString);
}
//Status brightness (%):
if (readString.indexOf("bright") > 0) {
getV();
client.println(V);
}
delay(1);
while (client.read() >= 0); //added: clear remaining buffer to prevent ECONNRESET
client.stop();
readString.remove(0);
}
}
}
}
}
Matching config.json example
{
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"port": 51826,
"pin": "031-45-154"
},
"description": "Example configuration file for NodeMCU-RGB-Controller and better-http-rgb plugin",
"accessories": [{
"accessory": "HTTP-RGB",
"name": "RGB Strip",
"switch": {
"status": "http://192.168.1.10:80/status",
"powerOn": "http://192.168.1.10:80/on",
"powerOff": "http://192.168.1.10:80/off"
},
"color": {
"status": "http://192.168.1.10:80/color",
"url": "http://192.168.1.10:80/set/%s"
},
"brightness": {
"status": "http://192.168.1.10:80/bright",
"url": "http://192.168.1.10:80/set/%s"
}
}],
"platforms": []
}
In your config.json edit the IP and port values (192.168.1.10:80) to those of your NodeMCU.
You can rename your device from "RGB Strip" to whatever you like. It will be used for Siri and labeling in Home App.
You might also edit homebridges default "username" and "pin" values within their given patterns.
Your final .json file can be checked for proper formatting here.
As suggested by philipp1887 you also might have to insert:
"service": "Light",
right under
"name": "RGB Strip",
In his case Homekit showed the strip as "Not supported" without that line.
Homebridge on Raspberry
I’m not going to explain how to set up a Raspberry from scratch, there are tons of howto’s on the web regarding this topic. If you’re familiar with Raspberry, the Homebridge setup will take about 15 minutes.
So, I installed Raspbian Jessie Lite (Edit: currently Stretch Lite on a Zero W) and went through the setup, enabled wifi & ssh to make it accessable with Terminal on a Mac. Putty will do ssh for win as far as I know.
To log in with Terminal via ssh, get the ip address of your pi (example:192.168.1.20) and type:
ssh pi@192.168.1.20
The default password is raspberry.
Once logged in, install Node.js like this:
Pi1 & Zero(W):
sudo apt-get update && sudo apt-get upgrade
wget https://nodejs.org/dist/v8.5.0/node-v8.5.0-linux-armv6l.tar.gz
tar -xvf node-v8.5.0-linux-armv6l.tar.gz
cd node-v8.5.0-linux-armv6l
sudo cp -R * /usr/local/
cd
rm node-v8.5.0-linux-armv6l.tar.gz
rm -R node-v8.5.0-linux-armv6l/
sudo apt-get install libavahi-compat-libdnssd-dev
sudo apt-get install git
Pi2 & 3:
sudo apt-get update && sudo apt-get upgrade
wget https://nodejs.org/dist/v8.5.0/node-v8.5.0-linux-armv7l.tar.gz
tar -xvf node-v8.5.0-linux-armv7l.tar.gz
cd node-v8.5.0-linux-armv7l
sudo cp -R * /usr/local/
cd
rm node-v8.5.0-linux-armv7l.tar.gz
rm -R node-v8.5.0-linux-armv7l/
sudo apt-get install libavahi-compat-libdnssd-dev
sudo apt-get install git
Now install Homebridge and the better-http-rgb plugin:
sudo npm install -g --unsafe-perm homebridge
sudo npm install -g homebridge-better-http-rgb
Create a config.json file:
sudo nano ~/.homebridge/config.json
Paste the content from the example config.json above and make sure to replace the IP and port values with these of your NodeMCU. Then hit ctrl+o to save and ctrl+x to close.
Make Homebridge start automatically on boot (Systemd Service):
sudo useradd --system homebridge_user
sudo mkdir /var/homebridge
sudo groupadd homebridge_group
sudo usermod -a -G homebridge_group homebridge_user
sudo usermod -a -G homebridge_group pi
sudo chown -R :homebridge_group /var/homebridge
sudo chmod -R g+rwX /var/homebridge
sudo chmod g+s /var/homebridge
exit
Log in again and copy the config.json to /var/homebridge/:
cp ~/.homebridge/config.json /var/homebridge/
exit
Download and unzip the homebridge and homebridge.service files from here, then copy them to your Raspberry’s ~/.homebridge directory.
On Windows you might use an sftp client, on a Mac you can use Terminal (logged out from Pi). The scp command should look something like this:
Your-Mac-Name:~ username$ scp /Users/username/Downloads/DownloadFolderName/homebridge pi@192.168.1.20:~/.homebridge
Add your Raspberrys IP and the correct path to the file on your Mac. If you’re struggling with the correct path you can simply drag n drop the file from Finder into Terminal after typing scp, then add the target directory.
Repeat the step above with the homebridge.service file like this:
Your-Mac-Name:~ username$ scp /Users/username/Downloads/DownloadFolderName/homebridge.service pi@192.168.1.20:~/.homebridge.service
Log in again and move both files like this:
sudo mv ~/.homebridge/homebridge /etc/default/homebridge
sudo mv ~/.homebridge/homebridge.service /etc/systemd/system/homebridge.service
Now edit the 'User' entry in homebridge.service by typing:
sudo nano /etc/systemd/system/homebridge.service
Change line 7 from User=homebridge to User=homebridge_user
Hit ctrl+o to save and ctrl+x to close.
Make Homebridge run as service and reboot:
sudo systemctl daemon-reload
sudo systemctl enable homebridge
sudo systemctl start homebridge
sudo reboot
Log in again and check if the service is running:
sudo systemctl status homebridge
Done, that's it.
To show the Homebridge journal:
sudo journalctl -f -u homebridge
Hit ctrl+c to stop journal
To run Homebridge in debug-mode:
sudo systemctl stop homebridge
DEBUG=* homebridge -D
Since you copied your config.json to /var/homebridge/, you can now edit it by typing:
sudo nano /var/homebridge/config.json