Remote volume servo for Home Assistant

Because I’m an idiot, I like to make things that half work rather than buy things that fully work. For that reason, music in my house isn’t provided by a slick Sonos system, but instead by a network of Raspberry Pis with digital to analog converter boards in custom-made 3D printed cases. They run the (excellent) Volumio software, which with a few plugins allows us to play music off our network, stream over Bluetooth, or via Spotify. It’s not perfect, but it all works most of the time and sounds great.

This is in no small part thanks to the fact that the Pis are hooked up to cheap but decent amps (including a pair of Cambridge Audio A1s I picked up for about £20 each), and decent speakers (Tannoy Arena in two rooms – the remains of my old home cinema system – & Dali Zensors in another – refurbed from a charity shop).

The main problem with this arrangement is that the amp for the kitchen is tucked away in a fairly inaccessible place. I can turn it on and off remotely with (audiophiles avert your eyes) a Sonoff unit I wired into the power line. But I can’t change the volume without climbing on a stool.

There is a reason for this: I figured control over the input volume via Volumio would be sufficient. It is not. So now I’m looking for a solution. My idea? Rig up a servo for remote control via Home Assistant so that I adjust the physical volume knob remotely.


The first thing I did was take some measurements of the amp, then had a dig through my various component boxes. Out came a 9g micro servo, a toothed wheel and matching belt (harvested from a photocopier I dismantled for exactly this type of part), and I went to work in Fusion 360.

I kept the design incredibly simple at first. And frankly it hasn’t got any more complicated. There’s a face plate that simply clips to the front of the amp, which has some nicely positioned ridges due to its construction. Then there’s a mounting piece for the servo, axle and pulley that glues to the top of this (I made it in two parts for ease of 3D printing).

The 6mm axle is 3D printed with a recess in one end to fit tightly over the output shaft of the servo. This took a couple of iterations, but at 9 minutes for a print, that wasn’t an issue. The other end of the axle is mounted in a 6mm bearing – also harvested from the photocopier.

The face plate took a couple of iterations to get the sizing right to properly clip on the front. But the actual mechanism worked a treat once I had the axle properly sized to fit the servo. I hooked the servo up to a simple sketch on an Arduino Uno and tried the Sweep example. Success!

The next challenge was tensioning the belt – a bit too long for the distance from the top of the amp to the volume knob. I could have pushed up the mounting for the servo to create some tension – either adjustable or fixed – but it might have made the amp mounting a little awkward. So instead I plumped for an idler mounted on a spring to push in on the belt from the side.

This used parts reclaimed from – you guessed it – the photocopier. I swear I got thousands of pounds worth of parts from that £5 machine. Including a number of small idlers with integrated roller bearings. One of these sits over an M5 screw. The holes in the mounting are sized so that it screws in without the need for any nuts or inserts.

You can download the STL files here.


The electronics for this project are incredibly simple. I’m a huge fan of the ESP8266-based NodeMCU and I had a few of these in store, so it was always going to based on that. The NodeMCU Base makes using these chips even easier, breaking out 5v and 3v3 power, and adding a barrel jack and external regulator so you can use a variety of power supplies.

Micro servos are perfectly happy running at 3V so I simply hooked up the power and ground lines of the servo to the Base and connected the signal line to D5. Nothing else needed! I’ll add a separate case for the NodeMCU that can be placed off to one side. This one I’m actually going to run off the USB port rather than the barrel jack since I have some spare sockets on a USB power hub where it will be living.


The software for this project is also very simple, as someone else has done all the work. Namely the incredible Otto Winter, creator of ESPHome. ESPHome makes it super simple to program and manage esp8266 and esp32 devices to use with your home automation system. There is an integrated UI for Home Assistant for managing all your devices, and you can even program them just by plugging them into your Home Assistant server.

I started with Otto’s example code from this page and made a few modifications from there:

Apart from renaming a few things, my main alteration was to the steps to control the servo from Home Assistant. I wanted a scale from 1 to 10 (though was tempted to take it up to 11) rather than +/- 100 (as it is in the video above). You can see how I’ve done this in the examples below.

ESPHome Configuration

   - service: volume_control
       level: float
       - servo.write:
         id: volume_servo
         level: !lambda 'return (level - 5) / 5.0;'

   - id: volume_servo
     output: pwm_output
     auto_detach_time: 3s

   - platform: esp8266_pwm
     id: pwm_output
     pin: D5
     frequency: 50 Hz

Home Assistant Configuration

### add this wherever you configure your input_numbers - could be configuration.yaml or a separate file if you have broken yours out like I have ###
     name: Volume Control
     initial: 5
     min: 0
     max: 10
     step: 1
     mode: slider

### add this to your automations - usually via the front end ###
alias: Amp Volume Control
   - platform: state
   entity_id: input_number.volume_control
   - service: esphome.amp_control_volume_control
       level: '{{ trigger.to_state.state | int }}'
mode: single

Note that for the Home Assistant automation, if you are using the front end editor you will need to click the three dots and select ‘Edit YAML’ in order to add the data template correctly.

Next steps

This all works nicely as you can see in this video. But there are some tweaks needed. Notably, the gearing. With the little pulley I used initially, I get less than a quarter turn on the volume dial. Half a turn would be more useful, so I will replace the pulley with a larger one on the next version. This means redesigning the frame to accomodate it.

Other than that, I’m really happy with this as a simple little fix. Long term, I might integrate power control of the amp into the same unit and put it all in a neater case – maybe with the Pi. But that’s for another day.