Remote controlling an amplifier
We recently got a new TV and wanted to use our existing amp and speakers with it, like we had for the previous TV. That turned out to be more difficult than expected! This post is about the details of getting that working. The solution I settled on is hacky, but doesn’t worsen the user experience.
Getting audio out
Modern TVs have disposed of analogue audio outputs. Our previous TV had a 3.5mm headphone socket which we connected to a small speaker amp’s RCA inputs. That’s no longer an option. Instead, our new TV has optical (TOSLINK), HDMI eARC, or Bluetooth as its only output options.
- Optical audio requires an amp with optical input or a small converter box.
- HDMI eARC sends the audio back to an AV receiver or soundbar over an HDMI cable.
- We don’t want to buy either of those options right now!
- Bluetooth audio is OK but not great.
- It doesn’t feel right to use Bluetooth for a permanent setup.
I chose to use TOSLINK because it keeps the setup simple - just adding a converter box. Upon plugging the Fiio D03K DAC into the TV, it turned out that there’s no volume control over TOSLINK! You’re expected to adjust the volume on the receiving end, by controlling the volume on your amp. That’s all well and good, but my amp only has a physical potentiometer - no remote control! That got me thinking - could I add remote control to the amp?

This is a Nobsound TPA3116 amplifier for small speakers. It doesn't look like they offer this exact model any more - perhaps due to chip shortages, or maybe they're just cobbling stuff together from what's cheap in Shenzhen.
Possible solutions
Receiving infrared commands from a TV remote to an Arduino is easy with the IRremote library I connected a VS1838B IR receiver to an Arduino and set it up to receive Samsung remote commands.
What’s harder is controlling the volume of the amp. It doesn’t have any external volume control, only the knob on the front. I thought of two options:
- Replace the volume potentiometer of the amp with a digital potentiometer chip
- Turn the volume potentiometer of the amp with a motor

Diagrams of the two options I thought of. Using the digital potentiometer is more wiring but a neater solution. Using the servo will be less neat but has a certain hacky aesthetic.
Trying a digital potentiometer
The first option I tested was using a digital potentiometer. In the pointing stick project, I used an MCP4251 digital pot to calibrate the centre position. It works as a variable resistor with 100kΩ resistance, but you can move the wiper digitally. The resistance is linear - each step increases the resistance by the same amount. That doesn’t match your ear’s volume response (which is roughly logarithmic), but it’ll do for a first test.
Here’s where buying a cheap, dodgy amp came in handy. The first one I received was dead on arrival, and only played a buzz with no audio. Luckily the volume knob did change the volume of the buzz. De-soldering the volume pot, I replaced it with the MCP4251 on a breadboard. It worked - I could adjust the volume using SPI commands from an Arduino!

Buying cheap can have its upsides! Now I have almost a full set of spare parts for the working one!
The downside of this option is that you need to modify the amp’s PCB. I wasn’t keep to do that on my working amp, as I might want to undo this mod in future. A less invasive option would be better.
Using a servo
What could be less invasive than turning the potentiometer like you usually would? It’s a much simpler concept too, and I like the hacky style of the solution. The first step to test whether this would work was to make a coupler. The servo needs to connect to the pot securely to turn it.
I designed a simple adapter based on a servo horn I found online (to make the teeth). Printing this on an FDM printer, I found that the resolution wasn’t high enough. The gear teeth became rounded and didn’t fit on the servo. Rather than trying out a friction fit, I printed it again on my resin printer. It resolved plenty of detail on the teeth and the adapter fits fine. The mini servo had plenty of torque to turn the potentiometer, so I could carry on.


The SG-90 servo needs to sit in the right place in front of the amp, aligned with the potentiometer. I recreated the faceplate in FreeCAD and added some bosses on the front to hold the servo.
Connecting this all together with jumper wires was messy. I build a small veroboard circuit to simplify connecting the servo and IR receiver to the Arduino Pro Micro. The 5V and GND are exposed and next to each other, so it needs a case to prevent short circuits. A few more minutes in FreeCAD was enough to design a very basic case for the circuit. I left the back open for cables to exit.


Somehow I managed to make the electronics box snap into place on my first try!
Testing the experience
The first test of the full system showed that it was going to work! Pressing the volume buttons on the TV remote made the volume on the amp change, as it should!. The servo is audible but since the noise is only brief it’s not very disruptive.
The volume steps definitely didn’t seem right. The amp’s linear potentiometer means the volume knob’s response is somewhat logarithmic. It’s more sensitive at the low volume end, so you need to make smaller steps there. I tried using a logarithmic curve, but you couldn’t hear the difference between the steps at the low end. After some testing, I settled on 5 degree steps at the low volume end and 10 degree steps at the high volumes.
The first version had a start-up volume of 0. Every time the TV powered on, the Arduino would turn on and reset the volume to 0. This was annoying - it would feel more natural to start at the same volume you left it. I worried that this might result in it starting too loud, so I picked a low fixed volume for it to start at.
Muting was completely missing to begin with. It turned out we use the mute feature quite a bit, and turning the volume right down wasn’t a good substitute. It was easy to add, so that was a simple fix.
Conclusion
This project should not have been necessary. If TV manufacturers included a single analogue audio output, there would have been no problem! That said, the volume adjuster works well. We’re back to having nice sound quality through external speakers, with controllable volume. It’s a pretty underwhelming outcome - we’re back to where we were before the new TV!
This was a quick project I threw together over a few evenings to make something that worked. Because of that, I didn’t plan it beyond a vague idea in my head. I added each part onto the existing system - coupler, then servo mount, then electronics box. This led to it looking quite cobbled together, which I like!
There are a few more things I’m likely to add over time:
- Rate limiting. The fancy remote spams “volume up” signals very quickly. It’s hard to increase the volume by a single step. If I limit the turning to X increments per second it should be more manageable.
- Restoring previous volume level on startup. It seems like a good idea, with an upper limit to prevent blowing out our eardrums!
- Visual feedback
- If there’s no sound playing it’s hard to tell how much the volume is changing. It would be good to have an indicator that shows the set volume level, to avoid playing unexpected loud sounds.
- A mute indicator would be very helpful! It’s hard to tell whether the amp is muted or turned right down.

Even without those features, the setup is a nice upgrade from the TV's built-in speakers! The design of the parts and the code to control the servo are located on my Gitlab.