Infrared, a CEC Injection Alternative

Posted on May 20, 2020

A few years ago, I decided to replace my three 1080p monitors in favor of a single 4k television. I’m not entirely sure what contributes to the massive discrepancy in price between monitor and TV, but for my purposes, text editing and Internet surfing, I doubt I’ll ever fully understand. There are a few minor inconveniences, but they can be overcome. The first, assuming your hardware is capable of 3840 x 2160, is getting it at 60hz through HDMI 2.0. In my case I had to use a DisplayPort adapter. Next, finding where the setting for 4:4:4 chroma subsampling is. It seems every manufacturer has it’s own obscure nomenclature for the feature and it even changes between models of the same brand. Not sure why it wouldn’t be activated by default. For my TV, and what seems to be most Samsungs, I had to enable the setting and then cycle the power at the outlet before I got any results. Activating “UHD Color” briefly blanks the screen as if something is happening, but didn’t change anything until I unplugged it and turn it back on. In my experience, it’s also beneficial to enable PC and gaming modes. A pain in the ass, but that’s how you know you’re getting a good deal. The last nuisance to contend with and the focus of this post is having to reach for the remote every time you want to turn the screen on and off. It’s really not that bad, but once you get everything configured properly, it’s the only thing left to regularly remind you that you’re not using something designed to interface with a computer. There are solutions in the form of CEC injectors, commonly used in Kodi setups, but they’re like $40 dollars. All you need is an Arduino and an IR transmitter and receiver.

Parts

Software

  • Xscreensaver
  • Arduino IDE
  • Sherriff’s IRRemote library
  • Perl

Instruction

Install Sherriff’s IRRemote library in the Arduino IDE.Ctrl+Shift+I to manage libraries.

image-20200518234903691

Connect the IR receiver (5v, ground, and data) to capture your remote control’s power signal.

image-20200519000044027

Use Sherriff’s example sketch “IRrecvDumpV2” and upload it. If you used data pin 11, there’s nothing to configure. Just open your serial monitor and check that baud is 9600. Press the power button at the IR receiver with your remote control and you should see the raw signal. Something like:

{9000, 4500, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 39416, 9000, 2210, 560}

You might also want to capture additional functions, like “exit” so you can make that info dialog disappear immediately after turning on. Now you’re ready bury that remote deep in the couch where it belongs and connect the IR transmitter LED to ground and data pin 3 (not optional). A 470 ohm resistor doesn’t hurt.

image-20200519004900425

The following sketch will wait for a “p” character and transmit the power signal. Put your raw signal data where the comments indicate:

IRsend irsend;
int khz = 38; // 38kHz carrier frequency for the NEC protocol
unsigned int irPower[] =  // Your raw power signal here
unsigned int irExit[] =  // Your raw exit signal here
void setup()
{
  Serial.begin(9600);
}
void loop() {
  char incomingCharacter = Serial.read();
  switch (incomingCharacter) {
    case 'p':
      irsend.sendRaw(irPower, sizeof(irPower) / sizeof(irPower[0]), khz);
      delay(2000);
      irsend.sendRaw(irExit, sizeof(irExit) / sizeof(irExit[0]), khz);
      break;
  }
}

Upload and test by sending a “p” in the serial monitor. If your LED is positioned correctly, your screen should turn on or off. The last step is to run a script that makes a serial connection to tell the Arduino when you want it to send the power signal. There are a myriad of ways to accomplish this. I stole and modified a Perl script from the xscreensaver-command documentation:

#!/usr/bin/perl
system "stty -F /dev/ttyUSB0 raw ispeed 9600 ospeed 9600 cs8 -ignpar -cstopb -echo";
system "cat < /dev/ttyUSB0 > /dev/null &";
$blanked = 0;
 open (IN, "xscreensaver-command -watch |");
 while (<IN>) {
     if (m/^(BLANK|LOCK)/) {
         if (!$blanked) {
             system "echo -n p  > /dev/ttyUSB0";
             $blanked = 1;
         }
     } elsif (m/^UNBLANK/) {
         system "echo -n p  > /dev/ttyUSB0";
         $blanked = 0;
     }
 }

The script provides for different actions on “BLANK” and “UNBLANK”, but in my case it does the same thing. Attached below is a basic enclosure if you happen to be using the same Arduino clone I had.

image-20200520230845766 Download from Thingiverse

Resources