Introduction: Pause Chromcast With a Remote Control

I have a Logitech harmony remote and run Home assistant on a raspberry pi.

I wanted to be able to pause chromecast from my remote, but i have an old tv that dont support this through hdmi. My Idea was then to use a NodeMcu to catch the ir signal and pause.

If you cant get it to work or have questions please comment below

Step 1: Equiptment

Equipment needed:

Nodemcu (

Ir reciver (like ex this:

dupont wires

Micro usb cable (power nodemcu)

I use Logitech Harmony -hub

For my approach You Need a Raspberry pi with Installed and Nodered.
I wont go into setting up homeassistant stuff here. If you use something other than homeassistant you need to adapt stuff yourself.

You need to be able to use Nodemcu on Arduino IDE as i wont go into that here

Step 2: Remote Signal

The way i did it was to copy a signal from a remote i dont use into harmony remote.

I used a remote for panasonic tv model TXL32C3E as that dont interfere with my equipment on my first floor. Thats a tv i have upstairs.

If you dont use harmony you can skip this.

So for finding the signal i used this scetch:

<p>/*<br> * IRremoteESP8266: IRrecvDumpV2 - dump details of IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Copyright 2009 Ken Shirriff, <a href="" rel="nofollow">
 * Copyright 2017 David Conran
 * Example circuit diagram:
 *  <a href="" rel="nofollow">
 * Changes:
 *   Version 0.3 November, 2017
 *     - Support for A/C decoding for some protcols.
 *   Version 0.2 April, 2017
 *     - Decode from a copy of the data so we can start capturing faster thus
 *       reduce the likelihood of miscaptures.
 * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009,
 */</p><p>#ifndef UNIT_TEST
#endif  // DECODE_AC</p><p>// ==================== start of TUNEABLE PARAMETERS ====================
// An IR detector/demodulator is connected to GPIO pin 14
// e.g. D5 on a NodeMCU board.
#define RECV_PIN 14</p><p>// The Serial connection baud rate.
// i.e. Status message will be sent to the PC at this baud rate.
// Try to avoid slow speeds like 9600, as you will miss messages and
// cause other problems. 115200 (or faster) is recommended.
// NOTE: Make sure you set your Serial Monitor to the same speed.
#define BAUD_RATE 115200</p><p>// As this program is a special purpose capture/decoder, let us use a larger
// than normal buffer so we can handle Air Conditioner remote codes.
#define CAPTURE_BUFFER_SIZE 1024</p><p>// TIMEOUT is the Nr. of milli-Seconds of no-more-data before we consider a
// message ended.
// This parameter is an interesting trade-off. The longer the timeout, the more
// complex a message it can capture. e.g. Some device protocols will send
// multiple message packets in quick succession, like Air Conditioner remotes.
// Air Coniditioner protocols often have a considerable gap (20-40+ms) between
// packets.
// The downside of a large timeout value is a lot of less complex protocols
// send multiple messages when the remote's button is held down. The gap between
// them is often also around 20+ms. This can result in the raw data be 2-3+
// times larger than needed as it has captured 2-3+ messages in a single
// capture. Setting a low timeout value can resolve this.
// So, choosing the best TIMEOUT value for your use particular case is
// quite nuanced. Good luck and happy hunting.
// NOTE: Don't exceed MAX_TIMEOUT_MS. Typically 130ms.
#define TIMEOUT 50U  // Some A/C units have gaps in their protocols of ~40ms.
                     // e.g. Kelvinator
                     // A value this large may swallow repeats of some protocols
#else  // DECODE_AC
#define TIMEOUT 15U  // Suits most messages, while not swallowing many repeats.
#endif  // DECODE_AC
// Alternatives:
// #define TIMEOUT 90U  // Suits messages with big gaps like XMP-1 & some aircon
                        // units, but can accidentally swallow repeated messages
                        // in the rawData[] output.
// #define TIMEOUT MAX_TIMEOUT_MS  // This will set it to our currently allowed
                                   // maximum. Values this high are problematic
                                   // because it is roughly the typical boundary
                                   // where most messages repeat.
                                   // e.g. It will stop decoding a message and
                                   //   start sending it to serial at precisely
                                   //   the time when the next message is likely
                                   //   to be transmitted, and may miss it.</p><p>// Set the smallest sized "UNKNOWN" message packets we actually care about.
// This value helps reduce the false-positive detection rate of IR background
// noise as real messages. The chances of background IR noise getting detected
// as a message increases with the length of the TIMEOUT value. (See above)
// The downside of setting this message too large is you can miss some valid
// short messages for protocols that this library doesn't yet decode.
// Set higher if you get lots of random short UNKNOWN messages when nothing
// should be sending a message.
// Set lower if you are sure your setup is working, but it doesn't see messages
// from your device. (e.g. Other IR remotes work.)
// NOTE: Set this value very high to effectively turn off UNKNOWN detection.
// ==================== end of TUNEABLE PARAMETERS ====================</p><p>// Use turn on the save buffer feature for more complete capture coverage.
IRrecv irrecv(RECV_PIN, CAPTURE_BUFFER_SIZE, TIMEOUT, true);</p><p>decode_results results;  // Somewhere to store the results</p><p>// Display the human readable state of an A/C message if we can.
void dumpACInfo(decode_results *results) {
  String description = "";
  if (results->decode_type == DAIKIN) {
    IRDaikinESP ac(0);
    description = ac.toString();
#endif  // DECODE_DAIKIN
  if (results->decode_type == FUJITSU_AC) {
    IRFujitsuAC ac(0);
    ac.setRaw(results->state, results->bits / 8);
    description = ac.toString();
  if (results->decode_type == KELVINATOR) {
    IRKelvinatorAC ac(0);
    description = ac.toString();
  if (results->decode_type == TOSHIBA_AC) {
    IRToshibaAC ac(0);
    description = ac.toString();
  if (results->decode_type == MIDEA) {
    IRMideaAC ac(0);
    ac.setRaw(results->value);  // Midea uses value instead of state.
    description = ac.toString();
#endif  // DECODE_MIDEA
  // If we got a human-readable description of the message, display it.
  if (description != "")  Serial.println("Mesg Desc.: " + description);
}</p><p>// The section of code run only once at start-up.
void setup() {
  delay(500);  // Wait a bit for the serial connection to be establised.</p><p>#if DECODE_HASH
  // Ignore messages with less than minimum on or off pulses.
#endif  // DECODE_HASH
  irrecv.enableIRIn();  // Start the receiver
}</p><p>// The repeating section of the code
void loop() {
  // Check if the IR code has been received.
  if (irrecv.decode(&results)) {
    // Display a crude timestamp.
    uint32_t now = millis();
    Serial.printf("Timestamp : %06u.%03u\n", now / 1000, now % 1000);
    if (results.overflow)
      Serial.printf("WARNING: IR code is too big for buffer (>= %d). "
                    "This result shouldn't be trusted until this is resolved. "
                    "Edit & increase CAPTURE_BUFFER_SIZE.\n",
    // Display the basic output of what we found.
    dumpACInfo(&results);  // Display any extra A/C info if we have it.
    yield();  // Feed the WDT as the text output can take a while to print.</p><p>    // Display the library version the message was captured with.
    Serial.print("Library   : v");
    Serial.println();</p><p>    // Output RAW timing info of the result.
    yield();  // Feed the WDT (again)</p><p>    // Output the results as source code
    Serial.println("");  // Blank line between entries
    yield();  // Feed the WDT (again)

When this scetch is uploaded and running with serial monitor open it will output the code for button press (see picture)

Write down the codes you want to use for later use. I used excel to note down what i got for buttons i wanted to use (see picture)

I Edited the buttons in my Netflix activity to Send pause signal from panasonic remote .. (see picture)

Step 3: Writing the Code for Sending to Nodered

<p>#ifndef UNIT_TEST<br>#include  <Arduino.h>
#include <IRremoteESP8266.h></p><p>#include <IRrecv.h></p><p>#include <IRutils.h></p><p>#include <ESP8266WiFi.h></p><p>#include <ESP8266WiFiMulti.h></p><p>#include <ESP8266HTTPClient.h></p><p>
</p><p>const char* ssid = "";    // Enter SSID here<br>const char* password = "";  //Enter Password here
const char *host = "";   //Ip addresse
#define USE_SERIAL Serial
ESP8266WiFiMulti WiFiMulti;
uint16_t RECV_PIN = 14;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
  irrecv.enableIRIn();  // Start the receiver
   // USE_SERIAL.setDebugOutput(true);
    USE_SERIAL.println();</p><p>    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
    WiFiMulti.addAP(ssid, password);
void loop() {
  if (irrecv.decode(&results)) {</p><p>   // Change this signal value for the one you got 
    if (results.value == 0x40040D00606D){
          USE_SERIAL.println("pause Signal recieved");
          wifisend(pause);<br>          delay(1000);</p><p>    } if (results.value == 0x400401007273){</p><p>          USE_SERIAL.println("previous");
    if (results.value == 0x40040100F2F3){
    irrecv.resume();  // Receive the next value
void wifisend(String data){
  if(( == WL_CONNECTED)) {
        HTTPClient http;
        USE_SERIAL.print("[HTTP] begin...\n");
        // configure traged server and url
        http.begin("http://[user]:[pass]@[ip]:[port]/chromecastpause?data=" + data);
        USE_SERIAL.print("[HTTP] GET...\n");
        // start connection and send HTTP header
        int httpCode = http.GET();
        // httpCode will be negative on error
        if(httpCode > 0) {
            // HTTP header has been send and Server response header has been handled
            USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);</p><p></p><p>            // file found at server
            if(httpCode == HTTP_CODE_OK) {
                String payload = http.getString();
        } else {
            USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());

This is the code i used on my nodemcu. You'll need to have those libraries installed.

You can test using serial monitor and press remote buttons you added in code to see the response..

In the line:

http.begin("http://[user]:[pass]@[ip]:[port]/chromecastpause?data=" + data);

You need to change [user] to your user and so on. WITHOUT brackets. brackets are there to show witch fields to change.

That line will also not work until we setup our flow in nodered.

Step 4: Creating a Flow in Nodered

As mentioned in the beginning i use with nodered. If you run a different setup you will need to make this different! You can see in the image that when a button is pressed it shows in the debug window...

The change payload node could probably have been skipped if i had chosen something different that data= in the previous step. The switch node i use is a lot bigger thn just pause but thats just so i could add more ir signals to use chromecast for radio stations etc..

For just play pause you could use the flow in the other picture.

[{"id":"e6440c30.4a35a","type":"http in","z":"869ceb74.0275c8","name":"","url":"chromecastpause","method":"get","upload":false,"swaggerDoc":"","x":133,"y":98,"wires":[["da574997.aba658","3c918780.5a1728","2870d113.8cef6e"]]},{"id":"2870d113.8cef6e","type":"debug","z":"869ceb74.0275c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":354,"y":50,"wires":[]},{"id":"3c918780.5a1728","type":"function","z":"869ceb74.0275c8","name":"response","func":"msg.success = true;\nmsg.code=\"200\";\nreturn msg;","outputs":1,"noerr":0,"x":432,"y":99,"wires":[["c15fff6.b46af"]]},{"id":"da574997.aba658","type":"function","z":"869ceb74.0275c8","name":"change payload","func":"msg.payload =;\nreturn msg;","outputs":1,"noerr":0,"x":230,"y":207,"wires":[["242ba45d.45b7cc"]]},{"id":"c15fff6.b46af","type":"http response","z":"869ceb74.0275c8","name":"","statusCode":"","headers":{},"x":612.9886169433594,"y":98.46307373046875,"wires":[]},{"id":"242ba45d.45b7cc","type":"api-call-service","z":"869ceb74.0275c8","name":"play pause chromecast","server":"e893ec39.f42e","service_domain":"media_player","service":"media_play_pause","data":"{ \"entity_id\": \"media_player.yourplayername\" }","mergecontext":"","x":574,"y":160,"wires":[[]]},{"id":"e893ec39.f42e","type":"server","z":"","name":"","url":"","pass":""}]<br>

I removed name userpass and url from this so you might need to edit that.

add a switch node if you want to react to more than just pause (see picture for example)

In the home assistant node for pause use:

name: play pause chromecast
domain: media_player
Service: media_play_pause
data: { "entity_id": "media_player.[your chromecast here]" }

for next track just copy that node and edit service to: media_next_track and name to: next chromecast

Step 5: Optional Alexa Pause Chromecast

Optional add alexa command for pause chromecast:

There is to options here.. You can make one alexa nnode called pause chromecast that pauses chromecast,

or you can make one called pause tv that checks current harmony activity and pause depending on that.

I'll add this in here later..