Need help with a Simple IR Remote for a person with Alzheimers

Hello all,

I am not new to Arduino programming but I am very much a newbie. I am trying design a very simple remote for my elderly mother who has severe Alzheimers and can not understand how to use her TV remote anymore. I just want to create a one button remote to turn on and off her TV, that's it. We will set her TV to a safe channel so that she can turn it on to watch something if we are not there to help her.

I am using the IRLib2 library and have a working code although I'm sure there is a better way to go about it. I am using the protocol captured from her current remote. Any suggestions would be welcome and very much appreciated.

#include <IRLibSendBase.h>    //We need the base code
#include <IRLib_HashRaw.h>    //Only use raw sender

const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  3;      // the number of the IR LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

IRsendRaw mySender;

void setup() {
  // initialize the IR LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the button pin as an input:
  pinMode(buttonPin, INPUT);
}

#define RAW_DATA_LEN 68    //SAMSUNG Controller ON
uint16_t rawData[RAW_DATA_LEN]={
  4438, 4662, 418, 1830, 422, 1822, 434, 1818, 
  450, 654, 470, 654, 454, 626, 482, 674, 
  454, 654, 462, 1770, 482, 1794, 478, 1762, 
  478, 630, 498, 630, 478, 622, 494, 630, 
  478, 626, 498, 630, 474, 1782, 486, 618, 
  494, 610, 514, 622, 478, 626, 490, 638, 
  486, 614, 486, 1774, 498, 606, 510, 1742, 
  506, 1786, 466, 1758, 510, 1758, 494, 1766, 
  486, 1774, 494, 1000};

void loop() {
  // read the state of the button value:
  buttonState = digitalRead(buttonPin);

  // check if the button is pressed. If it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    mySender.send(rawData,RAW_DATA_LEN,36);
  }
}

If it works why mess with it? What needs improved?

I would use the state change detection method to send the code only one time when the button becomes pressed.

I would use an active low switch (switch wired to ground). That is the more accepted way of switch wiring. See my state change detection tutorial for using state change detection with an active low switch.

Thank you for taking the time to reply. :slight_smile:

Can it be simplified in any way? Is it best to send using the raw data?

I am also wondering (but haven't asked yet) how to add a second button to send a different signal to her DVD player if it turns out she can manage more than one button.

Thanks!

I don't think that it needs to be simplified. And I do not know that library at all so can not answer the question about raw data.

I don't see why you could not add another button. Just add another function that checks the other button and sends the proper command when the button is pressed.

Here is an example of using the state change detection to send the data only once per button press. Note that I changed the switch wiring to active low (switch wired to ground and the and input set to INPUT_PULLUP). Untested as I do not have that library.

#include <IRLibSendBase.h>    //We need the base code
#include <IRLib_HashRaw.h>    //Only use raw sender

const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  3;      // the number of the IR LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int lastButtonState = 0; // ******** history variable

IRsendRaw mySender;

void setup()
{
   Serial.begin(115200);
   // initialize the IR LED pin as an output:
   pinMode(ledPin, OUTPUT);
   // initialize the button pin as an input:
   pinMode(buttonPin, INPUT_PULLUP);  // ***** active low switch
}

#define RAW_DATA_LEN 68    //SAMSUNG Controller ON
uint16_t rawData[RAW_DATA_LEN] =
{
   4438, 4662, 418, 1830, 422, 1822, 434, 1818,
   450, 654, 470, 654, 454, 626, 482, 674,
   454, 654, 462, 1770, 482, 1794, 478, 1762,
   478, 630, 498, 630, 478, 622, 494, 630,
   478, 626, 498, 630, 474, 1782, 486, 618,
   494, 610, 514, 622, 478, 626, 490, 638,
   486, 614, 486, 1774, 498, 606, 510, 1742,
   506, 1786, 466, 1758, 510, 1758, 494, 1766,
   486, 1774, 494, 1000
};

void loop()
{
   checkOnButton();
}

void checkOnButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      buttonState = digitalRead(buttonPin);
      if (buttonState != lastButtonState)
      {
         if (buttonState == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR");
            mySender.send(rawData, RAW_DATA_LEN, 36);
            // flash the LED on and off
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButtonState = buttonState;
      }
   }
}

If you post a link to where you got that library i will install it so that I can test the code, better.

Here is the link: https://github.com/cyborg5/IRLib2

I am using the rawRecv and rawSend examples as a starting point.

Thank you for the code, I am going to re-wire the switch and test it. :slight_smile:

Hi,

I have re-wired the button and tested it, it works well. I have a follow-up question for the button. With your method, what would be the best way to add a second button? Would that button need to check the state of the other button before it works and vice versa?

Sorry for the very basic questions, I do appreciate the help with this project because my mom is struggling with her remote so much. I am even going to include an IR LED at both ends of the remote as she often points the wrong end at the TV.

I like to think of alternatives....

You might consider the elderly "big" button remotes. And open the case and see if you can make every button turn the TV on. They are simple contact locations where the flexible buttons complete the circuit. Some of the old ones I've taken apart were simple enough but at that time i didn't consider such a modification.

This may not be ideal but:
minimal button remote

Simply disable the buttons you don't want to allow usage (tape under button on PCB). May be a little frustrating to find ON/OFF but you can have it working in 2 days (with Amazon prime).

I modified the code that I previously posted to include the second button. Also, I changed some of the date types (int to byte or bool). Again, untested as I cannot get that library to install. But this code should give you the idea.

#include <IRLibSendBase.h>    //We need the base code
#include <IRLib_HashRaw.h>    //Only use raw sender

const byte buttonPin = 2;     // the number of the pushbutton pin
const byte button_1Pin = 4;  // ***** added a second button
const byte ledPin =  3;      // the number of the IR LED pin

// variables will change:
bool buttonState = 1;         // variable for reading the pushbutton status
bool lastButtonState = 1; // ******** history variable

bool button_1State = 1;  // **** added second button's state
bool lastButton_1State = 1; // **** added second button history

IRsendRaw mySender;

void setup()
{
   Serial.begin(115200);
   // initialize the IR LED pin as an output:
   pinMode(ledPin, OUTPUT);
   // initialize the button pin as an input:
   pinMode(buttonPin, INPUT_PULLUP);  // ***** active low switch
}

#define RAW_DATA_LEN 68    //SAMSUNG Controller ON
uint16_t rawData[RAW_DATA_LEN] =
{
   4438, 4662, 418, 1830, 422, 1822, 434, 1818,
   450, 654, 470, 654, 454, 626, 482, 674,
   454, 654, 462, 1770, 482, 1794, 478, 1762,
   478, 630, 498, 630, 478, 622, 494, 630,
   478, 626, 498, 630, 474, 1782, 486, 618,
   494, 610, 514, 622, 478, 626, 490, 638,
   486, 614, 486, 1774, 498, 606, 510, 1742,
   506, 1786, 466, 1758, 510, 1758, 494, 1766,
   486, 1774, 494, 1000
};

// add raw data array for second button
// #define second button array length
// uint16_t rawDataForSecondButton[length] =
{
   // second button raw data
};


void loop()
{
   checkOnButton();
   checkSecondButton();
}

void checkOnButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      buttonState = digitalRead(buttonPin);
      if (buttonState != lastButtonState)
      {
         if (buttonState == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR for first button");
            mySender.send(rawData, RAW_DATA_LEN, 36);
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButtonState = buttonState;
      }
   }
}

void checkSecondButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      button_1State = digitalRead(buttonPin);
      if (button_1State != lastButton_1State)
      {
         if (button_1State == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR for second button");
            //mySender.send(command for second button);
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButton_1State = button_1State;
      }
   }
}

Hi, I thought about that and we tried the Flipper one. Even that is too confusing for her, she doesn't recognize it. So I am going to 3D print a simple one that looks like her Rogers remote, same colour, size and shape but just has one button, on and off. Possibly a second button if she can manage it.

If I 3D print the case, I can make changes based on what she can do.

Do I need to initialize the second button in the void setup()?

At this point I am just asking both buttons to do the same thing until I have the protocols for her DVD player.

#include <IRLibSendBase.h>    //We need the base code
#include <IRLib_HashRaw.h>    //Only use raw sender

const byte buttonPin = 2;     // the number of the pushbutton pin
const byte button_1Pin = 4;  // ***** added a second button
const byte ledPin =  3;      // the number of the IR LED pin

// variables will change:
bool buttonState = 1;         // variable for reading the pushbutton status
bool lastButtonState = 1; // ******** history variable

bool button_1State = 1;  // **** added second button's state
bool lastButton_1State = 1; // **** added second button history

IRsendRaw mySender;

void setup()
{
   Serial.begin(115200);
   // initialize the IR LED pin as an output:
   pinMode(ledPin, OUTPUT);
   // initialize the button pin as an input:
   pinMode(buttonPin, INPUT_PULLUP);  // ***** active low switch
   pinMode(button_1Pin, INPUT_PULLUP);
}

#define RAW_DATA_LEN 68    //SAMSUNG Controller ON
uint16_t rawData[RAW_DATA_LEN] =
{
   4438, 4662, 418, 1830, 422, 1822, 434, 1818,
   450, 654, 470, 654, 454, 626, 482, 674,
   454, 654, 462, 1770, 482, 1794, 478, 1762,
   478, 630, 498, 630, 478, 622, 494, 630,
   478, 626, 498, 630, 474, 1782, 486, 618,
   494, 610, 514, 622, 478, 626, 490, 638,
   486, 614, 486, 1774, 498, 606, 510, 1742,
   506, 1786, 466, 1758, 510, 1758, 494, 1766,
   486, 1774, 494, 1000
};


void loop()
{
   checkOnButton();
   checkSecondButton();
}

void checkOnButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      buttonState = digitalRead(buttonPin);
      if (buttonState != lastButtonState)
      {
         if (buttonState == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR for first button");
            mySender.send(rawData, RAW_DATA_LEN, 36);
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButtonState = buttonState;
      }
   }
}

void checkSecondButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      button_1State = digitalRead(buttonPin);
      if (button_1State != lastButton_1State)
      {
         if (button_1State == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR for second button");
            //mySender.send(command for second button);
            mySender.send(rawData, RAW_DATA_LEN, 36);
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButton_1State = button_1State;
      }
   }
}

Yes. :+1: Nice catch!

I added that initialization but I still can't seem to get the second button to work.

I know pin 2 is used for most tutorials where the INPUT_PULLUP is used but does it work on pin 4 as well?

Not sure what is wrong as I am just asking the pin 4 button to do the same thing as the first button.
:thinking:

#include <IRLibSendBase.h>    //We need the base code
#include <IRLib_HashRaw.h>    //Only use raw sender

const byte buttonPin = 2;     // the number of the pushbutton pin
const byte button_1Pin = 4;  // ***** added a second button
const byte ledPin =  3;      // the number of the IR LED pin

// variables will change:
bool buttonState = 1;         // variable for reading the pushbutton status
bool lastButtonState = 1; // ******** history variable

bool button_1State = 1;  // **** added second button's state
bool lastButton_1State = 1; // **** added second button history

IRsendRaw mySender;

void setup()
{
   Serial.begin(115200);
   // initialize the IR LED pin as an output:
   pinMode(ledPin, OUTPUT);
   // initialize the button pin as an input:
   pinMode(buttonPin, INPUT_PULLUP);  // ***** active low switch
   pinMode(button_1Pin, INPUT_PULLUP);
}

#define RAW_DATA_LEN 68    //SAMSUNG Controller ON
uint16_t rawData[RAW_DATA_LEN] =
{
   4438, 4662, 418, 1830, 422, 1822, 434, 1818,
   450, 654, 470, 654, 454, 626, 482, 674,
   454, 654, 462, 1770, 482, 1794, 478, 1762,
   478, 630, 498, 630, 478, 622, 494, 630,
   478, 626, 498, 630, 474, 1782, 486, 618,
   494, 610, 514, 622, 478, 626, 490, 638,
   486, 614, 486, 1774, 498, 606, 510, 1742,
   506, 1786, 466, 1758, 510, 1758, 494, 1766,
   486, 1774, 494, 1000
};


void loop()
{
   checkOnButton();
   checkSecondButton();
}

void checkOnButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      buttonState = digitalRead(buttonPin);
      if (buttonState != lastButtonState)
      {
         if (buttonState == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR for first button");
            mySender.send(rawData, RAW_DATA_LEN, 36);
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButtonState = buttonState;
      }
   }
}

void checkSecondButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      button_1State = digitalRead(buttonPin);
      if (button_1State != lastButton_1State)
      {
         if (button_1State == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR for second button");
            //mySender.send(command for second button);
            mySender.send(rawData, RAW_DATA_LEN, 36);
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButton_1State = button_1State;
      }
   }
}

I think that you will need a separate timer variable for the second button. The primary button gets checked first and the other one doesn't get a chance to be read.

INPUT_PULLUP enables the internal pullup resistor that is present on all digital pins (and the analog inputs, too).

The timer and interval variables are local variables declared inside those functions so are only in scope in that function.

1 Like

Oops, good point.

OP, do you see this in your serial output:

sending IR for second button

Was reading buttonPin in the second function instead of button_1Pin. See comment. Again, my bad.

void checkSecondButton()
{
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check button 20 times a second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the state of the button value:
      button_1State = digitalRead(button_1Pin); // **&^&&&***(&&^^^**  was  buttonPin
      if (button_1State != lastButton_1State)
      {
         if (button_1State == LOW) // ***** button pressed = LOW
         {
            Serial.println("sending IR for second button");
            //mySender.send(command for second button);
            mySender.send(rawData, RAW_DATA_LEN, 36);
            digitalWrite(ledPin, HIGH);
            delay(100);
            digitalWrite(ledPin, LOW);
         }
         lastButton_1State = button_1State;
      }
   }
}

Both buttons are working well! :grinning:

My serial output is showing ??? for both buttons but the print is not necessary for the operation of the remote.

Is the baud rate set to 115200 in serial monitor?

I wish you luck, this is such an important quality of life device.

still, I think Voltaire said "....excellent is the enemy of good..."

If you could make all the buttons do the same thing she could have it sooner, while you work on a custom.