Home Automation blog

Skip to Content

Arduino universal remote

Article image for Arduino universal remote

Posted by Chris

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.

Built using:

Arduino universal remote diagramHow it works:

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. Store them within Node-RED.

The 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_ip(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 Remote
IRsend ir_send;
String ir_type;
unsigned long ir_code;


void setup()
{
	if (Ethernet.begin(device_mac) == 0)
	{
		while (true)
		{
		}
	}
	
	randomSeed(micros());

	mqtt.setServer(mqtt_ip, 1883);
	mqtt.setCallback(callBack);
}



void loop()
{
	Ethernet.maintain();

	if (!mqtt.connected())
	{
		reconnect();
	}

	mqtt.loop();
}



void reconnect()
{
	while (!mqtt.connected())
	{
		mqtt_client += String(random(0xffff), HEX);
		
		if (mqtt.connect(mqtt_client.c_str(), mqtt_user, mqtt_pass))
		{
			mqtt.subscribe(mqtt_sub);
		}
		else
		{
			delay(5000);
		}
	}
}



void callBack(char* topic, byte* payload, unsigned int leng)
{
	char type[3] = "";
	for (int i = 0; i < 3; i++)
	{
		type[i] = payload[i];
	}
	
	char code[leng-3] = "";
	for (int i = 3; i < leng; i++)
	{
		code[i-3] = payload[i];
	}

	ir_type = String(type).substring(0, 3);
	ir_code = strtol(code, NULL, 0);

	if (ir_type == "NEC")
	{
		ir_send.sendNEC(ir_code, 32);
	}
	else if (ir_type == "SAM")
	{
		ir_send.sendSAMSUNG(ir_code, 32);
	}
	else if (ir_type == "PAN")
	{
		ir_send.sendPanasonic(ir_code, 32);
	}
	else if (ir_type == "JVC")
	{
		ir_send.sendJVC(ir_code, 32, false);
	}
	else if (ir_type == "LG ")
	{
		ir_send.sendLG(ir_code, 32);
	}
	else if (ir_type == "SON")
	{
		ir_send.sendSony(ir_code, 32);
	}
	else if (ir_type == "RC5")
	{
		ir_send.sendRC5(ir_code, 32);
	}
}

 

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.