Proyecto 1: Comunicación Bi-direccional ESP32 - Computador

Proyecto elaborado por Mauricio Zuñiga, Javier Arredondo y Jeremías Carrasco de la Universidad de Viña del Mar en abril 2026.

Introducción

Este proyecto consiste en establecer una comunicación bi-direccional entre una placa ESP32 y un computador a través del puerto serial (USB). El objetivo es que un evento físico en el ESP32 (presionar un botón) dispare una acción en el computador, y que el computador pueda a su vez responder con una señal que el ESP32 traduce en una acción física (encender un LED).

En nuestra implementación, al presionar el botón el ESP32 avisa al computador por serial; la aplicación puente en el computador baja el brillo de la pantalla y, una vez hecho esto, le indica al ESP32 que encienda el LED como confirmación visual de que la acción se ejecutó correctamente.

Aprendizajes

  • Instalación y configuración del IDE y el SDK de ESP32.

  • Circuitos básicos de entrada (botón con pull-up) y salida (LED con resistencia limitadora).

  • Comunicación serial bi-direccional (UART sobre USB) entre un microcontrolador y un computador.

  • Lectura de botones con debounce para evitar falsos disparos.

  • Automatización de tareas del sistema operativo (control de brillo) desde una aplicación externa.

Descripción del Funcionamiento

  1. El usuario presiona el botón conectado al ESP32.

  2. El ESP32 detecta el flanco de bajada (con debounce) y envía el mensaje BTN_PRESS por el puerto serial.

  3. La aplicación puente, corriendo en el computador y escuchando ese puerto serial, recibe el mensaje y ejecuta la acción correspondiente: bajar el brillo de la pantalla.

  4. La aplicación puente responde al ESP32 con el mensaje LED_ON.

  5. El ESP32 recibe el mensaje y enciende el LED, confirmando visualmente que el ciclo se completó.

El protocolo es de mensajes de una línea terminados en \n (BTN_PRESS, LED_ON, LED_OFF), a 115200 baudios. Esto permite extender fácilmente el sistema a otras acciones sin cambiar la lógica base.

Lista de Componentes

Componente Descripción Cantidad

ESP32 (DevKit)

Microcontrolador encargado de leer el botón y controlar el LED, comunicado con el computador por USB.

1

LED

Indicador visual que se enciende cuando el computador confirma la acción (brillo bajado).

1

Botón pulsador

Genera el evento que dispara la comunicación hacia el computador.

1

Resistencia limitadora (~220-330 Ω)

Protege al LED de una corriente excesiva desde el GPIO.

1

Protoboard

Soporte para armar el circuito del botón y el LED.

1

Cables dupont

Conexiones entre el ESP32, el botón y el LED.

Varios

Cable USB

Conexión física y alimentación entre el ESP32 y el computador; por este mismo cable viaja la comunicación serial.

1

Esquemático y Tabla de Conexión

Función GPIO ESP32 Descripción

Botón pulsador

GPIO 4

Entrada digital (INPUT_PULLUP). Un extremo va al GPIO, el otro a GND; al presionar, el pin pasa de HIGH a LOW.

LED indicador

GPIO 2

Salida digital. Ánodo al GPIO a través de la resistencia limitadora, cátodo a GND.

Al usar INPUT_PULLUP en el botón no se necesita resistencia externa para esa entrada; el pull-up interno del ESP32 mantiene el pin en HIGH hasta que el botón lo conecta a GND.

Código

Firmware del ESP32

Sketch completo (proyecto1_esp32.ino) que implementa la lectura del botón con debounce y el control del LED según los comandos recibidos por serial.

Aplicación Puente (Computador)

Aplicación puente (proyecto1_puente.py) desarrollada en Python para Windows. Escucha el puerto serial del ESP32; al recibir BTN_PRESS alterna el brillo de la pantalla entre normal y bajo usando la librería screen-brightness-control, y responde al ESP32 con LED_ON o LED_OFF según corresponda.

Dependencias (instalar antes de ejecutar):

pip install pyserial screen-brightness-control
Antes de ejecutar, ajustar la constante PUERTO al puerto COM real donde el sistema operativo reconoce al ESP32 (visible en el Administrador de dispositivos de Windows).

Posibles Usos en la Industria

  • Indicadores físicos de estado en estaciones de trabajo (por ejemplo, un LED que señala "modo no molestar" o "grabando" activado desde software).

  • Automatización de oficina: gatillar acciones sobre luces o dispositivos físicos a partir de eventos del computador.

  • Interfaces físicas de accesibilidad: botones grandes que ejecutan funciones del sistema operativo para usuarios con movilidad reducida.

  • Confirmación visual en paneles de control industrial: un LED que confirma que el sistema recibió y procesó una orden.

  • Prototipado rápido de sistemas IoT/domótica que combinan hardware simple con lógica en el computador o en la nube.

Código del proyecto

project.ino
/*
  Proyecto 1: Comunicación bi-direccional ESP32 <-> Computador
  ---------------------------------------------------------------
  Flujo:
    1. El usuario presiona el botón conectado al ESP32.
    2. El ESP32 envía "BTN_PRESS" por el puerto serial (USB).
    3. La aplicación puente en el computador recibe el aviso, baja
       el brillo de la pantalla y responde con "LED_ON".
    4. El ESP32 enciende el LED al recibir "LED_ON".
    5. Un segundo click vuelve todo a su estado normal: el puente
       sube el brillo de nuevo y envía "LED_OFF".

  Protocolo serial (115200 baudios, mensajes de una línea, '\n' al final):
    ESP32 -> PC : "BTN_PRESS"
    PC -> ESP32 : "LED_ON" | "LED_OFF"
*/

const int PIN_BOTON = 4;   // Botón entre GPIO4 y GND (usa pull-up interno)
const int PIN_LED   = 2;   // LED + resistencia limitadora (~220-330 ohm) a GND

const unsigned long DEBOUNCE_MS = 50;

int estadoBotonAnterior = HIGH;
unsigned long ultimoCambio = 0;

String bufferSerial = "";

void setup() {
  Serial.begin(115200);
  pinMode(PIN_BOTON, INPUT_PULLUP);
  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);
}

void loop() {
  leerBoton();
  leerSerial();
}

// Detecta el flanco de bajada del botón (con debounce por tiempo)
// y avisa al computador.
void leerBoton() {
  int lectura = digitalRead(PIN_BOTON);

  if (lectura != estadoBotonAnterior) {
    ultimoCambio = millis();
  }

  if ((millis() - ultimoCambio) > DEBOUNCE_MS) {
    if (lectura == LOW && estadoBotonAnterior == HIGH) {
      Serial.println("BTN_PRESS");
    }
  }

  estadoBotonAnterior = lectura;
}

// Arma línea por línea lo que llega desde el computador y ejecuta
// el comando correspondiente sobre el LED.
void leerSerial() {
  while (Serial.available() > 0) {
    char c = Serial.read();

    if (c == '\n') {
      bufferSerial.trim();

      if (bufferSerial == "LED_ON") {
        digitalWrite(PIN_LED, HIGH);
      } else if (bufferSerial == "LED_OFF") {
        digitalWrite(PIN_LED, LOW);
      }

      bufferSerial = "";
    } else if (c != '\r') {
      bufferSerial += c;
    }
  }
}