ESP32 Steuerungsbox für Videokonferenzen (Stummschaltung, Kamera, Ton, Hand heben, etc.)

Besonders im Moment, wenn viele Videokonferenzen von Zuhause stattfinden und zum Reden immer wieder die Stummschaltung aufgehoben oder vorher die Hand gehoben werden muss, wäre eine kleine Steuerungsbox doch sehr hilfreich.

Nun, das habe ich mir auch gedacht und mich direkt Mal an eine Lösung für verschiedene Videokonferenz-Tools gemacht. Sie funktioniert mit Microsoft Teams, Zoom und jeder anderen Software, die Shortcuts für die Steuerung der gewünschten Funktionen nutzt.

Doch bevor ich weiter auf die Funktionsweise eingehe, liste ich hier erst einmal auf, was du benötigst um das Projekt nachzubauen:

  • ein ESP32-Entwicklerboard
  • ein Micro USB Kabel
  • MTS-102 Kippschalter (oder beliebig andere Schalter, in meinem Modell nutze ich aber solche Modelle, da ich sie am praktischsten finde)
  • zwei Mal einen kapazitiven Touch-Sensor (TTP223)
  • GPIO Jumper Kabel
  • Header Pins
  • GPIO Pins
  • Micro USB zu DIP Adapter
  • ggf. einen 3D Drucker, wenn du ein Gehäuse drucken möchtest
  • einen PC mit einer für den ESP32 eingerichteten Entwicklungsumgebung (in diesem Beispiel mit der Arduino IDE)

Funktionsweise der Steuerungsbox

Doch wie soll das ganze überhaupt funktionieren? Der ESP32 wird so programmiert, dass er als Bluetooth-Tastatur für einen Computer funktioniert. In diesem Beispiel habe ich es mit einem Bluetooth-fähigen Windows-PC getestet, für einen Mac oder Linux müsste der Code entsprechend angepasst werden. Dann werden von dem ESP32 beim Umlegen der Schalter die entsprechenden Shortcuts emuliert, die von MS Teams, Zoom, etc. genutzt werden. Dafür muss sich dann das Fenster mit der Videokonferenz im Fokus befinden, damit die Befehle funktionieren.

Programmierung

Du musst als erstes die nötige Bibliothek hier herunterladen und in der Arduino IDE (oder deiner bevorzugten Entwicklungsumgebung) einbinden. Du musst dann noch gegebenenfalls die Pins anpassen, an denen du die Schalter angeschlossen hast. Im folgenden Quellcode ist auch die Möglichkeit gegeben, noch eine Neopixel-LED anzuschließen, um gegebenenfalls direkt an der Steuerungsbox Feedback mit Farben zu geben. Standardmäßig sind diese Teile des Codes aber auskommentiert. In der Programmierung sieht das dann so aus:

#include <BleKeyboard.h>
//#include <Adafruit_NeoPixel.h>

BleKeyboard bleKeyboard("Konferenz-Box", "Bloggingwelt", 100);
//Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, 13, NEO_GRB + NEO_KHZ800);

const int DEBOUNCE_DELAY_MUTE = 50;
unsigned long lastDebounceTimeMute = 0;

const int DEBOUNCE_DELAY_CAM = 50;
unsigned long lastDebounceTimeCam = 0;

const int DEBOUNCE_DELAY_RAISE = 50;
unsigned long lastDebounceTimeRaise = 0;

const int DEBOUNCE_DELAY_MEDIAOUT = 50;
unsigned long lastDebounceTimeMediaout = 0;

const int mutePin = 19;
const int camPin = 21;
const int raisePin = 5;
const int mediaoutPin = 18;
const int endPin = 25;
const int lockPin = 26;

int lastSteadyStateMute = LOW;
int lastFlickerableStateMute = LOW;
int currentStateMute;

int lastSteadyStateCam = LOW;
int lastFlickerableStateCam = LOW;
int currentStateCam;

int lastSteadyStateRaise = LOW;
int lastFlickerableStateRaise = LOW;
int currentStateRaise;

int lastSteadyStateMediaout = LOW;
int lastFlickerableStateMediaout = LOW;
int currentStateMediaout;

void setup() {
  Serial.begin(115200);
  pinMode(mutePin, INPUT_PULLUP);
  pinMode(camPin, INPUT_PULLUP);
  pinMode(raisePin, INPUT_PULLUP);
  pinMode(mediaoutPin, INPUT_PULLUP);
  pinMode(endPin, INPUT_PULLUP);
  pinMode(lockPin, INPUT_PULLUP);
  bleKeyboard.begin();
  /*pixels.begin();
  pixels.setPixelColor(0, 0, 255, 0);
  pixels.show();*/
}

void loop() {
  if(bleKeyboard.isConnected()) {
    currentStateMute = digitalRead(mutePin);
    currentStateCam = digitalRead(camPin);
    currentStateRaise = digitalRead(raisePin);
    currentStateMediaout = digitalRead(mediaoutPin);
    //Mute-Button
    if (currentStateMute != lastFlickerableStateMute) {
      lastDebounceTimeMute = millis();
      lastFlickerableStateMute = currentStateMute;
    }
    if ((millis() - lastDebounceTimeMute) > DEBOUNCE_DELAY_MUTE) {
      if((lastSteadyStateMute == HIGH && currentStateMute == LOW) || (lastSteadyStateMute == LOW && currentStateMute == HIGH)) {
          bleKeyboard.press(KEY_LEFT_CTRL);
          bleKeyboard.press(KEY_LEFT_SHIFT);
          bleKeyboard.print("m");
          delay(50);
          bleKeyboard.releaseAll();
          /*pixels.setPixelColor(0, 0, 128, 255);
          pixels.show();
          delay(500);
          pixels.setPixelColor(0, 0, 255, 0);
          pixels.show();*/
      }
      lastSteadyStateMute = currentStateMute;
    }
    //Cam-Button
    if (currentStateCam != lastFlickerableStateCam) {
      lastDebounceTimeCam = millis();
      lastFlickerableStateCam = currentStateCam;
    }
    if ((millis() - lastDebounceTimeCam) > DEBOUNCE_DELAY_CAM) {
      if((lastSteadyStateCam == HIGH && currentStateCam == LOW) || (lastSteadyStateCam == LOW && currentStateCam == HIGH)) {
          bleKeyboard.press(KEY_LEFT_CTRL);
          bleKeyboard.press(KEY_LEFT_SHIFT);
          bleKeyboard.print("o");
          delay(50);
          bleKeyboard.releaseAll();
          /*pixels.setPixelColor(0, 0, 128, 255);
          pixels.show();
          delay(500);
          pixels.setPixelColor(0, 0, 255, 0);
          pixels.show();*/
      }
      lastSteadyStateCam = currentStateCam;
    }
    //Raise-Hand-Button
    if (currentStateRaise != lastFlickerableStateRaise) {
      lastDebounceTimeRaise = millis();
      lastFlickerableStateRaise = currentStateRaise;
    }
    if ((millis() - lastDebounceTimeRaise) > DEBOUNCE_DELAY_RAISE) {
      if((lastSteadyStateRaise == HIGH && currentStateRaise == LOW) || (lastSteadyStateRaise == LOW && currentStateRaise == HIGH)) {
          bleKeyboard.press(KEY_LEFT_CTRL);
          bleKeyboard.press(KEY_LEFT_SHIFT);
          bleKeyboard.print("k");
          delay(50);
          bleKeyboard.releaseAll();
          /*pixels.setPixelColor(0, 0, 128, 255);
          pixels.show();
          delay(500);
          pixels.setPixelColor(0, 0, 255, 0);
          pixels.show();*/
      }
      lastSteadyStateRaise = currentStateRaise;
    }
    //Mediaoutput-Button
    if (currentStateMediaout != lastFlickerableStateMediaout) {
      lastDebounceTimeMediaout = millis();
      lastFlickerableStateMediaout = currentStateMediaout;
    }
    if ((millis() - lastDebounceTimeMediaout) > DEBOUNCE_DELAY_MEDIAOUT) {
      if((lastSteadyStateMediaout == HIGH && currentStateMediaout == LOW) || (lastSteadyStateMediaout == LOW && currentStateMediaout == HIGH)) {
          bleKeyboard.press(KEY_MEDIA_MUTE);
          delay(50);
          bleKeyboard.releaseAll();
          /*pixels.setPixelColor(0, 0, 128, 255);
          pixels.show();
          delay(500);
          pixels.setPixelColor(0, 0, 255, 0);
          pixels.show();*/
      }
      lastSteadyStateMediaout = currentStateMediaout;
    }
    //End-Call-Button
    if(digitalRead(endPin) == HIGH) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press(KEY_LEFT_SHIFT);
      bleKeyboard.print("b");
      delay(50);
      bleKeyboard.releaseAll();
      /*pixels.setPixelColor(0, 255, 0, 255);
      pixels.show();
      delay(800);
      pixels.setPixelColor(0, 0, 255, 0);
      pixels.show();*/
    }
    //Lock-Screen-Button
    if(digitalRead(lockPin) == HIGH){
      bleKeyboard.press(KEY_LEFT_GUI);
      bleKeyboard.print("l");
      delay(50);
      bleKeyboard.releaseAll();
      /*pixels.setPixelColor(0, 255, 128, 0);
      pixels.show();
      delay(800);
      pixels.setPixelColor(0, 0, 255, 0);
      pixels.show();*/
    }
  }
}Code-Sprache: PHP (php)

Diesen Code kannst du dann kompilieren und auf den ESP32 aufspielen.

Elektronik der Steuerungsbox

Mit den oben ausgeführten Bauteilen lässt sich die Kontrollbox einfach nachbauen. Natürlich kannst du es auch mit weniger Schaltern umsetzen, je nachdem, welche Funktionen du benötigst.

Für die Kippschalter muss jeweils eine Verbindung zwischen Ground und einem Pin des ESP32 hergestellt werden. Dafür verbindest du einfach einen von zwei nebeneinanderliegenden Kontakten am Schalter mit zum Beispiel Pin 19 am Mikrocontroller. Die Kabel zu Ground kannst du auch wie auf dem unten zu sehenden Foto gezeigt, jeweils zwischen den Schaltern verbinden und nur den letzen Schalter an den Mikrocontroller. Die Enden der Kabel, die zum ESP32 gehen, kannst du jeweils mit einem Header Pin ausstatten, um sie einfach auf den Mikrocontroller aufstecken zu können.

Verkabelung an den Schaltern (mit etwas schlechten Lötverbindungen von mir 😉)

Für die kapazitiven Touch-Sensoren benötigst du eine Spannungsversorgung (3,3V), einen Kontakt zu Ground und einen Pin für das Signal. Dafür musst du als erstes jeweils die 3 GPIO Pins auf die Kontakte an den Sensoren löten. Dann kannst du ganz einfache GPIO Kabel nutzen, um sie mit dem ESP32 zu verbinden.

Um jetzt noch den Micro USB Port des ESP32 einfacher zugänglich zu machen, empfehle ich dir, einen Kontakt zu einem Mirco USB zu DIP Adapter herzustellen. Dafür kannst du einfach wieder die GPIO Pins auf den Adapter löten und dann mit GPIO Kabeln 5V mit VBUS und GND mit GND verbinden. Zwischen dem Kabel mit der Spannungsversorgung kannst du dann auch einen weiteren Kippschalter, so wie es bei mir der linke ist, einbauen, um die Box einfach ein- und ausschalten zu können.

Jetzt hast du die gesamte Elektronik abgeschlossen und kannst sie in ein Gehäuse verpacken. Die Elektronik darin könnte dann so aussehen:

Um alles im Gehäuse zu halten, kannst du dann hinten mit etwas Klebeband nachhelfen:

Gehäuse aus dem 3D Drucker

So sieht mein Gehäuse aus:

Gehäuse von innen
Gehäuse von innen
Gehäuse von außen
Gehäuse von außen

Um das Projekt damit jetzt noch schön zu verpacken kannst du folgende stl-Datei herunterladen und ausdrucken:

Das Endergebnis sieht bei mir dann so aus:

Fertige Box
Endergebnis

Das lässt sich dann beispielsweise an einen Schreibtisch montieren:

Und das war‘s schon! Jetzt hast du eine neue Möglichkeit, deine Videokonferenzen bequem zu steuern. Ich würde mich sehr freuen, wenn du mir deine Erfahrungen damit in einem Kommentar mitteilst. Verbesserungsvorschläge sind natürlich auch immer willkommen ;-).

Hinweis: Mit Sternchen (*) markierte Links auf dieser Seite sind Werbelinks. Beim Kauf darüber erhalte ich eine kleine Provision, der Preis bleibt für dich aber gleich. Damit unterstützt du mich, sodass ich weiterhin kostenlosen Inhalt auf diesem Blog anbieten kann ;-).

Wie findest du die Steuerungsbox? Hinterlasse doch gerne einen Kommentar!

Bitte bedenke, dass alle Kommentare manuell freigeschaltet werden müssen. Das kann teilweise ein bisschen dauern, du kannst dich aber mit der unten aufgeführten Funktion benachrichtigen lassen, wenn er beantwortet wurde. Das heißt auch, dass Beleidigungen, Spam oder pure Werbung keine Chance haben, auf die Website zu kommen. Deine Email-Adresse wird selbstverständlich nicht veröffentlicht. Erforderliche Felder sind mit * oder (erforderlich) markiert.