Hardware volume control for Chromecast Audio devices

Similar projects worth following

CastVolumeKnob is hardware volume control for Chromecast Audio devices, based on the ESP8266 microcontroller using micropython.

The problem

  • For controlling the volume on Chromecast devices you need to use your phone. - it is clumsy, not very intuitive.

The requirements

  • Easy to use, hardware based volume control.
  • Wireless
  • Visual feedback of the current volume level
  • Relatively cheap

The solution

This is the final form. Completely wireless, rechargeable device. 

To wake it up you have to tap the knob once. After it wakes up it automatically connects to the first chromecast device, you can control its volume by turning the knob. To change the device tap the knob again. To stop the music playback press and hold the knob until the LEDs turn red.

  • 1 × ESP8266 WEMOS D1 mini
  • 1 × ATtiny85 Microprocessors, Microcontrollers, DSPs / ARM, RISC-Based Microcontrollers
  • 1 × 18650 Battery Battery
  • 1 × Clickable Rotary Encoder
  • 1 × NeoPixel Ring or Strip WS2812

View all 11 components

  • Schematic

    Ákos Melczer01/30/2019 at 14:58 0 comments

    I added the schematic in .jpg and .png to the github repo:

  • PCB and case design

    Ákos Melczer01/24/2019 at 23:48 0 comments

    The requirements I set for the PCB design were:

    • relatively small size
    • using THT components for easy soldering and debugging
    • circle shape
    • connectors for the wires to be able to taken apart

    I designed the PCB in KiCAD. Managed to fit all the components on a 70mm circle PCB with a 12mm hole in the middle for wires to run through it. Ordered 10 pieces from JLCPCB and after 2 weeks these showed up.

    Not counting a minor mistake in my design - MOSFET legs swapped - It turned out great. After soldering on all the components, everything worked as expected.
    It was time to design a case for it.

    I designed the case for 3D printing in Solidworks. It consist of 5 parts. Only 2 pieces are needed to be glued together, the other parts connects with screws. The whole model can be easily assembled and disassembled.

    This is the models Section analysis.

    In the top part under the translucent part goes the LED ring. In the top center goes the clickable encoder. in the middle section is the main board. In the bottom is the battery and the charger/boost converter board. 

    Printed and assembled, working.

  • First prototype

    Ákos Melczer01/24/2019 at 00:00 0 comments

    My next step was to implement the hardware and prototype code on the microcontroller.

    For the microcontroller I chose the ESP8266 because it's well documented and easy to use wifi capabilities. I wanted to try out micropython for this project. After flashing it into the ESP it was very straight forward to port my prototype code from my PC to the microcontroller. The only third party library I had to use was the micropython-stm-lib/encoder/ which I modified to be able to set the initial value of the encoder. To control the Neopixel ring I made a custom class which inherited from the built in Neopixel class.

    After soldering everything up to a prototype board, it looked like this.
    Since I wanted to make this project wireless I had to consider the power consumption as well, which was not great at this point. I implemented a MOSFET to turn off the Neopixel ring power when its not in use. The ESP8266 still consumed too much power in standby mode. After a bit research i found out about the ESP8266's DEEPSLEEP mode which is basically turns the microcontroller down completely. To wake it up you need to reset it what is usually done by hooking up the internal watchdog timer to the reset pin, but in my case i only needed to wake up the mcu when the encoder push button is closed. For this purpose I used the ATtiny85 mcu in sleep mode and used interrupts to wake it up. After it wakes up, forwards the next button presses to the ESP to change the chromecast device or stop the playback. With the interrupt handler/watchdog mcu and the MOSFET, the power draw dropped from 100-80 mA to 0.8 mA in standby.
    According to my calculations, could run for 3 months with a single 18650 Li-Ion battery. This is great!
    The next thing I was not happy with yet was the visualization. When I was changing the color on the LED ring the brightness was also changing, this was due to the neopixels non linearity. Quick search online I found a gamma correction table for these LEDs, which worked for me reasonably well. At first I divided the LEDs equally to represent the volume level from 0 to 100. Later I realized This was not very useful, because i was hard to tell the precise volume level just by looking at the ring. My solution was to use most of the LEDs to represent volume levels from 10 to 30 percent and to show 0 to 10 and 30 to 100 i used the remaining LEDs on the side. To distinguish between multiple Chromecast devices I assigned a color to each device and used the first LED on the ring to show that color.
    At this stage I was almost happy with the software functionality, I started to design the PCB.

  • First steps

    Ákos Melczer01/21/2019 at 22:34 0 comments

    The first I had to figure out  a way I can communicate with Chromecasts. The official API to communicate only supports Android, iOS and Chrome browser. For my purpose either of those options are usable, I needed to communication from a microcontroller.

    Third party options:

    None of these options were appropriate for my use case but I have found a lot's of useful information in the documentations.


    Chromecasts use a communication protocol called Protocol-buffers or protobuf, developed by Google.

    To use protocol-buffers you need to 'define' your protocol in a .proto file which you can compile out to a library. The supported languages are:

    • C++
    • C#
    • Dart
    • Go
    • Java
    • Python

    I started development on a PC and I choose Python because it was the easiest and quickest to develop in for me. At first I tried to construct my own protocol-buffer messages but I couldn't get it to work.Then I tried the .proto file and the compiled library from the pychromecast library, but i still didn't got any response.

    Then I tried to capture the messages sent from the pychromecast library with wireshark, but the socket is encrypted.

    Then I inserted a few print statements in to the library before sending the messages.

    And i got messages like this:

    b'\x00\x00\x00Y\x08\x00\x12\x08sender-0\x1a\nreceiver-0"(\x002\x13{"type": "CONNECT"}'

    With the protocol-buffer libray I could parse these strings and into more readable JSON format.

    When i tried to send these back, I got an answer from the Chromecast - Finally!

    I continued with this method and found the message responsible for changing the volume, I could even change the value and it still worked.

    Done. Right?

    Not so fast!

    For some reason it only worked when I converted the messages to strings with the precompiled protocol-buffer library.

    Due to size and complexity I can't use the protobuf library on a microcontroller, I need a simpler solution.

    My first thought was creating messages to set the volume from 0 to 100 and from that create a lookup table. As I was creating that table I noticed a pattern, besides the value of the volume i wanted to change there is a request number. Every message from the initial connection is numbered, starting from 1 and increments by 1. I needed to change that as well. Although almost everything else stayed the same between the messages there was still one important difference. Every part of the message had a number before it indicating its size. Since I wanted to send volume and request values from single digits to triple digits (0 to 100) I needed 5 different sized message. From those 5 created messages I can pick according to the current volume level and request number. And it worked. :)

    Now I got it working without any third party library, I was getting closer.

View all 4 project logs

  • 1
    Programming the ESP8266
    • install esptool and ampy
      • pip install esptool
        pip install adafruit-ampy
    • erase the flash with esptool
      • --port COM5 erase_flash  
    • download the micropython firmware
    • deploy the firmware
      • --port COM5 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin
    • put the code to the mcu
    • ampy -p COM5 -b 115200 put
  • 2
    • 3D print the case and glue the middle and the top part together
    • Solder everything to the PCB
    • Put the LED ring and Encoder in place
    • Screw the Board in place
    • Solder the Battery holder to the charging/boost converter board
    • Glue it in place
    • Screw the bottom part in

View all instructions

Enjoy this project?



calebmabewake wrote 08/30/2022 at 04:45 point

Hey Akos, this looks like it could be a perfect solution for what I'm trying to do. Basically I used cc audio to connect several speakers through my house. My wife regularly wants to change volume but is not using the casting device. Would this solution work to control a whole speaker group or just one speaker at a time? Apologies for the simple question. I'm a little new to all this, thanks.

  Are you sure? yes | no

thusgaard wrote 01/05/2020 at 18:09 point

Hi Ákos, is it possible to do this project with out soldering, and with out the battery. I would love to build this project but on a beadboard. 

  Are you sure? yes | no

Ákos Melczer wrote 03/13/2020 at 22:16 point

Hello, it is certainly possible to recreate this on a breadboard, however it would get considerably bigger and would require a bigger enclosure.

  Are you sure? yes | no

matfra wrote 07/08/2019 at 02:20 point

This is a great idea and a great project ! I'll try to give it a shot, thank you for sharing !

  Are you sure? yes | no

Mauricio Farías wrote 03/28/2019 at 21:28 point

I really like your project. Very clear instructions! Congratulations! 

  Are you sure? yes | no

Dillon Nichols wrote 02/25/2019 at 16:44 point

Awesome project. I'm trying to make my own but have some questions about the electronics. I sent you a message on here if you get a chance to help me out. Thanks!

  Are you sure? yes | no

Alexander wrote 02/04/2019 at 18:27 point

This is excellent! I love my Chromecast Audio, but it's such a pain to either use my Home Mini to tell it to turn down, or open my phone and go to the Google Home app. Now that Chrome has blocked ad-blockers and I'm back on Opera, I can't even use my browser to control the volume! I totally need to build this.

Awesome work!

  Are you sure? yes | no

pete.reiter wrote 02/01/2019 at 06:44 point

very nice. I made a chrome cast volume knob with album art / now playing display using a pi zero and a small tft display. Unfortunately, like most of my pi projects it eventually stopped working.

I might make one of these since you have the protocol implemented in micro python.

  Are you sure? yes | no

Ted wrote 02/01/2019 at 04:26 point

I absolutely love it. I don't understand the "do it all from your mobile phone" idea. Especially when it comes to the basic stuff like play/pause and in the lighting world on/off.
If I could lock it into a specific chromecast I would have one in every room.

Another great project of the same nature you my have stumbled across.

Nice work

p.s. I like the knob better then the buttons of shivasiddharth version but he has a good idea in using LED colour to distinguish which casting device it is controlling.

  Are you sure? yes | no

Ákos Melczer wrote 02/01/2019 at 11:43 point

I'm glad you like my project. To distinguish between devices I use the first LED in the ring and also an animation while switching (each device has it's color). To make it lock to one specific device you set the configuration file only to one device. 

  Are you sure? yes | no

Mike Szczys wrote 01/29/2019 at 21:54 point

You have solved one of the problems currently on my "future projects" list. I've always wanted a standalone pause button for Chromecast. Thanks for writing about this and for making it open source. I'm going to dig in and build a version of my own!

  Are you sure? yes | no

Ákos Melczer wrote 01/30/2019 at 15:03 point

Thank you very much! Let me know if you need any help or clarification. I'm sure it wouldn't be hard to modify it to just to pause the playback.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates