Convertí una impresora vieja en WiFi e INTELIGENTE con un mini router, OpenWRT y Home Assistant

Casa inteligente Video
Convertí una impresora vieja en WiFi e INTELIGENTE con un mini router, OpenWRT y Home Assistant

Cansado de sacar la impresora del armario cada vez que necesitaba imprimir, me acordé de un mini router que tenía guardado y terminé en un proyecto que me llevó bastante más de lo esperado. Pero valió la pena.

Todo el detalle está en el video de YouTube, este post es un write-up para el que lo quiera hacer.

Buscando entre mis cosas, encontré un TP-Link TL-WR703N. Este mini router estaba pensado para compartir internet cuando se usaban los módems 3G USB.

TP-Link TL-WR703N

Especificaciones
CPUAtheros AR7240 (400 MHz)
ChipsetAtheros AR9331 (wireless integrada)
WiFi802.11 b/g/n 150 Mbps (130 Mbps real)
Potencia wireless20 dBm – 100 mW
Memoria flash4 MB
RAM32 MB
Dimensiones5.7 cm × 5.7 cm × 1.8 cm
Puerto LAN1
Puerto USB1 × USB 2.0
AlimentaciónMicro-USB
LED1

El modelo venía con el firmware solo en idioma chino, así que en esa época le instalé OpenWRT. TP-Link TL-WR703N

Versión de OpenWRT que tenía instalada el router desde la última vez que lo usé.

El problema: la última versión oficial de OpenWRT para este router es la 19, porque dejaron de soportar dispositivos con 4MB de almacenamiento. Todo lo que vino después requiere más espacio.

Cambio de memoria SPI Flash: de 4MB a 16MB

Para poder instalar versiones más recientes de OpenWRT, tuve que cambiar la memoria SPI flash (básicamente el “disco” del router) por una de 16MB.

Para hacer esto, tuve que comprar algunas cosas que no tenía:

Materiales necesarios

  • Memoria SPI flash W25Q128FVSIG (16MB): el modelo exacto o similares → Mercado Libre
  • Programador CH341A: el más barato y que funciona para estas memorias, sirve para leer y escribir el chip → Mercado Libre
  • Pinzas ESD antiestáticas: para sujetar el chip al desoldar sin armar desastre → Mercado Libre

Adaptar el dump original a la nueva memoria

Primero tenemos que hacer el dump de la memoria original, utilicé la aplicación oficial del programador CH341A pero recomiendo utilizar NeoProgrammer (repo acá) ya que me dió mejores resultados a la hora de la escritura (gracias @FreeForge11 en X por la recomendación).

Una vez guardado el dump, extendemos la partición del firmware para que complete los 16MB de la memoria. Además, cambiamos el uboot por el de pepe2k (repo acá), que no es el bootloader original pero es necesario para que tome la nueva memoria.

Para hacer estas modificaciones al binario usé HxD (sitio oficial), un editor hexadecimal que permite editar los archivos byte a byte.

Compilar OpenWRT 23 para el TL-WR703N

Agradecimiento a este post que utilicé para hacer la compilación de OpenWRT: Build OpenWRT 22/23 for TL-WR703N with 16M Flash y también al amigo Cocus que estuvo detrás de todo este caos dando una mano.

Compartos los pasos que utilicé en particular del post anterior:

Primero y principal, leer e instalar lo necesario para OpenWRT.

Una vez que está todo instalado, arrancamos con el procedimiento;

1. Clonar el repositorio de OpenWrt

git clone https://github.com/openwrt/openwrt.git
cd openwrt

2. Hacer checkout de la versión a compilar

git tag -l
git checkout v23.05.6

Antes de instalar los feeds, modifiqué el archivo feeds.conf.default con los siguientes registros (los que vienen por defecto funcionan recontra lento):

src-git packages https://github.com/openwrt/packages.git^e59d9ef823bcb581e3939789b4eaeaf900b79759
src-git luci https://github.com/openwrt/luci.git^7ce34fe1a53db10bb9dd0223467f5bb71a29a659
src-git routing https://github.com/openwrt/routing.git^4a06b031dc16628c9b8351ac297ecdbc92695dc2
src-git telephony https://github.com/openwrt/telephony.git^98c8a5aa4624312ed758e2e2b6d4039050a1649d

Ahora sí instalamos los feeds:

./scripts/feeds update -a
./scripts/feeds install -a

Verificar que no haya errores de dependencias.

3. Modificar la definición Device/tplink_tl-wr703n

Editar el archivo target/linux/ath79/image/tiny-tp-link.mk. Buscar la línea define Device/tplink_tl-wr703n y cambiar $(Device/tplink-4mlzma) por $(Device/tplink-16mlzma) (para memoria de 16MB). El resultado debe quedar así:

define Device/tplink_tl-wr703n
  $(Device/tplink-16mlzma)
  SOC := ar9331            
  DEVICE_MODEL := TL-WR703N                            
  DEVICE_PACKAGES := kmod-usb-chipidea2
  TPLINK_HWID := 0x07030101
  SUPPORTED_DEVICES += tl-wr703n     
endef
TARGET_DEVICES += tplink_tl-wr703n

4. Modificar el archivo dts para 16MB de flash

Editar target/linux/ath79/dts/ar9331_tplink_tl-wr703n_tl-mr10u.dtsi:

  • En partition@20000 { cambiar reg = <0x20000 0x3d0000>; por reg = <0x20000 0xfd0000>;
  • Cambiar art: partition@3f0000 { por art: partition@ff0000 {
  • Debajo de eso, cambiar reg = <0x3f0000 0x10000>; por reg = <0xff0000 0x10000>;

El resultado debe quedar así:

&spi {                  
        status = "okay";
                                             
        flash@0 {                            
                compatible = "jedec,spi-nor";  
                reg = <0>;                     
                spi-max-frequency = <25000000>;
                                                        
                partitions {                            
                        compatible = "fixed-partitions";
                        #address-cells = <1>;
                        #size-cells = <1>;  
                                                    
                        uboot: partition@0 {        
                                reg = <0x0 0x20000>;
                                label = "u-boot";
                                read-only;
                        };                                     
                                                               
                        partition@20000 {                      
                                compatible = "tplink,firmware";
                                reg = <0x20000 0xfd0000>;
                                label = "firmware";
                        };                               
                                                         
                        art: partition@ff0000 {          
                                reg = <0xff0000 0x10000>;
                                label = "art";
                                read-only;
                        };
                };
        };
};

5. Configurar el build

Descargar el config.buildinfo para OpenWrt v23.05.6:

wget https://downloads.openwrt.org/releases/23.05.6/targets/ath79/tiny/config.buildinfo -O config.buildinfo

Agregar las siguientes líneas al config.buildinfo:

CONFIG_TARGET_DEVICE_ath79_tiny_DEVICE_tl-wr703n-v1=y
CONFIG_TARGET_DEVICE_PACKAGES_ath79_tiny_DEVICE_tl-wr703n-v1=""

Y estos paquetes que son clave para mi caso del print server:

CONFIG_PACKAGE_kmod-usb-core=y
CONFIG_PACKAGE_kmod-usb-printer=y    # crea /dev/usb/lp0
CONFIG_PACKAGE_p910nd=y              # el print server
CONFIG_PACKAGE_luci-app-p910nd=y     # interfaz web para p910nd
CONFIG_PACKAGE_libusb-1.0=y

Sobreescribir .config con config.buildinfo. Deberías ver TL-WR703N en la lista de Target Devices:

cat config.buildinfo > .config
make defconfig
make menuconfig

Antes de hacer el build, les recomiendo destildar la opción Build the LLVM-BPF toolchain tarball ya que a mi me trajo errores a la hora de buildear. OpenWRT menuconfig

Comencemos el build, esto va a tomar bastante tiempo como dice el post original pueden ser bastantes minutos o incluso horas.

nohup time make -j8 V=s &

Se puede ver en tiempo real como va el proceso con este comando:

tail -f nohup.out

Una vez terminado el build, tenemos que subir el firmware al router.

Flashear el firmware via web (método pepe2k)

Una de las ventajas del uboot de pepe2k es que incluye un servidor web integrado que permite subir el firmware directamente desde el navegador, sin necesidad de consola serie ni servidor TFTP.

  1. Conectar el router al PC con un cable de red por el puerto LAN
  2. Configurar la IP del PC manualmente: 192.168.1.2 con máscara 255.255.255.0
  3. Encender el router manteniendo presionado el botón de reset hasta que el LED parpadee (unos 3 segundos)
  4. Abrir el navegador y entrar a http://192.168.1.1
  5. Va a aparecer una página simple con un formulario de carga de archivo
  6. Seleccionar el archivo .bin del firmware compilado (el sysupgrade o factory)
  7. Hacer click en el botón para iniciar la escritura y esperar que el router reinicie solo pepe2k-web Así se ve la web del uboot de pepe2k para subir el firmware compilado. Una vez que reinicia ya tiene el nuevo OpenWRT corriendo.

La arquitectura: CUPS + p910nd

Como el router tiene poca RAM (32MB), desistí con la idea de correr CUPS ahí dentro. La arquitectura final quedó así: Plan final

[Cliente]  →IPP→  [CUPS / Home Server]  →TCP 9100→  [p910nd / Router]  →USB→  [HP P1005]

¿Por qué no CUPS directo en el router?

La HP P1005 requiere el driver foo2zjs, que a su vez depende de ghostscript para convertir PDF/PS. El binario de ghostscript ocupa ~15MB. El TL-WR703N tiene 4MB de flash total. Es imposible.

¿Qué hace p910nd?

p910nd es un proxy extremadamente liviano (~15KB, sin dependencias) que hace exactamente una cosa: abre el puerto TCP 9100 y reenvía cada byte que recibe hacia el dispositivo USB configurado (/dev/usb/lp0), y viceversa. No interpreta nada. Es un puente bidireccional puro.

ComponenteProtocoloPuerto
CUPS (clientes)IPP/IPPS631
CUPS → p910ndAppSocket (raw TCP)9100
p910nd → impresoraUSB printer class

La HP LaserJet P1005 y el firmware correcto

HP LaserJet P1005

Un cañito esta impresora, vieja pero se la banca.

Esta impresora es host-based (también llamada GDI o “winprinter”): no tiene procesador ni firmware propio almacenado en ROM. Al conectarla por USB, el sistema operativo del host debe enviarle un archivo de firmware antes de que pueda recibir trabajos de impresión.

El firmware se pierde cada vez que la impresora se desconecta o apaga. Hay que cargarlo de nuevo en cada conexión.

El USB ID de la impresora nunca cambia (03f0:3d17). Lo que cambia es el Device ID IEEE 1284:

Sin firmware:  CMD:ACL
Con firmware:  CMD:HBS,PJL,ACL;FWVER:20080415

La clave estaba en usar el firmware correcto. Hay dos versiones del archivo sihpP1005.dl dando vueltas:

OrigenTamañoMD5Funciona
printer-driver-foo2zjs222.443 bytesed18611a9c0c6c23b97d8c543fb2ec79✓ Sí
Plugin HPLIP116.925 bytes63f5696df7175af70cdfbf56126336ce✗ No

El firmware que funciona es el del paquete foo2zjs (open source), no el plugin propietario de HPLIP.

Cómo obtenerlo:

Opción 1: desde un sistema Debian/Ubuntu con el paquete instalado

sudo apt install printer-driver-foo2zjs
# El archivo queda en: /usr/lib/firmware/hp/sihpP1005.dl

Opción 2: descargar con el script del proyecto foo2zjs

git clone https://github.com/koenkooi/foo2zjs
cd foo2zjs
./getweb P1005
# → crea sihpP1005.dl en el directorio actual

Verificar siempre el MD5 antes de usar:

md5sum sihpP1005.dl
# debe mostrar: ed18611a9c0c6c23b97d8c543fb2ec79

Configurar OpenWRT y p910nd

Copiar el firmware de la impresora al router

# Desde la máquina que tiene el archivo:
scp -O sihpP1005.dl root@IP-DEL-ROUTER:/lib/firmware/sihpP1005.dl

# Verificar en el router:
md5sum /lib/firmware/sihpP1005.dl
# → ed18611a9c0c6c23b97d8c543fb2ec79

Configurar p910nd

Archivo /etc/config/p910nd en el router:

config p910nd
    option device         '/dev/usb/lp0'
    option port           '0'
    option bidirectional  '1'
    option enabled        '1'
    option runas_root     '1'
    option usbvidpid      '03f0/3d17'
    option driver_file    '/lib/firmware/sihpP1005.dl'

Luego ejecutar:

/etc/init.d/p910nd restart
/etc/init.d/p910nd enable

Opciones críticas

OpciónValorPor qué
bidirectional1La P1005 usa protocolo bidireccional. Sin esto, CUPS puede reportar errores falsos.
usbvidpid03f0/3d17El USB ID de la P1005. Nunca es 3e17 (ese es el de la P1006). Si está mal, el hotplug nunca dispara.
driver_file/lib/firmware/sihpP1005.dlp910nd carga el firmware automáticamente al detectar la impresora vía hotplug.

Al conectar la impresora al router, los logs deben mostrar:

daemon.info p910nd hotplug: Sending driver to p910nd printer 03f0/3d17
daemon.info p910nd hotplug: Sent /lib/firmware/sihpP1005.dl to /dev/usb/lp0 [ 03f0/3d17 ]
daemon.info p910nd hotplug: (Re)starting p910nd
# Verificar con:
logread | grep p910nd

CUPS en un contenedor

La instalación de CUPS es sencilla; lo tengo corriendo en un contenedor. Uso una imagen customizada donde ya dejé preinstalados los drivers foomatic, que son clave para esta impresora:

Repo: https://github.com/Pocho-Labs/cups-avahi-airprint

Ahí también van a encontrar recursos sobre cómo agregar drivers o correrlo como contenedor.

Configuración de reintentos en CUPS

Como la impresora y el router están apagados la mayor parte del tiempo, necesitamos que CUPS reintente el trabajo mientras todo se está encendiendo. Esto va en /etc/cups/cupsd.conf:

ErrorPolicy retry-job
JobRetryInterval 30
JobRetryLimit 20

Con esta configuración, CUPS tiene hasta 10 minutos (20 reintentos × 30 segundos) para que el router levante y cargue el firmware de la impresora antes de descartar el trabajo.

Agregar la impresora en CUPS

Por interfaz web (recomendado para la primera vez):

  1. Abrir la interfaz web de CUPS (por defecto en el puerto 631)
  2. Administración → Añadir impresora
  3. Seleccionar AppSocket/HP JetDirect
  4. En conexión poner: socket://IP-DEL-ROUTER:9100
  5. Poner nombre y descripción
  6. Tildar Compartición
  7. En el último paso seleccionar el driver HP LaserJet P1005 Foomatic/foo2zjs y añadir

Automatización con Home Assistant

Con todo andando, quería aprovechar y automatizar el encendido. Para eso usé:

  • Enchufe inteligente: link - ZigBee va conectado a un doble toma donde van la impresora y el router.
  • Fingerbot: link - ZigBee dispositivo que hace de “dedo” para presionar el botón físico de encendido de la impresora y se integra fácil a Home Assistant.

La lógica es la siguiente: al tener la impresora en la red, Home Assistant la integra mediante CUPS y conoce el estado. Cuando llega un trabajo de impresión, la impresora cambia de En reposo a Imprimiendo.

Estado impresora en HA

Ahí dispara el script que enciende el enchufe y activa el fingerbot. Una vez que el router levanta y carga el firmware, CUPS reintenta solo imprimir (gracias a la config de reintentos). Luego, cuando la impresora vuelve a En reposo durante 20 minutos, se apaga el enchufe. También dejé un botón en el dashboard para cuando me gana la ansiedad.

Script: Encender impresora HP LaserJet P1005

sequence:
  - action: switch.turn_on
    metadata: {}
    target:
      entity_id: switch.smart_plug
    data: {}
  - delay:
      hours: 0
      minutes: 0
      seconds: 50                 # Un tiempo prudente para que inicie primero el router
      milliseconds: 0
  - action: switch.toggle
    metadata: {}
    target:
      entity_id: switch.fingerbot
    data: {}
    enabled: true
alias: Encender impresora HP LaserJet P1005
description: ""

Automatización: Encender impresora en recibir trabajo

alias: Encender impresora en recibir trabajo
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.hp_laserjet_p1005
    from:
      - idle
    to:
      - printing
conditions:
  - condition: device
    type: is_off
    device_id: device_id_smart_plug
    entity_id: entity_id_smart_plug
    domain: switch
actions:
  - action: script.turn_on
    metadata: {}
    target:
      entity_id: script.encender_impresora
    data: {}
mode: single

Automatización: Apagar la impresora inactiva por 20 minutos

alias: Apagar la impresora inactiva por 20 minutos
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.hp_laserjet_p1005_foomatic_foo2xqx_recommended
    from:
      - printing
    to:
      - idle
    for:
      hours: 0
      minutes: 20
      seconds: 0
conditions:
  - condition: device
    type: is_on
    device_id: device_id_smart_plug
    entity_id: entity_id_smart_plug
    domain: switch
actions:
  - action: switch.turn_off
    metadata: {}
    target:
      entity_id: switch.smart_plug
    data: {}
mode: single

Espero que les haya sido de utilidad, los leo en los comentarios del video. Sumensé con un like y una suscripción al canal.

Saludos!

comments powered by Disqus