I implemented simple MQTT IR Transmitter/receiver with ESP. I used basic ESP01,
Here is code:
/*
* IRremoteESP8266: IRServer - MQTT IR server
* An IR LED must be connected to ESP8266 RX port (GPIO-3)
* An IR receiver to GPIO 0
* used library:
* https://github.com/markszabo/IRremoteESP8266
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <IRremoteESP8266.h>
#include <PubSubClient.h>
int RECV_PIN = 0; //an IR detector/demodulator is connected to GPIO pin 0
IRrecv irrecv(RECV_PIN);
const char* ssid = "MY-SSID";
const char* password = "MY-WIFI-PSK";
const char* topicRaportPrefix = "esp8266/02/info/";
const char* topicSubscribe = "esp8266/02/sender/#";
const char* topicPrefix = "esp8266/02/";
const char* mqtt_server = "10.10.10.10";
const char* mqtt_user = "mqtt_user";
const char* mqtt_pass = "mqtt_pass";
String clientName; // MQTT client name
char message_buff[100];
// Pin of IR sender
IRsend irsend(3); // rx port z RS232
WiFiClient wifiClient;
void callback(char* topic, byte* payload, unsigned int length);
void connect_to_MQTT();
PubSubClient client(mqtt_server, 1883, callback, wifiClient);
// -----------------------------------------------------------------
void callback(char* topic, byte* payload, unsigned int length) {
int i = 0;
Serial.println("Message arrived: topic: " + String(topic));
Serial.println("Length: " + String(length,DEC));
// create character buffer with ending null terminator (string)
for(i=0; i<length; i++) {
message_buff[i] = payload[i];
}
message_buff[i] = '\0';
unsigned int freq=38;
String msgString = String(message_buff);
String msgTopic = String(topic);
unsigned long msgInt = msgString.toInt();
Serial.println("Payload String: " + msgString);
// structure "esp8266/02/sender/type[/bits[/panasonic_address]]"
int endOfBits;
String irTypStr = "";
String irBitsStr = "";
int irBitsInt=-1;
String irPanasAddrStr = "";
int endOfTyp = msgTopic.indexOf("/",20);
if (endOfTyp == -1)
{
// One element - only irTyp
irTypStr = msgTopic.substring(18);
} else {
// irTyp exists and something more
irTypStr = msgTopic.substring(18, endOfTyp);
endOfBits = msgTopic.indexOf("/",endOfTyp+1);
if (endOfBits== -1)
{
// irBits is last
irBitsStr = msgTopic.substring(endOfTyp+1);
} else {
// irBits and something more
irBitsStr = msgTopic.substring(endOfTyp+1, endOfBits);
irPanasAddrStr = msgTopic.substring(endOfBits+1);
}
irBitsInt = irBitsStr.toInt();
}
Serial.println(irTypStr);
Serial.println(irBitsStr);
Serial.println(irPanasAddrStr);
if (irTypStr=="NEC")
Serial.print("Send NEC:");
Serial.println(msgInt);
irsend.sendNEC(msgInt, 36);
} else if (irTypStr=="RC5") {
Serial.print("Send RC5:");
Serial.print(msgInt);
Serial.print(" (");
Serial.print(irBitsInt);
Serial.println("-bits)");
irsend.sendRC5(msgInt, irBitsInt);
}
}
// -----------------------------------------------------------------
String macToStr(const uint8_t* mac)
{
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
if (i < 5)
result += ':';
}
return result;
}
// -----------------------------------------------------------------
void setup(void){
irsend.begin();
irrecv.enableIRIn(); // Start the receiver
Serial.begin(115200,SERIAL_8N1,SERIAL_TX_ONLY);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
clientName += "esp8266-";
uint8_t mac[6];
WiFi.macAddress(mac);
clientName += macToStr(mac);
clientName += "-";
clientName += String(micros() & 0xff, 16);
connect_to_MQTT();
}
// -----------------------------------------------------------------
void connect_to_MQTT() {
Serial.print("Connecting to ");
Serial.print(mqtt_server);
Serial.print(" as ");
Serial.println(clientName);
char myTopic[100];
int is_conn = 0;
while (is_conn == 0) {
if (client.connect((char*) clientName.c_str(), mqtt_user, mqtt_pass)) {
Serial.println("Connected to MQTT broker");
sprintf(myTopic, "%sclient", topicRaportPrefix);
client.publish((char*)myTopic, (char*) clientName.c_str());
IPAddress myIp = WiFi.localIP();
char myIpString[24];
sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
sprintf(myTopic, "%sip", topicRaportPrefix);
client.publish((char*)myTopic, (char*) myIpString);
sprintf(myTopic, "%stype", topicRaportPrefix);
client.publish((char*)myTopic,"IR server");
Serial.print("Topic is: ");
Serial.println(topicSubscribe);
if (client.subscribe(topicSubscribe)){
Serial.println("Successfully subscribed");
}
is_conn = 1;
}
else {
Serial.print("MQTT connect failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
// -----------------------------------------------------------------
// Encodig of data
void encoding (decode_results *results, char * result_encoding)
{
switch (results->decode_type) {
default:
case UNKNOWN: strncpy(result_encoding,"UNKNOWN\0",8); break ;
case NEC: strncpy(result_encoding,"NEC\0",4); break ;
case SONY: strncpy(result_encoding,"SONY\0",5); break ;
case RC5: strncpy(result_encoding,"RC5\0",4); break ;
case RC6: strncpy(result_encoding,"RC6\0",4); break ;
case DISH: strncpy(result_encoding,"DISH\0",5); break ;
case SHARP: strncpy(result_encoding,"SHARP\0",6); break ;
case JVC: strncpy(result_encoding,"JVC\0",4); break ;
case SANYO: strncpy(result_encoding,"SANYO\0",6); break ;
case MITSUBISHI: strncpy(result_encoding,"MITSUBISHI\0",11); break ;
case SAMSUNG: strncpy(result_encoding,"SAMSUNG\0",8); break ;
case LG: strncpy(result_encoding,"LG\0",3); break ;
case WHYNTER: strncpy(result_encoding,"WHYNTER\0",8); break ;
case AIWA_RC_T501: strncpy(result_encoding,"AIWA_RC_T501\0",13); break ;
case PANASONIC: strncpy(result_encoding,"PANASONIC\0",11); break ;
}
}
// -----------------------------------------------------------------
void loop(void){
client.loop();
if (! client.connected()) {
Serial.println("Not connected to MQTT....");
connect_to_MQTT();
}
decode_results results; // Somewhere to store the results
if (irrecv.decode(&results)) { // Grab an IR code
char myTopic[100];
char myTmp[50];
char myValue[500];
encoding (&results, myTmp);
if (results.decode_type == PANASONIC) { //Panasonic has address
// struktura "prefix/typ/bits[/panasonic_address]"
sprintf(myTopic, "%sreceiver/%s/%d/%d", topicPrefix, myTmp, results.bits, results.panasonicAddress );
} else {
sprintf(myTopic, "%sreceiver/%s/%d", topicPrefix, myTmp, results.bits );
}
if (results.decode_type != UNKNOWN) {
// any other has code and bits
sprintf(myValue, "%d", results.value);
client.publish((char*) myTopic, (char*) myValue );
}
irrecv.resume(); // Prepare for the next value
}
}
I don’t have schematic - it’s very simple.
- I have 8v power supply and DC-DC converter to 3,3V
- There are pullup resistors 3,3k (or 10k) conneted between +3,3V and RESET, CH_PD, GPIO15 and GPIO-0 (See improved stability schematic http://esp8266.github.io/Arduino/versions/2.0.0/doc/boards.html )
- Output PIN of TSOP IR receiver is connected to GPIO-0 pin (with pullup resistor).
- To avoid problems with GPIO-0/2 stability I’m using GPIO-3 (RX port) for output and TX-only mode of port. To this port is connected simple amplifier with NPN transistor (see diagram - http://www.mikrocontroller.net/topic/377947 ).
Code is not finished - I implemented universal IR->MQTT and MQTT->IR only for NEC and Phillips because I need only this codecs - but there is no problem to add next.
All transmited IR codes are visible via MQTT (topic esp8266/02/receiver/#). So I can check code and add items to OH:
Number ir_in_lg "IR LG/NEC command [%d]" <ir> (gIR) {mqtt="<[mosquitto:esp8266/02/receiver/NEC/32:state:default]"}
Switch ir_philips_on "Philips Power" <ir> (gIR) {mqtt=">[mosquitto:esp8266/02/sender/RC5/12:command:ON:56]"}
and add use such items in rules:
rule lgTVOnOff
when
Item ir_in_lg received update 551489775
then
if (LgTvStatus.state==OFF) // TV is off (from LG-TV binding)
{
sendCommand(tv_backlight,ON) // Turn on TV backlight
} else {
sendCommand(tv_backlight,OFF) // Turn off TV backlight
}
end
with:
sendCommand(ir_philips_on,ON)
I can send Philips power comand from rules.
I’m planning migration to Homie aware code with OTA support, but current version works fine for me so this task have now low prioritity
Because it is installed in my living room I had to find nice enclosure - I used enclosure from old IR extender.
https://shopdelta.eu/wireless-remote-control-extension-vt2-sig_l2_p2282.html
I removed radio part and used only existing power suplly.