Arduino universal remote
Date posted:
For my first home automation project I built an Arduino universal remote for my home theatre room. It's an IR transmitter (blaster) built into my ceiling for controlling the projector, amp/receiver, bluray player and anything else in the future that can receive IR signals.
Hardware:
- Arduino Compatible Infrared Transmitter
- 5mm Infrared Receiver (not pictured below)
- PoE EtherTen (100% Arduino Uno compatible with onboard Ethernet)
- NPN Transistor
Software:
The Ardunio uses the IRremote library to send the IR signal which it receives as a string sent over the network via MQTT protocol from my Raspberry Pi server running Node-RED with homekit nodes.
I use the NPN transister to act as a switch for the IR LED transmitter. The LED requires 5v to run at 100% which the normal Arduino digital pins don't provide, otherwise the LED wasn't bright enough to reach across the room.
I use another Ardunio with the IR receiver to "record" my various appliances' remote's signals. And save them within Node-RED.
The Ardunio code
#include <stdlib.h>
#include <IRremote.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <SPI.h>
// Ethernet https://www.miniwebtool.com/mac-address-generator/
byte device_mac[] = {0x64, 0x72, 0x59, 0xD3, 0x3F, 0xA3};
EthernetClient device;
// MQTT
IPAddress mqtt_server(XXX, XXX, XXX, XXX);
PubSubClient mqtt(device);
String mqtt_client = "cinemaremote";
const char mqtt_user[] = "XXXX";
const char mqtt_pass[] = "XXXX";
const char mqtt_sub[] = "device/cinema/remote";
// IR
IRsend ir_send;
String ir_type;
unsigned long ir_code;
void setup()
{
// Wait for network connection
while (Ethernet.begin(device_mac) == 0)
{
delay(1000);
}
// Initializes the pseudo-random number generator
randomSeed(micros());
// Configure MQTT
mqtt.setServer(mqtt_ip, 1883);
mqtt.setCallback(mqttReceive);
}
void loop()
{
// Keep network connection
Ethernet.maintain();
// Reconnect to MQTT server
if (!mqtt.connected())
{
mqttReconnect();
}
// MQTT process
mqtt.loop();
}
/**
* Reconnects MQTT service
*
* @return void Loops unit connected
*/
void mqttReconnect()
{
while (!mqtt.connected())
{
if (mqtt.connect(String(mqtt_client + String(random(0xffff), HEX)).c_str(), mqtt_user, mqtt_pass))
{
mqtt.subscribe(mqtt_sub);
}
else
{
delay(5000);
}
}
}
/**
* MQTT callback function when msg received
*
* @param char* topic Incoming topic
* @param byte* payload The message
* @param int leng Length of message
* @return void
*/
void mqttReceive(char* topic, byte* payload, unsigned int leng)
{
// Determine first 3 chars of payload for IR type
char type[3] = "";
for (int i = 0; i < 3; i++)
{
type[i] = payload[i];
}
// Determine rest of payload for IR code
char code[leng-3] = "";
for (int i = 3; i < leng; i++)
{
code[i-3] = payload[i];
}
// Set type to string, code to long-int
ir_type = String(type).substring(0, 3);
ir_code = strtol(code, NULL, 0);
// Send correct IR code
if (ir_type == "NEC")
{
ir_send.sendNEC(ir_code, 32);
return;
}
else if (ir_type == "SAM")
{
ir_send.sendSAMSUNG(ir_code, 32);
return;
}
else if (ir_type == "PAN")
{
ir_send.sendPanasonic(ir_code, 32);
return;
}
else if (ir_type == "JVC")
{
ir_send.sendJVC(ir_code, 32, false);
return;
}
else if (ir_type == "LG ")
{
ir_send.sendLG(ir_code, 32);
return;
}
else if (ir_type == "SON")
{
ir_send.sendSony(ir_code, 32);
return;
}
else if (ir_type == "RC5")
{
ir_send.sendRC5(ir_code, 32);
return;
}
}
Node-RED
Node-RED's HomeKit plugin nodes simulate HomeKit compatible devices/accessories. These are presented as actionable devices within the iOS Home app. But can also accept input from other Node-RED nodes.
My projector requires the off-button on the original remote to be pressed twice (to confirm action). So I route the "off" action's output from Node-RED twice with a 1 second delay between them.
Writing all the logic in Node-RED allows you to change the rules on the fly without having to re-compile the Ardunio or restart the Pi / homekit.
The MQTT message string sent with the IR encoding in the first 3 characters and the HEX code in the remainder of the message:
NEC0x4CB340BF
What's next?
I plan to 3D-print housing for Ardunio compatible motion/PIR sensors for each room to toggle on/off the downlights. In the home theatre room I'll combine the motion sensor and IR LED in the one housing. For now the Ardunio sits in the ceiling within a box and a face-plate with a hole for the IR LED, pretty discrete looking.