MQTT IR Blaster for my OpenHab Setup (nodemcu+MQTT+openhab+IR)

A few months back I started to setup a dedicated home automation system to control my ever-growing number of “smart” devices.

Smart devices are great but they usually have separate interfaces and mobile programs to install and control each device. What is really needed is a single program to control all of my devices… from a single interface.

Well that in a nutshell is Openhab, a software suite developed specifically for controlling smart devices from a range of manufacturers and industries, utilizing many different communication protocols.

One of these communication protocols is MQTT. I wont go into the specifics of this protocol, only that it is widely used in industrial applications and has even been used for face-books messenger app.

Now the reason for designing an IR blaster that uses MQTT to trigger the IR LED’s is that I’m already using it to control several appliances in my apartment.

Specifically I’m using Nodemcu boards with Arduino compatible code to receive an MQTT command and do some action… i.e. turn on or off a relay

Except this time instead of turning on and off a relay I will use a separate Arduino library called IRsend.h to activate the IR leds through a digital pin on the nodemcu board.

Here is the Arduino code for the Nodemcu boards:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <IRsend.h>

IRsend irsend(14);  // An IR LED is controlled by GPIO pin 14 (D5) on nodemcu boards

// Update these with values suitable for your network.

//openhab MQQT settings
const char* ssid = "********";
const char* password = "********";
const char* mqtt_server = "xxx.xxx.xxx.xxx";
const char* brokerusername = "********";
const char* brokerpassword = "********";

IPAddress ip(192, 168, 0, 114); // where xx is the desired IP Address
IPAddress gateway(192, 168, 0, 1); // set gateway to match your network
IPAddress subnet(255, 255, 255, 0); // set subnet mask to match your network

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.config(ip, gateway, subnet);

  WiFi.mode(WIFI_STA);
 
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  
  String p_payload;
  
  for (int i = 0; i < length; i++) {

    p_payload.concat((char)payload[i]);
         
  }
    Serial.println(p_payload);
    
    // Convert from String HEX to Hex long
    long hexCmd;
    hexCmd = strtol(&p_payload[0], NULL, 16);
    irsend.sendNEC(hexCmd, 32);
       
    Serial.print("INT:");
    Serial.println(hexCmd);
      
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), brokerusername, brokerpassword)) {
      Serial.println("connected");
      client.subscribe("apartment/livingroom/ir_blaster/state");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  irsend.begin();
  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  
}

void loop() {
    
   ArduinoOTA.handle();

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  }

The code posted above is pretty simple, its using an MQTT communication library for receiving commands from Openhab. It subscribes to the “apartment/livingroom/ir_blaster/state” topic. Openhab publishes an IR code to this topic and the code here receives that command, and uses the IRsend library to pulse pin 14 (D5) on the nodemcu boards.

I decided on using 6 IR LED’s arranged in a semicircular pattern to entirely cover my living room. Each LED is 30 degrees from the next, with 6 LED’s its able to cover more than 180 degrees. I used a single PN222A transistor driven through pin 14, which switches the IR LED’s. There are three series pairs of IR leds in parallel running through the PN222A, with this configuration I do not require current limiting resistors.

Here is the circuit:

And then I designed and 3D printed this case:

Now all that’s left to do is send some IR codes to the device through the subscribed MQQT channel.

I recorded the IR codes from several of my favourite devices remotes and then set up some items and button in my Openhab UI.

UI currently looks like this:

It works perfectly!! Next I need to design some nice UI’s to allow control of my home entertainment system through a tablet.

If anyone wants a tutorial on how to record IR codes from remotes let me know.

Here is a shot of the IR codes being recorded:

16 X 16 Pixel RGB LED Artboard Part 3

This is the third post in the 16 X 16 Pixel RGB LED Artboard project, Part1 and Part2  links just in case you showed up late!

In this post I will discuss the building of a pine framed box to house the pixel array. It has a glass cover on the front for easy cleaning and finished look.

First part was cutting the frame pieces, used a miter box and hand saw to cut all four sides.

Frame of pine

Next I carved out a groove for the glass, the location of the grooves was marked onto the wood with a pencil, square and metal ruler.

Then I used a small 1/4″ wood chisel to slowly carve out the groove to a depth of approximately 1/4″ deep. The glass was cut 1/2″ (13mm) larger on both sides than the wood frame. So a groove about 3/16″ to 1/4″ holds the glass in place and hides the edge.

Laying out the grooves
Cutting the grooves
Fitting the glass

Ok so that went fairly quickly, it was a lot of fun carving the wood. I love the smell of fresh cut wood.

Once I was totally satisfied with the fit, wood glue was applied to each joint and painters tape used to hold the sides in tension with each other.

Holding the frame together while glue dries

The panel is held in place with offcuts from making the sides.

Completed frame with led array in place

Right away I tested it out!!

Very first full panel tests!!

And the first tests were successful!

This panel is power hunnngggry though!! The small bench power supply I used for this test immediately started to smell like burning electronics, so I shut it down… Need to find a 5V 4A power supply, 10A would be even better!

The pattern shown on the panel  is being fed via wifi to an ESP8266 mounted on the back of the panel. The ESP8266 is running an Artnet Node with two universes. I’m feeding the data from a windows PC running Jinx…. ive also tested it with GLEDiator as well and it works fine.

To be continued…. Programming, ESP8266, Artnet in the next post.

16 X 16 Pixel RGB LED Artboard Part 1

A few months back I saw some very interesting NeoPixel coffee table designs on YouTube. Right away I knew that I must get my hands on some of these amazing little lights and start to experiment.

Instead of going for a large coffee table design I decided on a smaller project, a 16 x 16 pixel NeoPixel Artboard that could display static images or animations. I was inspired by this video:

And thus the project began, first by purchasing some WS2812B addressable RGB LED’s from an online vendor. The parts showed up after waiting a couple weeks and I dove in right away!

In the past I’ve played around with classic thru hole RGB LED’s, but these were quite different. The nice part with these LED’s is that each pixel in a strip is individually addressable, meaning they can be controlled separately using a very simple one wire communication protocol. No extra shift registers are required which keeps this project compact and the wiring very simple, although tedious if you use the individual LED’s on pcb approach that I did here.

In the future I would definitely use and suggest using the pre-wired strips for a project like this.

My first experiment was wiring up a 10×10 array for testing. Here is a picture of the LED’s as they arrived at my doorstep.

Here’s how I wired it up for testing, except I did add a 100 Ohm current limiting resistor in series with the data line as it was suggested in the manufacturers documentation online.

 

Looking back I really should have ordered the prewired strips for this project. Oh well such is life, live and learn… Needless to say I wasn’t looking forward to soldering for at least a week after this. Wiring by hand, this took a few hours. I used solid 22awg copper wire for power, gnd and data.

This went smoothly and in no time I was up and running, I downloaded the acclaimed AdafruitNeoPixelLibrary and installed it in Arduino IDE. Then I wired up the panel to an Arduino Nano and suitable DC power supply (these things are power hungry so beware!).

Here I’m testing each row individually as they are wired.

And finally success, the whole panel works… But why is my small bench supply making funny smells. This thing is drawing easily 2A at 5V DC, depending on the color produced. White is the worst as it requires all three LED’s of each pixel to run at full brightness.

Continued in Part 2 – Designing and Building the Array…

Wifi Temperature Sensor (ESP8266 + DHT11 + MQTT)

So on cold tuesday night in late December I thought this would be a good evening project – take a nodemcu esp8266 development board from ebay, a dht11 temperature sensor and make a wifi temperture sensor that will publish MQTT messages to my local network.

Seems easy enough… Heres my code for the ESP board:

#include <PubSubClient.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <DHT11.h>


// Update these with values suitable for your network.

const char* ssid = "SSID";
const char* password = "PASSWORD";
const char* mqtt_server = "192.168.0.3";
const char* brokerusername = "openhabian";
const char* brokerpassword = "openhabian";

IPAddress ip(192, 168, 0, 112); // where xx is the desired IP Address
IPAddress gateway(192, 168, 0, 1); // set gateway to match your network
IPAddress subnet(255, 255, 255, 0); // set subnet mask to match your network

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

//dht11 stuff
const int pin=D0;
int err;
float temp, humi;
char Temperature[10];

DHT11 dht11(pin); 


void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.config(ip, gateway, subnet);

  WiFi.mode(WIFI_STA);
 
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '0') {
    
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is acive low on the ESP-01)
  } else { }

if ((char)payload[0] == '1') {
   
    digitalWrite(BUILTIN_LED, HIGH);   // Turn the LED on (Note that LOW is the voltage level
  }else{}
  

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), brokerusername, brokerpassword)) {
      Serial.println("connected");
      client.subscribe("apartment/livingroom/temp/state");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  
}

void loop() {
   ArduinoOTA.handle();

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

if((err=dht11.read(humi, temp))==0)
delay(DHT11_RETRY_DELAY); //delay for reread

dtostrf(temp,4,3,Temperature);

client.publish("apartment/livingroom/temp/state", Temperature);

delay(10000);

}

 

It works perfect! Currently its set to publish the measured temp to an MQTT topic (in my case apartment/livingroom/temp/state) every ten seconds. My openhab server listens for any MQTT messages and displays the temperature on a webpage.

I plan on using these little sensors to report the temps to my home automation system so it can adjust the heating or cooling automatically.

Finished sensor with 3d printed case, plugs into standard micro usb phone charger. Only needs power all data is sent over wifi, so no usb data connection is required.

3D object files for case here: https://www.thingiverse.com/thing:1128026