-->
Page 1 of 19

RGB Controller for Apple HomeKit and Siri (NodeMCU-ESP8266)

PostPosted: Tue Oct 25, 2016 5:55 am
by eqsOne
Well, there is this great repository named Homebridge by Nick Farina available on GitHub. It turns a Raspberry i.e. into a HomeKit-Bridge and makes Siri switch any stuff that you can find a homebridge-plugin for.

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 Setup.jpg



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.

RGB-Controller v0.2.jpg

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
Code: Select all//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
Code: Select all{
   "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:
Code: Select all"service": "Light",

right under
Code: Select all"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:
Code: Select allssh pi@192.168.1.20


The default password is raspberry.

Once logged in, install Node.js like this:

Pi1 & Zero(W):
Code: Select allsudo 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:
Code: Select allsudo 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:
Code: Select allsudo npm install -g --unsafe-perm homebridge

sudo npm install -g homebridge-better-http-rgb



Create a config.json file:
Code: Select allsudo 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):
Code: Select allsudo 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/:
Code: Select allcp ~/.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:
Code: Select allYour-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:
Code: Select allYour-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:
Code: Select allsudo 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:
Code: Select allsudo 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:
Code: Select allsudo systemctl daemon-reload

sudo systemctl enable homebridge

sudo systemctl start homebridge

sudo reboot



Log in again and check if the service is running:
Code: Select allsudo systemctl status homebridge



Done, that's it.



To show the Homebridge journal:
Code: Select allsudo journalctl -f -u homebridge


Hit ctrl+c to stop journal

To run Homebridge in debug-mode:
Code: Select allsudo systemctl stop homebridge

DEBUG=* homebridge -D



Since you copied your config.json to /var/homebridge/, you can now edit it by typing:
Code: Select allsudo nano /var/homebridge/config.json


Re: RGB Controller for Apple HomeKit and Siri (NodeMCU-ESP82

PostPosted: Thu Oct 27, 2016 1:47 am
by thifi
Thanks for the article and your instructions, it works like a charm.

Many thanks for sharing.

Thifi

Re: RGB Controller for Apple HomeKit and Siri (NodeMCU-ESP82

PostPosted: Thu Oct 27, 2016 3:27 am
by eqsOne
You're welcome, great to hear!

Re: RGB Controller for Apple HomeKit and Siri (NodeMCU-ESP82

PostPosted: Thu Jan 05, 2017 6:59 am
by DaPeace
Thanks for the great tutorial. ive already build a controller to interact with the better-rgb-plugin but you showed me that the brightness is only calulated and send back to the plugin.. My first thought was, that the plugin waites for 0-100 at the brightness-url and a hex-color for the color.. ive stolen your conversion-code and hope it will work when i come home :D