The Software
I found IR libraries to have less than great documentation. I could find examples, but they were a bit tough to parse as well. I finally went with an ESP32 variant of the IRremote library, Arduino-IRRemote. Due to naming conflicts, the built-in RobotIremote library has to be removed from the application bundle (on the Mac, which is the install dir on Windows) to get it to build properly. Getting IR to work took the most time of the development, from testing different libraries to figuring out what the codes actually work and how to get them into a format that the IR libraries would accept.
It’s very important to note that when I started this project, the official Arduino Library didn’t support the ESP32, but by the time I finished it did. The library I used is based on an older version of IRRemote. Somewhat annoyingly, if you click the “releases” link from the repository above, it goes to the official library that has had some significant changes and will not work with my existing code. It took me way too long to realize this when I had to update the remote for my new Yamaha receiver. I finally just downloaded the a zip of the repository so that I had the correct version. I’ll have to update the code for the new library someday…
Sony Codes
Finding codes was its own challenge. After some searching, I finally just plugged an IR receiver into an Arduino Uno I had lying around and loaded IRremote’s IRrecvdemo onto it. I was able to read the volume up and volume down codes for my A/V receiver and pass those to the sendSony() method. This particular device uses 15 bit codes, as evidenced by the length of the hex codes: 0x240C for volume up and 0x640C for volume down.
Sony codes need to be transmitted three times for the device to accept them, with a short delay between. I originally used 40 ms, but this caused a lot of turns of the dial to miss, as sending the codes and the delay are done in a blocking section of code. I was able to get it down to a 5 ms delay with no ill effects, which made the knob much more responsive. It is still easy to miss steps, though, but in general use it’s fine, as I only tend to urn the dial small amounts anyway. However, you still need to turn it slowly to avoid missing steps too often.
Another detail I discovered is the first code sent to the receiver simply shows the current volume level on the VFD or TV overlay, rather than changing the volume level. This means that no matter what you need to go two steps for anything to happen.
Samsung Codes
The Samsung TV power codes were a bit trickier because of what I wanted to have it do. The important thing here is to get discrete on and off codes, rather than the single toggle code that the remote control sends. This meant that I couldn’t just record the code from the remote, which is just an on/off toggle, and had to find another source. A particularly useful site for this is RemoteCentral.com, which has a slew of raw codes for various devices, including Samsung TVs. I converted those codes into a list of integers that could be copied into a C array using IrSscrutinizer (just paste them into the window and hit Scrutinize), which could then be transmitted with sendRaw().
Yamaha Codes
I later replaced the Sony receiver with a Yamaha RX-V4A receiver. This specific model isn’t listened on RemoteCentral.com, but I was able to use some of the raw codes fro another RX class receiver for volume control. I couldn’t find HDMI input codes, though, and the remote doesn’t have discrete input buttons, just next/previous buttons and four “scene” buttons. I would up mapping the scenes to different inputs, and using an ESP32 with an IR receiver and IRRecvDumpV2 from the IRRemote library to capture the NEC codes directly. I mapped these codes to the four input buttons, with the Samsung codes mapped to if the button is held for more than a second. I also have Samsung HDMI 4 fire when using any of the Yamaha codes to ensure that it’s on the correct TV input.
Repeat Codes
I also tried adding support for repeat codes via irsend.sendNEC( REPEAT, 15 ) if successive ticks from the encoder came in fast enough, but this seemed to do nothing at all. I tried different code lengths in place of 15, but nothing worked. I was recording 0xFFFFFF (the repeat code) from the IRrecvdemo, so it definitely supports a repeat code, but I’m not sure how to transmit it. Luckily there are relatively few lost ticks unless you spin the knob quickly, so I decided to just let leave out repeats, at least for the time being. Apparently NEC repeat codes are sent every 110 ms, so even then I could spin the dial faster than it could transmit codes, assuming Sony uses the same repeat period. I didn’t try using the repeat codes with the Yamaha receiver.
Encoder Button
ESPRotary handled direction reporting from the rotary encoder. I read the encoder’s button with the InputDebounce library to easily deal with debouncing, and configured it to turn the TVs on and off.
HTTP Server
The web server was mostly copied from the AutoOffice-ESP8266 code. However, ArduinoJSON has since been updated fairly significantly and I need to make some code changes to get my sketch to build. I also had to make some tweaks to the web server startup sequence to keep it from crashing on boot, but nothing too major.
The final software (including the version 2 input switching functions) can be found on Github.
The Enclosure
I used MODO to design a simple case for the hardware, leaving holes for the USB port, LED headers and rotary encoder. I built in small vent holes in the side to help keep the ESP cool. The case was designed in two halves with screw holes to mate them. I printed this in ABS on my Ender 3 3D printer. I made a second version of the case that is more sloped, and a final third version that has space for the input switching buttons for the Version 2 design described further down.
LXO (all versions)
STL Original (V1) Base Top
STL Sloped (V2) Base Top
STL With Input Buttons (V3) Base Top
I left empty space below the ESP32 to fill with metal, which in this case was some bolts. Lead shot would have been better, but is surprisingly pricey. Tungsten would have been really cool, but even more expensive. Lead Pinewood Derby car would also be an option, but kits are only four ounces and kind of expensive for what they are. I stuck with the bolts, but something heavier would have been nice. A redesign of the enclosure would have made it easier to fit more in. I used some packing tape to ensure that they didn’t short the ESP32.
To keep it from sliding around my desk I bought some adhesive-backed rubber pads by 3M from Amazon, which were sold as “2-Piece Self-Stick Rubber Anti-Skid Pad Furniture and Floor Protectors (Black) by ROOS”. I (poorly) cut it down to the size of the base with cut-outs for the screw holes. It significantly improved how well it stayed in place on the desk, although more weight would have helped even more.