Building a custom remote control

I am trying to build a custom remote to control several of my HiFi & TV systems from a single remote.

To start testing, I have an Adafruit IR receiver wired to an Uno and I'm using example code from the IRremote library:

/*
 * SimpleReceiver.cpp
 *
 * Demonstrates receiving ONLY NEC protocol IR codes with IRremote
 * If no protocol is defined, all protocols (except Bang&Olufsen) are active.
 *
 *  This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
 *
 ************************************************************************************
 * MIT License
 *
 * Copyright (c) 2020-2025 Armin Joachimsmeyer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************************
 */

#include <Arduino.h>

/*
 * Specify which protocol(s) should be used for decoding.
 * If no protocol is defined, all protocols (except Bang&Olufsen) are active.
 * This must be done before the #include <IRremote.hpp>
 */
//#define DECODE_DENON        // Includes Sharp
//#define DECODE_JVC
//#define DECODE_KASEIKYO
//#define DECODE_PANASONIC    // alias for DECODE_KASEIKYO
//#define DECODE_LG
//#define DECODE_NEC          // Includes Apple and Onkyo. To enable all protocols , just comment/disable this line.
//#define DECODE_SAMSUNG
//#define DECODE_SONY
//#define DECODE_RC5
//#define DECODE_RC6

//#define DECODE_BOSEWAVE
//#define DECODE_LEGO_PF
//#define DECODE_MAGIQUEST
//#define DECODE_WHYNTER
//#define DECODE_FAST

//#define DECODE_DISTANCE_WIDTH // Universal decoder for pulse distance width protocols
//#define DECODE_HASH         // special decoder for all protocols

//#define DECODE_BEO          // This protocol must always be enabled manually, i.e. it is NOT enabled if no protocol is defined. It prevents decoding of SONY!

//#define DEBUG               // Activate this for lots of lovely debug output from the decoders.

//#define RAW_BUFFER_LENGTH  750 // For air condition remotes it may require up to 750. Default is 200.

/*
 * This include defines the actual pin number for pins like IR_RECEIVE_PIN, IR_SEND_PIN for many different boards and architectures
 */
#include "PinDefinitionsAndMore.h"
#include <IRremote.hpp> // include the library

void setup() 
{
    Serial.begin(115200);

    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));

    // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
    IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
    Serial.print ("IR_PIN: ");
    Serial.println(IR_RECEIVE_PIN);
    
    Serial.print(F("Ready to receive IR signals of protocols: "));
    printActiveIRProtocols(&Serial);
    Serial.println(F("at pin " STR(IR_RECEIVE_PIN)));
}

void loop() 
{
    /*
     * Check if received data is available and if yes, try to decode it.
     * Decoded result is in the IrReceiver.decodedIRData structure.
     *
     * E.g. command is in IrReceiver.decodedIRData.command
     * address is in command is in IrReceiver.decodedIRData.address
     * and up to 32 bit raw data in IrReceiver.decodedIRData.decodedRawData
     */
    if (IrReceiver.decode()) {

        /*
         * Print a summary of received data
         */
        if (IrReceiver.decodedIRData.protocol == UNKNOWN) 
        {
            Serial.println(F("Received noise or an unknown (or not yet enabled) protocol"));
            // We have an unknown protocol here, print extended info
            IrReceiver.printIRResultRawFormatted(&Serial, true);

            IrReceiver.resume(); // Do it here, to preserve raw data for printing with printIRResultRawFormatted()
        } 
        else 
        {
            IrReceiver.resume(); // Early enable receiving of the next IR frame

            IrReceiver.printIRResultShort(&Serial);
            IrReceiver.printIRSendUsage(&Serial);
        }
        Serial.println();

        /*
         * Finally, check the received data and perform actions according to the received command
         */
        if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) {
            Serial.println(F("Repeat received. Here you can repeat the same action as before."));
        } else {
            if (IrReceiver.decodedIRData.command == 0x10) {
                Serial.println(F("Received command 0x10."));
                // do something
            } else if (IrReceiver.decodedIRData.command == 0x11) {
                Serial.println(F("Received command 0x11."));
                // do something else
            }
        }
    }
}

This works fine, I can point remotes at it and the Uno will report what it sees.

So I set up a Nano Every with code from the same library to transmit using an Adafuit superbright 5mm IR led (part 388A) using this code:

//#include <IRremote.hpp>

/*
 * SimpleSender.cpp
 *
 *  Demonstrates sending IR codes in standard format with address and command
 *  An extended example for sending can be found as SendDemo.
 *  Sending IR codes using several pins for sending is implements in the MultipleSendPins example.
 *
 *  Copyright (C) 2020-2025  Armin Joachimsmeyer
 *  armin.joachimsmeyer@gmail.com
 *
 *  This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
 *
 *  MIT License
 */
#include <Arduino.h>

#if !defined(ARDUINO_ESP32C3_DEV) // This is due to a bug in RISC-V compiler, which requires unused function sections :-(.
#define DISABLE_CODE_FOR_RECEIVER // Disables static receiver code like receive timer ISR handler and static IRReceiver and irparams data. Saves 450 bytes program memory and 269 bytes RAM if receiving functions are not required.
#endif
//#define SEND_PWM_BY_TIMER         // Disable carrier PWM generation in software and use (restricted) hardware PWM.
//#define USE_NO_SEND_PWM           // Use no carrier PWM, just simulate an active low receiver signal. Overrides SEND_PWM_BY_TIMER definition

/*
 * This include defines the actual pin number for pins like IR_RECEIVE_PIN, IR_SEND_PIN for many different boards and architectures
 */
#include "PinDefinitionsAndMore.h"
#include <IRremote.hpp> // include the library

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);

    Serial.begin(115200);

    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));
    Serial.print(F("Send IR signals at pin "));
    Serial.println(IR_SEND_PIN);

    /*
     * The IR library setup. That's all!
     */
    IrSender.begin(); // Start with IR_SEND_PIN -which is defined in PinDefinitionsAndMore.h- as send pin and enable feedback LED at default feedback LED pin
    disableLEDFeedback(); // Disable feedback LED at default feedback LED pin
    delay(1000);
    IrSender.sendSamsung(0x7, 0x2, 0); // TV on and off - does not work
    IrSender.sendNEC(0x7C87, 0x88, 0);  // NAD volume up. Protocol=NEC Address=0x7C87 Command=0x88 Repeat Gap=38400us Duration=11750us
}

/*
 * Set up the data to be sent.
 * For most protocols, the data is build up with a constant 8 (or 16 byte) address
 * and a variable 8 bit command.
 * There are exceptions like Sony and Denon, which have 5 bit address.
 */
uint8_t sCommand = 0x34;
uint8_t sRepeats = 0;

void loop() {
    return;
    /*
     * Print current send values
     */
    Serial.println();
    Serial.print(F("Send now: address=0x00, command=0x"));
    Serial.print(sCommand, HEX);
    Serial.print(F(", repeats="));
    Serial.print(sRepeats);
    Serial.println();

    Serial.println(F("Send standard NEC with 8 bit address"));
    Serial.flush();

    // Receiver output for the first loop must be: Protocol=NEC Address=0x102 Command=0x34 Raw-Data=0xCB340102 (32 bits)
    IrSender.sendNEC(0x00, sCommand, sRepeats);

    /*
     * If you want to send a raw HEX value directly like e.g. 0xCB340102 you must use sendNECRaw()
     */
//    Serial.println(F("Send 32 bit LSB 0xCB340102 with NECRaw()"));
//    IrSender.sendNECRaw(0xCB340102, sRepeats);

    /*
     * If you want to send an "old" MSB HEX value used by IRremote versions before 3.0 like e.g. 0x40802CD3 you must use sendNECMSB()
     */
//    Serial.println(F("Send old 32 bit MSB 0x40802CD3 with sendNECMSB()"));
//    IrSender.sendNECMSB(0x40802CD3, 32, sRepeats);

    /*
     * Increment send values
     */
    sCommand += 0x11;
    sRepeats++;
    // clip repeats at 4
    if (sRepeats > 4) {
        sRepeats = 4;
    }

    delay(1000);  // delay must be greater than 5 ms (RECORD_GAP_MICROS), otherwise the receiver sees it as one long signal
}

This works too in test - it sends signals to the Uno receiver and it reports them the same way as it does when I press the matching button on the remote.

However, when I test the Nano circuit agains the TV or amplifier, nothing happens. I'm at a bit of a loss as to how to debug this.

How far away were you when you did the test?
How far away were you when you tried it with TV?

In test, it's a foot or so. I tried it at every distance from long to very short against the TV. Certainly worth a bit more scientific investigation though.

Thanks.

Unless you are driving the LED with 100mA or more it won't output a lot of power, so it won't go very far.

How do you have the LED connected to the Nano Every?
Do you have a 220 ohm resistor in series?

Why not just buy a learning remote control? Maybe like this.

I would, but part of this is to make it usable by a user with poor eyesight and all the examples I can find that learn have tiny buttons.

Indeed I do.

Looking at the datasheet linked by Adafruit for the product check figure 5 for radiant intensity vs forward current.

As @jim-p suggests, driving the led directly from a pin will get you low intensity. The TV remote receiver may have a lower sensitivity than your test apparatus.

Or just use a filter to avoid a false positive signals

Then see post #4
You need more current.
Do you need help with a circuit?
Do you know how to solder?
Do you have a multimeter/DMM?
Can you buy from Digi-Key or Mouser?
Do you have any MOSFETs or transistors?

You need more current.
Ok, I have plenty of spares if I blow one or two.

Do you need help with a circuit?
Normally yes, but this test is trivial.

Do you know how to solder?
Yes. Badly, but it's all breadboard for now, although perhaps higher current will make that a bad idea.

Do you have a multimeter/DMM?
Yes. A very nice birthday present :grinning_face:

Can you buy from Digi-Key or Mouser?
Yes.

Do you have any MOSFETs or transistors?
Yes. finding them may be another matter.

Does that mean you know what to build or you don't want to build anything.

I can put a simple circuit together on a breadboard and so far, both transmitter and receiver are so simple I don't need help wiring them up. If I have to solder them up I will, but at this point I haven't got any further than breadboard tests. Similarly, if you folks think I need a mosfet to drive the transiting LED, I can wire that up too. Basically though, I'm a software guy - when it comes to hardware, I just have to fake it until I make it :wink:

Up to you.
If you want to go farther then a few feet, then you will need a driver circuit.

It certainly looks like it - I did some tests on the bench with the 220 ohm resistor still in place. The range is less than three feet :hushed_face:

Can you suggest a suitable MOSFET?

The IRLZ44N is very common and will work.

If you don't have transistors on hands, you can put 3 LEDs in series with 68ohm resistor. If that doesn't work from short distance, I expect you have something else wrong.

Ok Jim, I have my MOSFETS and a wider selection of resistors, as I see some circuits use 64 ohm items. Could you advise on a preferred circuit please.

Could you clarify what kind of test you did? In the case of the TV, did you fire the TV's remote into your Adafruit IR receiver to detect what protocol, address and command it is using for a particular key, and then enter that info into your transmit sketch? If so, could you give us the details of one such test, including the brand and model of the TV?

Yes, that's exactly what I did. The library example even kindly spits out the code needed for transmitting what was read. The first try was to turn the TV on. You can see the code for it in the second sketch I included in the original post.

I see that I also added code in there for increasing the volume on my amplifier, which is a NAD C658. This second test was included after the TV failed to respond. The TV is a Samsung, model UN60KS8000FXZA.