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.
El mini router TP-Link TL-WR703N
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.

| Especificaciones | |
|---|---|
| CPU | Atheros AR7240 (400 MHz) |
| Chipset | Atheros AR9331 (wireless integrada) |
| WiFi | 802.11 b/g/n 150 Mbps (130 Mbps real) |
| Potencia wireless | 20 dBm – 100 mW |
| Memoria flash | 4 MB |
| RAM | 32 MB |
| Dimensiones | 5.7 cm × 5.7 cm × 1.8 cm |
| Puerto LAN | 1 |
| Puerto USB | 1 × USB 2.0 |
| Alimentación | Micro-USB |
| LED | 1 |
El modelo venía con el firmware solo en idioma chino, así que en esa época le instalé OpenWRT.

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 {cambiarreg = <0x20000 0x3d0000>;porreg = <0x20000 0xfd0000>; - Cambiar
art: partition@3f0000 {porart: partition@ff0000 { - Debajo de eso, cambiar
reg = <0x3f0000 0x10000>;porreg = <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.

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.
- Conectar el router al PC con un cable de red por el puerto LAN
- Configurar la IP del PC manualmente:
192.168.1.2con máscara255.255.255.0 - Encender el router manteniendo presionado el botón de reset hasta que el LED parpadee (unos 3 segundos)
- Abrir el navegador y entrar a
http://192.168.1.1 - Va a aparecer una página simple con un formulario de carga de archivo
- Seleccionar el archivo
.bindel firmware compilado (elsysupgradeofactory) - Hacer click en el botón para iniciar la escritura y esperar que el router reinicie solo
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í:

[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.
| Componente | Protocolo | Puerto |
|---|---|---|
| CUPS (clientes) | IPP/IPPS | 631 |
| CUPS → p910nd | AppSocket (raw TCP) | 9100 |
| p910nd → impresora | USB printer class | — |
La HP LaserJet P1005 y el firmware correcto

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:
| Origen | Tamaño | MD5 | Funciona |
|---|---|---|---|
printer-driver-foo2zjs | 222.443 bytes | ed18611a9c0c6c23b97d8c543fb2ec79 | ✓ Sí |
| Plugin HPLIP | 116.925 bytes | 63f5696df7175af70cdfbf56126336ce | ✗ 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ón | Valor | Por qué |
|---|---|---|
bidirectional | 1 | La P1005 usa protocolo bidireccional. Sin esto, CUPS puede reportar errores falsos. |
usbvidpid | 03f0/3d17 | El 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.dl | p910nd 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):
- Abrir la interfaz web de CUPS (por defecto en el puerto 631)
- Administración → Añadir impresora
- Seleccionar AppSocket/HP JetDirect
- En conexión poner:
socket://IP-DEL-ROUTER:9100 - Poner nombre y descripción
- Tildar Compartición
- En el último paso seleccionar el driver
HP LaserJet P1005 Foomatic/foo2zjsy 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.

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!



