Controlar el puerto USB de la Raspberry Pi por software para encender y apagar dispositivos

ilustracion mostrando una placa raspberry un reloj de arena y un ventilador

El puerto USB de la Raspberry Pi no es solo para conectar dispositivos, si se utiliza de manera inteligente puede ser una alternativa para encender y apagar dispositivos. Eso abre una posibilidad que poca gente usa: controlar dispositivos de forma programática sin tocar los pines GPIO.

Este artículo documenta cómo llegué a esa solución, qué usé, y el código completo para replicarlo.

El problema

Tengo una Raspberry Pi 4 que hace dos cosas simultáneamente: transmite una estación de radio en línea las 24 horas y, desde este fin de semana, también corre un servidor VPN para que familiares en Venezuela puedan navegar sin restricciones a través de mi conexión de 1 gigabit en Lima.

La combinación de ambas cargas dispara la temperatura. La Pi tiene un ventilador de refrigeración activa montado directo sobre la CPU, pero aun así, en una hora de uso combinado la temperatura sube de 48°C a 56°C. Los picos más fuertes ocurren durante el tráfico VPN: breves, pero frecuentes.

El chasis es una caja plástica de envases de cotonetes, improvisada pero funcional: tiene orificios para ventilación y tornillos de montaje. El problema es que ninguno de mis ventiladores de 5V cabe dentro.

Controlar el puerto USB de la Raspberry Pi por software para encender y apagar dispositivos 1

Lo que sí tenía disponible: un ventilador grande de fuente de poder de 12V y un módulo Step-Up USB con potenciómetro para subir el voltaje desde los 5V del puerto USB hasta los 12V que necesita el ventilador.

Controlar el puerto USB de la Raspberry Pi por software para encender y apagar dispositivos 2

El ventilador conectado al Step-Up, el Step-Up conectado al USB. Faltaba resolver cómo encenderlo y apagarlo sin intervención manual.

Por qué el puerto USB y no los pines GPIO

Los pines GPIO son la respuesta obvia para controlar dispositivos en la Raspberry Pi. El problema es que los tengo ocupados: el ventilador de refrigeración activa está conectado ahí y no deja pines de 5V ni de 3.3V libres.

El puerto USB entrega 5V y se puede controlar por software en la Pi 4. No a nivel de puerto individual de forma nativa, sino a nivel de hub completo, pero en este caso es suficiente porque el ventilador es el único dispositivo USB conectado.

La herramienta: uhubctl

uhubctl es una utilidad de línea de comandos para Linux que permite encender y apagar puertos USB por software en hardware compatible. La Raspberry Pi 4 es compatible.

Instalación:

sudo apt update && sudo apt install uhubctl -y

Para ver qué hubs detecta en tu Pi:

sudo uhubctl

En mi caso la salida mostró tres hubs. El relevante es 1-1, que corresponde a los puertos USB 2.0 (los negros). Ahí está conectado el ventilador.

Prueba de funcionamiento:

# Apagar 
sudo uhubctl -l 1-1 -a off 

# Encender 
sudo uhubctl -l 1-1 -a on

Confirmado que el ventilador respondía, el siguiente paso fue automatizarlo.

La lógica de control

Despues de realizar varias pruebas de carga de trabajo encontré el punto optimo para evitar tener el ventidador todo el día encendido. La lógica quedó así:

  • Para encender: La temperatura supera los 52°C
  • Para apagar: La temperatura baja a 48°C o menos

El intervalo de chequeo varía según el estado:

  • Ventilador apagado: chequeo cada 5 minutos
  • Ventilador encendido: chequeo cada 30 segundos

Script principal: fan_control.py

Es el que corre como servicio. Lee la temperatura desde /sys/class/thermal/thermal_zone0/temp, aplica la lógica de encendido/apagado y registra cada evento en un log con timestamp. (Reemplaza ‘pizero’ por tu carpeta de usuario)

#!/usr/bin/env python3

import subprocess
import time
import logging
from datetime import datetime

# --- Configuracion ---
TEMP_ON      = 52.0   # Celsius: umbral de encendido
TEMP_OFF     = 48.0   # Celsius: umbral de apagado
INTERVAL_OFF = 300    # Segundos entre lecturas cuando ventilador apagado (5 min)
INTERVAL_ON  = 30     # Segundos entre lecturas cuando ventilador encendido (30 seg)
HUB          = "1-1"  # Hub USB del ventilador
LOG_FILE     = "/home/pizero/usb-fan/fan_control.log"

# --- Logger ---
logging.basicConfig(
    filename=LOG_FILE,
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)

def log(msg):
    logging.info(msg)
    print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} {msg}")

def get_temp():
    with open("/sys/class/thermal/thermal_zone0/temp", "r") as f:
        return int(f.read().strip()) / 1000.0

def set_usb(state):
    action = "on" if state else "off"
    subprocess.run(
        ["sudo", "uhubctl", "-l", HUB, "-a", action],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

def main():
    log("Servicio iniciado. Apagando USB al arranque.")
    set_usb(False)
    fan_on = False

    while True:
        try:
            temp = get_temp()

            if not fan_on:
                log(f"Temperatura: {temp:.1f}°C | Ventilador: OFF")

                if temp >= TEMP_ON:
                    set_usb(True)
                    fan_on = True
                    log(f"ENCENDIDO: temperatura {temp:.1f}°C supero {TEMP_ON}°C")

                time.sleep(INTERVAL_OFF)

            else:
                log(f"Temperatura: {temp:.1f}°C | Ventilador: ON")

                if temp <= TEMP_OFF:
                    set_usb(False)
                    fan_on = False
                    log(f"APAGADO: temperatura {temp:.1f}°C bajo a {TEMP_OFF}°C")

                time.sleep(INTERVAL_ON)

        except Exception as e:
            log(f"ERROR: {e}")
            time.sleep(INTERVAL_OFF)

if __name__ == "__main__":
    main()

Encendido manual:

sudo uhubctl -l 1-1 -a on

Apagado manual:

sudo uhubctl -l 1-1 -a off

Para instalarlos:

mkdir -p /home/pizero/usb-fan 
chmod +x /home/pizero/usb-fan/*.py

Instalación como servicio systemd

El servicio se llama usb-fan y arranca automáticamente con el sistema. Al iniciarse, apaga el puerto USB como primera acción para asegurarse de que el ventilador arranca en estado conocido.

Archivo del servicio: usb-fan.service

[Unit]
Description=Control de ventilador USB por temperatura
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/bin/python3 /home/pizero/usb-fan/fan_control.py
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

 Instalación:

sudo cp /home/pizero/usb-fan/usb-fan.service /etc/systemd/system/ 
sudo systemctl daemon-reload 
sudo systemctl enable usb-fan 
sudo systemctl start usb-fan

Comandos útiles:

# Estado del servicio 
sudo systemctl status usb-fan 

# Detener 
sudo systemctl stop usb-fan 

# Ver el log en tiempo real 
tail -f /home/pizero/usb-fan/fan_control.log

Estado actual y próximos pasos

El montaje actual es una prueba de concepto. Funciona, pero no es prolijo. Tengo en camino unos ventiladores comprados en AliExpress que voy a montar correctamente, con cableado limpio, cuando lleguen.

Lo que sí está validado: la estrategia funciona. El puerto USB como interruptor controlado por software es una alternativa real a los GPIO cuando estos no están disponibles, y uhubctl hace el trabajo sin complicaciones en la Raspberry Pi 4.

Santos R. Guerra F.