Adding IR control to Computer Monitor

The Situation: We have a 22" Asus monitor that we wanted to wall mount in our nursery and use as a TV. It has an HDMI input, and built in speakers, so we thought this would be perfect with a ROKU box on it.

The Problem: There is no remote for this monitor (it never had one). The monitor is being mounted across the room, and it is inconvenient to walk across the room to push the volume/power buttons.

The Solution: Take apart the monitor and add in an Arduino controlled IR receiver; basically turn it into a Sony (compatible) TV.

Resources & Credits:

Taking apart the monitor, and getting access to the buttons.

I used an old USB header cable for connecting the power supply and buttons.
Once opened, I found a 5v supply in the monitor - I just tapped into that for powering the Arduino.

I used an old 3-pin fan cable from a computer to wire up the IR sensor, I just plugged this straight into a header that I soldered on the board.

You can see the whole assembly here. It is attached to power from the monitor, there are 3 transistors wired out to control the buttons on the monitor, and the IR sensor is attached at the base.

Here I drilled a hole in the side of the monitor for the IR sensor to poke through.

I carved out a bit of plastic from the inside to make the sensor fit better.

I also drilled a couple of small holes for mounting the board to the inside of the monitor.

You can see how everything is mounted from inside.

Here you can see how the IR sensor looks from the outside.

Next you can see how the board looks with everything wired up inside the monitor.

If you look closely at the closeup of the buttons, you can see the IR receiver on the right side of the monitor (sorry for the not great picture).

Finally, you can see the whole thing done, and mounted to the wall.

Now for the code controlling the whole thing:

/**
 * Add a remote control to an ASUS Monitor
 * Uses Power & Volume buttons from a standard Sony TV remote
 */

#include <EEPROM.h>

//CONSTANTS
#define btnPower   149
#define btnMute    148
#define btnDown    147
#define btnUp      146
#define rate       4
#define start_bit  2000                //Start bit threshold (Microseconds)
#define bin_1      1000                //Binary 1 threshold (Microseconds)
#define bin_0      400                //Binary 0 threshold (Microseconds)
#define ir_pin     2                //Sensor pin 1 wired through a 220 ohm resistor
#define led_pin    13                //"Ready to Recieve" flag, not needed but nice
#define debug      0                 //Serial connection must be started to debug


//VARIABLES
long timer = -5000;
int i      = 0;                    //general purpose counter 
int wait = 20;


void setup() {
  pinMode(6, OUTPUT); //Push button when Volume-down detected
  pinMode(7, OUTPUT); //Push button when Volume-up detected
  pinMode(8, OUTPUT); //Push when Power detected
  pinMode(led_pin, OUTPUT);          //This shows when we're ready to recieve
  pinMode(ir_pin, INPUT);
  digitalWrite(led_pin, LOW);          //not ready yet
  timer = -5000; // used for volume up command
}

void loop() {
  //Fetch the key  
  int key = getIRKey();
  
   switch (key) {     
    case btnPower:
      digitalWrite(8, HIGH);
      delay (500); //Debounce switch
      digitalWrite(8, LOW);
      timer = -5000;
      break;
      
    case btnDown:
      digitalWrite(6, HIGH);
      delay(wait);
      digitalWrite(6, LOW);
      timer = millis(); //reset timer to now
      break;   
      
    case btnUp:
      if ((millis() - timer) >= 3500){ // activate volume instead of default brightness setting for vol + button.
        digitalWrite(6, HIGH); 
        delay(wait);
        digitalWrite(6, LOW); 
        delay(wait);
      }
      digitalWrite(7, HIGH);
      delay(wait);
      digitalWrite(7, LOW);
      timer = millis(); //reset timer to now
      break; 
    
    default:
      digitalWrite(8, LOW);
      digitalWrite(6, LOW);
      digitalWrite(7, LOW);
  }
}


int getIRKey() {
  int data[12];
  digitalWrite(led_pin, HIGH);         //Ok, i'm ready to recieve  
  
  while(pulseIn(ir_pin, LOW) < 2200) { 
    //Wait for a start bit
    return -1; //clear out old codes
  }
  
  for(i=0;i<11;i++){
    data[i] = pulseIn(ir_pin, LOW);   //Start measuring bits, I only want low pulses
  }
  
  digitalWrite(led_pin, LOW);

  if(debug == 1) {
    //Serial.println("-----");
  }
  
  for(int i=0;i<11;i++) {          //Parse them
    
    if (debug == 1) {
      //Serial.println(data[i]);
    }
    
    if(data[i] > bin_1) {          //is it a 1?
      data[i] = 1;
    } else {
      if(data[i] > bin_0) {        //is it a 0?
        data[i] = 0;
      } else {
        data[i] = 2;              //Flag the data as invalid; I don't know what it is!
      }
    }
    
  }

  for(i=0;i<11;i++) {              //Pre-check data for errors
    if(data[i] > 1) {
      return -1;                //Return -1 on invalid data
    }
  }

  int result = 0;
  int seed = 1;
  for(int i=0;i<11;i++) {      //Convert bits to integer
    if(data[i] == 1) {
      result += seed;
    }
    seed = seed * 2;
  }
  return result;             //Return key number
}

One tricky part for this code is that the monitor uses the same buttons for both volume and brightness. If you press the Vol (+) button first, it will do brightness, not volume (goofy design if you ask me). What I did to counter this, is if more than a few seconds have gone by, and you press the Vol (+) button on the remote, the Arduino will send one Vol (-) command before sending the Vol (+) commands - this is enough to get the monitor into volume mode first before increasing volume.

This code was modified from the link referenced in the first post. Thanks to all of the resources listed on top - they were all very helpful.

The monitor now works just as if it were a Sony TV (well at least for Power, Volume Up, and Volume Down). The wife is very happy. :slight_smile:

This makes me want to turn my old monitor into a TV