ESPHome, Using MQTT values with remote transmitter

Hi All,

I want to build an MQTT to Infrared gateway using ESPHome. I understand that remote.transmitter.raw can accept a templated value for code, provided it’s iterable. A lambda returning the x variable throws a bunch of errors on build, I’m guessing because it’s not iterable.

Had anyone else got something like this working? my C++ is non-existant, but I’m guessing I need to slice up x and return an array.

-Cheers, Max.

Here’s how far I’ve got. I think I’m close, just need a type conversion

mqtt:
  broker: mqtt.example.com
  discovery: True
  on_json_message:
    - topic: $devicename/ir/send
      then:
        - remote_transmitter.transmit_raw:
            carrier_frequency: 38kHz
            code: !lambda |-
              std::string str = x["raw"];
              std::vector<std::string> v;
              char * token;
              char seps[] = ",";
              token = strtok (&str[0],seps);
              while (token != NULL)
              {
                v.push_back(token);
                token = strtok (NULL, seps);
              }
              return v;

gives the following error as v is the wrong type

src/main.cpp: In lambda function:
src/main.cpp:224:14: error: could not convert 'v' from 'std::vector<std::basic_string<char> >' to 'std::vector<int>'
       return v;
              ^
src/main.cpp:225:3: warning: control reaches end of non-void function [-Wreturn-type]
   });
   ^

k, resolved the type error and it compiles. will test later…

code: !lambda |-
     std::string str = x["raw"];
     std::vector<int> v;
     char * token;
     char seps[] = ",";
     token = strtok (&str[0],seps);
     while (token != NULL)
     {
       v.push_back( atoi(token) );
       token = strtok (NULL, seps);
     }
     return v;

k, got it. so just for the record, and to avoid this:

wisdom_of_the_ancients

mqtt:
  broker: mqtt.example.com
  discovery: True
  on_message:
    topic: $devicename/ir/send
    then:
    - remote_transmitter.transmit_raw:
        carrier_frequency: 38kHz
        code: !lambda |-
          std::string str = x;
          std::vector<int> v;
          char * token;
          char seps[] = ",";
          token = strtok (&str[0],seps);
          while (token != NULL)
          {
            v.push_back( atoi(token) );
            token = strtok (NULL, seps);
          }
          return v;

I now have the receiver working too…

remote_receiver:
  pin:
    number: 4
    inverted: True
  dump: all
  on_raw:
    then:
    - mqtt.publish:
        topic: $devicename/ir/receive
        payload: !lambda |-
          std::vector<int> rxv = x;
          std::string rxstr;
          for (size_t i = 0; i < rxv.size(); i++) {
            rxstr.append(to_string(rxv[i]));
            if (i < (rxv.size()-1)) {
              rxstr.append(",");
            }
          }
          return rxstr;
1 Like

@maxlock, thanks for the examples! i got my IR remote working with these scripts!

actually… it does not :frowning:

The receiver works perfectly, i can see the RAW transmission in MQTT.
via node-red i’ve routed them to $devicename/ir/send and the debug log of the remote transmitter shows that it’s doing something on_message but not sending the RAW transmission that i can see in MQTT…

am i missing something @maxlock?

Hi @ArjanC

Hmm, ok assuming you’ve copied the code correctly and there are no newlines or spaces hiding in there, I’d try sending a code that you’ve received without using HA. Send the code exactly as you’ve received it. I use the mosquitto_sub & mosquitto_pub commands to do this. Also check your hardware, point a mobile phone camera at the IR emitter to see if it’s flashing. You need to use the ‘selfie’ camera as it won’t have an IR filter.

-Max.

Here’s my full config fyi…

substitutions:
  devicename: irblaster

esphome:
  name: $devicename
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: xxxxx
  password: xxxxx
  use_address: xxxxx

mqtt:
  broker: mqtt
  discovery: True
  on_message:
    topic: $devicename/ir/send
    then:
    - remote_transmitter.transmit_raw:
        carrier_frequency: 38kHz
        code: !lambda |-
          std::string txstr = x;
          std::vector<int> txv;
          char * token;
          char seps[] = ",";
          token = strtok (&txstr[0],seps);
          while (token != NULL)
          {
            txv.push_back( atoi(token) );
            token = strtok (NULL, seps);
          }
          return txv;

web_server:
  port: 80

logger:
  level: INFO

ota:
  safe_mode: True

sensor:
  - platform: wifi_signal
    name: "signal"
    update_interval: 900s

status_led:
  pin:
    number: 12
    inverted: True

remote_transmitter:
  pin: 14
  carrier_duty_percent: 50%

remote_receiver:
  pin:
    number: 5
    inverted: true
  dump: all
  on_raw:
    then:
    - mqtt.publish:
        topic: $devicename/ir/receive
        payload: !lambda |-
          std::vector<int> rxv = x;
          std::string rxstr;
          for (size_t i = 0; i < rxv.size(); i++) {
            rxstr.append(to_string(rxv[i]));
            if (i < (rxv.size()-1)) {
              rxstr.append(",");
            }
          }
          return rxstr;

1 Like

Hello, I managed to get your code working witch is great thank you, but I want to receive the data form nec not raw, iv tried just replacing the “on_raw” with “on_nec”
but just gives an error on compileing.

Any pointers to help Thanks James

Hey there.
I love it when people ask for a question, don’t receive a reply but manage to find one/figure it out themselves and then update the thread with the answer. Internet needs more people like you! :clap:

Thank you for this, i was looking to do the same and found your solution, works like a charm :slight_smile:

Good afternoon, could you share your code that works with the NEC protocol

Hi I would like to have two esphome with IR transmitter and receiver to centralize iptv box and satellite receiver in one place and to be able to control using IR receiver on each TV box. Do you know if this use case works with 2 esphome (how is the delay between IR receiving → mqtt → mqtt receiver → IR transmitting?
Thanks

Thanks OP for sharing what you came up with, it was helpful as a starting point for what I was trying to do. Here’s what I came up with for sending arbitrary Pioneer-encoded messages:

mqtt:
  broker: ...
  on_message:
    topic: ir-controller/ir/send
    then:
    - remote_transmitter.transmit_pioneer:
        rc_code_1: !lambda |-
          return strtoul(x.c_str(), NULL, 16);

This expects a hex-formatted payload in the MQTT message. It should be pretty easy to convert this to the other remote formats that have a single configuration variable, just change “transmit_pioneer” to the appropriate format (such as “transmit_jvc”), and replace “rc_code_1” with the proper configuration variable (“data” for transmit_jvc).

For formats that require multiple configuration variables (like NEC with “address” and “command”) you could hardcode one of the values and use the lambda for the dynamic one. If you need to be able to control both you’d need to come up with a way of delimiting the different values and pulling each one out separately in multiple lambdas.