WiFi Line Level Volume Control

Update 10-2020

So, there was a bit too much current coming from the TV and it was causing the chip to be overdriven. I put a resister inline with the input and that solved the issue. I have updated the drawings and the images. I used a variable resistor as I had to try a few values before I got it right. Carry on..

So I have these studio monitors… I also have a TV with crappy speakers. What could go wrong?

I wanted to use a set of studio monitors for my bedroom TV. The speakers in the TV suck and these monitors always sounded great. Here is the problem, the TV that I have will not allow me to control the line level volume out. I know what you are going to say, “get off my ass, get up and change the volume”. To that I say, “What is this 1970”? This is 2020, and there is no good reason to have to walk across the room to adjust the volume. The monitors have volume control as they are active, but a pain to get too.

So, I started by looking to see if there was already something on the market. I was thinking there had to be an inline IR remote controlled line level controller. Well, there is, but they all look cheeezzeee and had poor reviews. I know, I will just build something. Yeah, I know it will cost much more than a new set of speakers or a sound bar, but what fun is that?

I started to think and plan. What technology should I use? Should I build an IR receiver and program that to take commands from my existing remote? Could I use something else that might have other uses for home automation? HECK YES!

After some research, I found a digital potentiometer that looked promising. What should I use to control it? Should I design an embedded JSON based web app? That would require me to open a web page every time I want to change the volume. Nah.. I know, connect it to my existing Home Assistant server. Yeah. And I will use an ESP32 DevKitC board to control it. Yeah yeah. And I can use MQTT to publish the volume topic using a slider in Home Assistant and subscribe to the topic on the new device. yeah yeah yeah. It’s at this point that I try to hide my excitement from my wife. I know if she sees me geeking out, she will just laugh at me and tell me it will cost too much. Better to just keep this to myself for now…

So, here it is. In all of it’s glory.

Note, I am not going over setting up Home assistant or and MQTT server. Just know you will need at least one Raspberry Pi for that.

Here is the configuration.yaml and automations.yaml entires to create the device, the slider and publish to the MQTT server.

# ---- Add this section to the automations.yaml file in Home Assistant ----

# ---- Volume slider automation ----

- id: '1590287899999'
  alias: Bedroom Volume
  trigger:
  - entity_id: input_number.slider1
    platform: state
  action:
  - data_template:
      payload: '{{ states.input_number.slider1.state | int }}'
      retain: true
      topic: audio/volume
    service: mqtt.publish
  initial_state: true
# ---- Add these elements to the congiguration.yaml file ----


# -- Configure mqtt broker --
mqtt:
# The IP of your mqtt server goes below
  broker: xxx.xxx.xxx.xxx

# -- Setup slider --
input_number:
  slider1:
    name: Volume
    icon: mdi:speaker
    initial: 30
    min: 1
    max: 127
    step: 1
    unit_of_measurement: "%"  

That will do it for Home Assistant configuration.

I used C to write the code for the microcontroller. I have been learning Micropython, and I may re-code it at some point as a fun project(I did give it a try, but it was taking to long to learn and code). As I mentioned, I used an ESP32 DevKit C Ver4 for the microcontroller board.

Here is the Schematic:

I used RCA jacks as they match the TV and the monitors have RCA as well.

Here is the code:

//ESP32 Code

//* This code is for a line level Wi-Fi volume controller to be used with Home Assistant *//

#include <WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>

// Update these variables.

const char* ssid = "........."; // Your SSID 
const char* password = "........."; // Your Wi-Fi password
const char* mqtt_server = "..........."; // Your MQTT broker
const char* mqtt_topic = "............"; // You can leave this topic or change if you would like If you change, you will need to update your Home Assistant automation topic
const char* mqtt_client_id = ".............."; // Name for this device on your MQTT network
int ChipSelect = 5; // SS or CS Pin (GPIO) on your board. On the ESP32 DEVKIT C V4, the CS pin in GPIO5

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.println();
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");

   payload[length] = '\0'; // Add a NULL to the end of the char* to make it a string.
   int volume = atoi((char *)payload);
   
  Serial.print(volume);
  writeMCP4241(0,volume);
  writeMCP4241(1,volume);
}

void writeMCP4241(byte address, char value) {
  digitalWrite(ChipSelect, LOW); 
  SPI.transfer(address << 4);
  SPI.transfer(value & 127);
  digitalWrite(ChipSelect, HIGH);
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = mqtt_client_id;
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      client.subscribe(mqtt_topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(ChipSelect, OUTPUT); 
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  Serial.println(SS);
  Serial.println(MISO);
  Serial.println(SCK);
  SPI.begin();
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

I created the PCB Gerber files and sent them off to JLCPCB to make. I still can’t believe how fast and how cheap it is to have them made. If you would like a copy of the Gerber file to make your own, just let me know and I will email it to you. I can’t post zip files on WordPress. Ugh

And that’s it! Now I can control my bedroom TV volume with a slider in the Home Assistant app on my phone. Works like a champ. The only issue I have run into is that my wife can also control the volume at the same time. There are some “limitations”. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.