Qué es exactamente un i-Buddy
El i-Buddy es un gadget USB de escritorio creado para Windows Live/MSN Messenger. Funcionalmente es un actuador físico de notificaciones: cabeza con LED RGB, corazón luminoso, alas móviles y giro del cuerpo. Clipset lo describía como un avatar USB que reaccionaba ante emoticonos del MSN mediante luces, movimiento, cambio de colores, alas, cabeza y corazón iluminado. (Clipset)
Desde el punto de vista de ingeniería, lo interesante es que el dispositivo no depende realmente de Messenger: se puede controlar como dispositivo USB HID enviándole comandos. La antigua librería iBuddyLib ya lo planteaba así: una librería .NET para controlar el i-Buddy desde código propio, con ejemplos como encender la cabeza en rojo o activar el corazón. (ibuddylib.sourceforge.net)
Capacidades físicas
El dispositivo permite controlar:
| Elemento | Control disponible |
|---|---|
| Cabeza | LED RGB: rojo, verde, azul y combinaciones: cian, amarillo, púrpura, blanco |
| Corazón | LED rojo encendido/apagado |
| Alas | Posición alta/baja, generando aleteo si se alterna |
| Cuerpo | Giro izquierda/derecha/centro |
| Alimentación | Por USB, sin batería |
Una ficha comercial antigua lo describe como una figura de unas 3 pulgadas, alimentada por USB, con corazón luminoso, alas que se mueven, cuerpo que gira y luces que cambian con emoticonos; también indica que era configurable y que funcionaba sobre USB 1.0/2.0. (usb.brando.com)
Identificación USB
La información más repetida en los proyectos técnicos es:
| Parámetro | Valor habitual |
|---|---|
| Vendor ID | 0x1130 |
| Fabricante USB | Tenx Technology |
| Product ID frecuentes | 0x0001, 0x0002, 0x0004, 0x0005 |
| Clase | HID / Human Interface Device |
MSXFAQ indica que en Windows se registra como dispositivo HID sin necesidad inicial de drivers específicos y que aparece con Vendor ID 0x1130 y Device ID 1 o 2. (MSXFAQ) El proyecto py3buddy declara soporte probado para 0x0001, 0x0002 y 0x0004, y menciona éxito reportado con el iBuddy Devil 0x0005; también señala rumores de dispositivos 0x0006. (GitHub)
Protocolo de control
El protocolo es muy simple: se envía primero una secuencia de preparación y después un comando de 8 bytes. El código de py3buddy documenta que cada comando arranca con:
55 53 42 43 00 40 02 XX
donde XX es el byte de control. (GitHub)
El módulo de kernel ibuddy-lkm confirma la misma estructura: usa como mensaje de preparación 22 09 00 02 01 00 00 00 y como comando base 55 53 42 43 00 40 02 FF, sustituyendo el último byte por el comando deseado. (GitHub)
La idea clave es que el último byte funciona con lógica activa en bajo: para activar una función, normalmente se pone a 0 el bit correspondiente. py3buddy documenta el reparto así: bit 7 para corazón, bits 4-6 para LED RGB de cabeza, bits 2-3 para alas y bits 0-1 para giro del cuerpo. (GitHub)
| Bits | Máscara | Función |
|---|---|---|
| Bit 7 | 0x80 | Corazón |
| Bit 4 | 0x10 | Rojo cabeza |
| Bit 5 | 0x20 | Verde cabeza |
| Bit 6 | 0x40 | Azul cabeza |
| Bits 2-3 | 0x0C | Alas |
| Bits 0-1 | 0x03 | Giro cuerpo |
Control con Python moderno
La vía más práctica hoy es Python + PyUSB + libusb, especialmente en Linux. PyUSB ofrece acceso USB desde Python y requiere una biblioteca nativa de backend como libusb; la versión publicada en PyPI como pyusb 1.3.1 requiere Python >=3.9 y un backend USB preinstalado. (PyPI)
Hay dos proyectos útiles:
- py3buddy: código Python 3 específico para i-Buddy, con demo, macros, DBus y reglas udev. Advierte expresamente de no dejar el dispositivo desatendido porque durante una prueba un i-Buddy llegó a empezar a quemarse. (GitHub)
- pybuddy: implementación Python antigua, tipo daemon, pensada para Linux y
python-usb, con ejemplos de uso para monitorización web, integración continua o notificaciones. (GitHub)
Ejemplo base en Python 3
Este ejemplo es una versión compacta para pruebas controladas en Linux. No lo dejaría ejecutándose en bucle indefinido sin supervisión.
#!/usr/bin/env python3
import time
import usb.core
VID = 0x1130
PIDS = [0x0001, 0x0002, 0x0004, 0x0005]
SETUP = bytes([0x22, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00])
PREFIX = bytes([0x55, 0x53, 0x42, 0x43, 0x00, 0x40, 0x02])
def find_ibuddy():
for pid in PIDS:
dev = usb.core.find(idVendor=VID, idProduct=pid)
if dev is not None:
print(f"i-Buddy encontrado: VID={VID:04x}, PID={pid:04x}")
return dev
raise RuntimeError("No se ha encontrado ningún i-Buddy compatible.")
def prepare_device(dev):
# En Linux, el driver HID del kernel puede reclamar interfaces.
for interface in (0, 1):
try:
if dev.is_kernel_driver_active(interface):
dev.detach_kernel_driver(interface)
except Exception:
pass
def build_command(
red=False,
green=False,
blue=False,
heart=False,
wings=None, # None, "high", "low"
twist=None # None, "left", "right", "middle", "reset"
):
cmd = 0xFF
# LEDs: activo en bajo
if heart:
cmd &= ~0x80
if red:
cmd &= ~0x10
if green:
cmd &= ~0x20
if blue:
cmd &= ~0x40
# Alas
cmd |= 0x0C
if wings == "high":
cmd &= ~0x08
elif wings == "low":
cmd &= ~0x04
# Giro
cmd |= 0x03
if twist == "left":
cmd &= ~0x02
elif twist == "right":
cmd &= ~0x01
elif twist == "middle":
cmd &= ~0x03
elif twist == "reset":
cmd |= 0x03
return cmd & 0xFF
def send(dev, cmd):
dev.ctrl_transfer(0x21, 0x09, 2, 1, SETUP)
dev.ctrl_transfer(0x21, 0x09, 2, 1, PREFIX + bytes([cmd]))
def reset(dev):
send(dev, 0xFF)
def demo(dev):
# Rojo + corazón
send(dev, build_command(red=True, heart=True))
time.sleep(0.5)
# Azul + alas arriba
send(dev, build_command(blue=True, wings="high"))
time.sleep(0.5)
# Verde + alas abajo + giro izquierda
send(dev, build_command(green=True, wings="low", twist="left"))
time.sleep(0.5)
# Blanco + giro derecha
send(dev, build_command(red=True, green=True, blue=True, twist="right"))
time.sleep(0.5)
reset(dev)
if __name__ == "__main__":
dev = find_ibuddy()
prepare_device(dev)
demo(dev)
Instalación recomendada en Linux
python3 -m venv .venv
source .venv/bin/activate
pip install pyusb
sudo apt install libusb-1.0-0
Regla udev sugerida:
sudo nano /etc/udev/rules.d/99-ibuddy.rules
Contenido:
SUBSYSTEM=="usb", ATTR{idVendor}=="1130", ATTR{idProduct}=="0001", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="1130", ATTR{idProduct}=="0002", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="1130", ATTR{idProduct}=="0004", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="1130", ATTR{idProduct}=="0005", MODE="0666"
Después:
sudo udevadm control --reload-rules
sudo udevadm trigger
py3buddy incluye precisamente una regla udev para los Product ID 0x0001, 0x0002, 0x0004 y 0x0005, pensada para colocarla en /etc/udev/rules.d/. (GitHub)
Alternativas de control
Windows
En Windows hay tres caminos:
- Librería .NET iBuddyLib: fue creada específicamente para controlar el i-Buddy desde código .NET, sin instalar drivers especiales porque Windows lo reconoce como HID. (ibuddylib.sourceforge.net)
- LibIBuddy: proyecto C# abierto que controla el i-Buddy y menciona una corrección importante relacionada con el calentamiento por inversión correcta de los bits de apagado. (GitHub)
- HIDAPI / HidSharp: opción más moderna si se quiere un controlador propio en C# o C/C++. HIDAPI es multiplataforma y permite acceder a dispositivos HID en Windows, Linux, FreeBSD y macOS. (GitHub)
Linux
Además de PyUSB, existe ibuddy-lkm, un módulo de kernel que crea una interfaz en /proc/driver/ibuddy/0 con atributos como heart, red, green, blue, wings y twist; escribir cualquier dato en esos ficheros conmuta la función correspondiente. (GitHub) Hoy lo consideraría más una referencia técnica que una solución recomendada, porque fue probado en Ubuntu 11.10 con kernel 3.0.0. (GitHub)
C / línea de comandos
El proyecto pbrier/ibuddy ofrece un programa de línea de comandos probado en Windows con MinGW. Su sintaxis permite enviar códigos como RGBHUDCA, donde las letras representan rojo, verde, azul, corazón, alas arriba/abajo y giro horario/antihorario. (GitHub)
Aplicaciones actuales interesantes
Para una aplicación moderna, yo no lo limitaría a mensajería. Lo usaría como indicador físico de estado:
| Caso de uso | Reacción propuesta |
|---|---|
| Compilación correcta | Cabeza verde |
| Error de test | Cabeza roja + alas |
| Reunión en curso | Corazón encendido fijo |
| Nuevo correo importante | Parpadeo amarillo |
| Alerta de servidor | Rojo + giro alterno |
| Estado docente/laboratorio | Verde disponible, rojo ocupado, azul en pausa |
La propia iBuddyLib proponía usos como notificación de correos, progreso de descargas, previsión meteorológica, fallos de servidor, pedidos en tienda online o carga del servidor. (ibuddylib.sourceforge.net)
Precauciones importantes
No lo dejaría funcionando sin vigilancia. py3buddy incluye una advertencia explícita: durante una prueba, un i-Buddy empezó a quemarse, por lo que recomiendan no ejecutarlo desatendido. (GitHub) Además, son dispositivos antiguos, con motores, bobinas o electroimanes y LEDs alimentados por USB, así que conviene evitar bucles rápidos, mantener pausas entre comandos y resetearlo al terminar.
Reprogramación 😉
El i-Buddy es un dispositivo muy aprovechable como actuador USB HID educativo. Su valor actual no está en Messenger, sino en que permite explicar de forma muy visual:
USB HID, control por software, bits activos en bajo, protocolos simples, actuadores físicos, notificaciones ambientales, integración Python-hardware y diseño de interfaces tangibles. Para clase o laboratorio, la mejor ruta práctica sería Linux + Python 3 + PyUSB, usando el protocolo documentado por py3buddy y empezando siempre con pruebas breves y supervisadas.
Reprogramación para Windows
Windows + Python 3 + PyUSB es viable, pero la parte delicada no es Python, sino el driver USB que Windows asocia al i-Buddy. Mi propuesta sería hacer un control sencillo, portable y seguro usando PyUSB + libusb 1.0 + WinUSB instalado con Zadig.
1. Arquitectura propuesta
i-Buddy USB
↓
Driver Windows: WinUSB / libusbK
↓
libusb 1.0
↓
PyUSB
↓
Módulo Python: ibuddy.py
↓
Aplicación: demo, notificador, GUI, integración docente, etc.
PyUSB necesita una biblioteca nativa de backend USB; actualmente PyUSB en PyPI indica que requiere Python >=3.9 y una biblioteca backend precompilada como libusb 1.x, libusb 0.1.x u OpenUSB. (PyPI)
Para Windows, la propia FAQ de PyUSB recomienda pyocd/libusb-package como forma cómoda de aportar la DLL de libusb 1.0, o copiar manualmente la DLL de una distribución oficial. (GitHub)
2. Instalación en Windows
Paso A: entorno Python
Recomiendo Python 3.11, 3.12 o 3.13 en 64 bits.
py -m venv .venv
.\.venv\Scripts\activate
python -m pip install --upgrade pip
pip install pyusb libusb-package
libusb-package es un paquete pensado precisamente para incluir bibliotecas compartidas de libusb y simplificar proyectos que usan PyUSB. (PyPI)
Paso B: driver con Zadig
Aquí está el punto importante. Aunque el i-Buddy aparece como HID, para controlarlo cómodamente desde PyUSB en Windows suele convenir asociarlo a WinUSB mediante Zadig.
Procedimiento recomendado:
- Conecta el i-Buddy.
- Abre Zadig como administrador.
- Menú Options → List All Devices.
- Selecciona el dispositivo Tenx / i-Buddy.
Debería aparecer conVID 1130y alguno de estos PID habituales:0001,0002,0004o0005. - Selecciona WinUSB como driver.
- Pulsa Replace Driver o Install Driver.
Zadig es una herramienta para instalar drivers genéricos USB en Windows, como WinUSB, libusb-win32 o libusbK, precisamente para acceder a dispositivos desde aplicaciones basadas en libusb. (zadig.akeo.ie) La documentación de libusb para Windows también recomienda Zadig y WinUSB como opción principal cuando se necesita comunicar con un dispositivo mediante libusb. (GitHub)
Precaución: cambiar el driver puede hacer que el software original del i-Buddy deje de reconocerlo hasta que reviertas el driver desde el Administrador de dispositivos.
3. Protocolo del i-Buddy
El i-Buddy usa comandos de control USB muy simples. La implementación Python 3 py3buddy documenta que el dispositivo se controla con:
setup: 22 09 00 02 01 00 00 00
comando: 55 53 42 43 00 40 02 XX
donde XX es el byte que codifica luces, alas y giro. (GitHub)
El reparto de bits es:
| Bit | Función | Lógica |
|---|---|---|
| 7 | Corazón | 0 = encendido, 1 = apagado |
| 6 | Azul cabeza | 0 = encendido |
| 5 | Verde cabeza | 0 = encendido |
| 4 | Rojo cabeza | 0 = encendido |
| 3-2 | Alas | combinaciones alta/baja |
| 1-0 | Giro | izquierda/derecha/centro |
Es decir: el dispositivo trabaja con lógica activa en bajo. Para encender algo, normalmente se borra su bit correspondiente.
4. Código base para Windows
Guarda esto como ibuddy_win.py.
import time
import usb.core
import usb.util
import usb.backend.libusb1
import libusb_package
VID = 0x1130
PIDS = (0x0001, 0x0002, 0x0004, 0x0005)
SETUP = bytes([0x22, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00])
PREFIX = bytes([0x55, 0x53, 0x42, 0x43, 0x00, 0x40, 0x02])
class IBuddy:
def __init__(self):
backend = usb.backend.libusb1.get_backend(
find_library=libusb_package.find_library
)
self.dev = None
self.pid = None
for pid in PIDS:
dev = usb.core.find(
idVendor=VID,
idProduct=pid,
backend=backend
)
if dev is not None:
self.dev = dev
self.pid = pid
break
if self.dev is None:
raise RuntimeError(
"No se ha encontrado el i-Buddy. "
"Comprueba conexión, VID/PID y driver WinUSB/Zadig."
)
self.command = 0xFF
self.send_raw(0xFF)
def send_raw(self, command_byte: int):
command_byte &= 0xFF
# bmRequestType=0x21, bRequest=0x09: HID Set_Report típico
self.dev.ctrl_transfer(0x21, 0x09, 2, 1, SETUP)
self.dev.ctrl_transfer(0x21, 0x09, 2, 1, PREFIX + bytes([command_byte]))
def apply(self):
self.send_raw(self.command)
def reset(self):
self.command = 0xFF
self.apply()
def heart(self, on: bool):
self.command |= 0x80
if on:
self.command &= ~0x80
self.apply()
def color(self, red=False, green=False, blue=False):
# Apagar primero los bits RGB
self.command |= 0x70
if red:
self.command &= ~0x10
if green:
self.command &= ~0x20
if blue:
self.command &= ~0x40
self.apply()
def wings(self, position: str):
"""
position: 'high', 'low' o 'neutral'
"""
self.command |= 0x0C
if position == "high":
self.command &= ~0x08
elif position == "low":
self.command &= ~0x04
elif position == "neutral":
pass
else:
raise ValueError("position debe ser 'high', 'low' o 'neutral'")
self.apply()
def twist(self, position: str):
"""
position: 'left', 'right', 'middle' o 'neutral'
"""
self.command |= 0x03
if position == "left":
self.command &= ~0x02
elif position == "right":
self.command &= ~0x01
elif position == "middle":
self.command &= ~0x03
elif position == "neutral":
pass
else:
raise ValueError("position debe ser 'left', 'right', 'middle' o 'neutral'")
self.apply()
def demo(self):
self.color(red=True)
self.heart(True)
time.sleep(0.5)
self.color(green=True)
self.wings("high")
time.sleep(0.5)
self.wings("low")
time.sleep(0.5)
self.color(blue=True)
self.twist("left")
time.sleep(0.5)
self.twist("right")
time.sleep(0.5)
self.reset()
if __name__ == "__main__":
buddy = IBuddy()
print(f"i-Buddy encontrado: VID={VID:04X}, PID={buddy.pid:04X}")
buddy.demo()
Ejecución:
python ibuddy_win.py
5. Prueba de diagnóstico
Antes de ejecutar el control, puedes comprobar si PyUSB ve el dispositivo:
import usb.core
import usb.backend.libusb1
import libusb_package
backend = usb.backend.libusb1.get_backend(
find_library=libusb_package.find_library
)
for dev in usb.core.find(find_all=True, backend=backend):
print(hex(dev.idVendor), hex(dev.idProduct))
Deberías ver algo parecido a:
0x1130 0x0001
o:
0x1130 0x0002
0x1130 0x0004
0x1130 0x0005
6. Errores típicos
| Error | Causa probable | Solución |
|---|---|---|
No backend available | Falta libusb-1.0.dll | Instalar libusb-package o copiar la DLL de libusb |
| El dispositivo no aparece | Windows lo mantiene como HID original | Usar Zadig y asociarlo a WinUSB |
Access denied | Driver incorrecto o proceso bloqueando el dispositivo | Reinstalar driver con Zadig, desconectar/conectar |
| No se mueve, pero no hay error | PID no contemplado o comandos no aceptados | Confirmar VID/PID con diagnóstico |
| Se calienta | Bucle de comandos demasiado agresivo | Añadir pausas, reset final y no dejarlo solo |
La FAQ de PyUSB indica que los errores de backend suelen deberse a que no está instalada la biblioteca libusb, no está en rutas de búsqueda, es demasiado antigua o PyUSB es demasiado antiguo. (GitHub)
7. Propuesta de estructura de proyecto
ibuddy-control/
│
├── ibuddy.py # Clase de bajo nivel
├── demo.py # Pruebas visuales
├── notifier.py # Notificaciones del sistema
├── requirements.txt
└── README.md
requirements.txt:
pyusb
libusb-package
8. Recomendación de ingeniería
Para una versión robusta en Windows, yo haría tres capas:
- Capa USB:
send_raw(), búsqueda VID/PID, backend libusb. - Capa dispositivo:
color(),heart(),wings(),twist(),reset(). - Capa aplicación: eventos del sistema, correo, compilación, estado de Teams, avisos docentes, etc.
Y pondría siempre estas reglas:
MIN_DELAY = 0.05 # mínimo entre comandos
MAX_DEMO_TIME = 30 # evitar bucles eternos
RESET_ON_EXIT = True
Además, conviene usar try/finally:
buddy = IBuddy()
try:
buddy.color(red=True)
buddy.heart(True)
time.sleep(2)
finally:
buddy.reset()
El proyecto py3buddy advierte que durante una prueba un i-Buddy empezó a quemarse, así que no conviene dejarlo funcionando sin supervisión ni con bucles rápidos de movimiento. (GitHub)
La propuesta final para entorno WINDOWS sería: WinUSB con Zadig + PyUSB + libusb-package + clase Python propia, evitando depender de software antiguo de MSN o librerías .NET obsoletas. Para docencia, es una combinación muy buena porque permite enseñar USB, drivers, protocolo binario, bits activos en bajo y control físico desde Python.