CHRONO-LABELER: Dispositivo Fechador De Alimentos Para Mini Impresoras Bluetooth.
by blopa1961 in Circuits > Arduino
100 Views, 0 Favorites, 0 Comments
CHRONO-LABELER: Dispositivo Fechador De Alimentos Para Mini Impresoras Bluetooth.
English version available HERE
Este proyecto permite generar etiquetas con fecha y hora utilizando un Arduino ESP32 y una mini impresora Bluetooth; sin necesidad de utilizar un smartphone o PC.
Destino:
Cuantas veces ha desechado comida porque no sabe cuánto hace que está en el refrigerador?
TÉRMINOS DE USO Y DESLINDE DE RESPONSABILIDAD:
Al descargar, instalar o utilizar este software, usted ("el Usuario") acepta cumplir con los presentes términos y condiciones: el Software se proporciona "tal como está", sin garantías de ningún tipo, expresas o implícitas, incluyendo, entre otras, garantías de comercialización ni idoneidad para un propósito particular. No garantizo que el Software esté libre de errores, interrupciones o fallos.
EN OTRAS PALABRAS, SI UTILIZA ESTE PROYECTO YO NO TENGO RESPONSABILIDAD ALGUNA.
Licencia:
Attribution Non-commercial (by-nc)
La licencia de uso del presente software es PERSONAL exclusivamente, es decir, no pueden vender el producto si lo fabrican.
Supplies
ESP32 Mini
3 LEDs de alta luminosidad (1 azul para modo de WiFi, 1 amarillo indicador de NTP y 1 verde para impresión)
3 resistores de 1K (preferible metalfilm por el tamaño)
1 resistor de 10K
1 botón (ver foto)
un trozo de placa perforada para desarrollo
una tira de pines Dupont
Descripción
Tal como dice al principio del presente documento, este aparato nació para cubrir la necesidad de fechar la comida guardada en el refrigerador o freezer.
Luego de analizar las impresoras disponibles en el mercado, descubrí que varias de las mini impresoras Bluetooth tienen bloqueos (un chip en el rollo) para forzar la compra de etiquetas de la marca (Niimbot) o intentan cobrar suscripciones anuales mayores al costo de la impresora para utilizar la más básica de las funciones como imprimir una fecha (Phomemo). De dichas impresoras no llegué a comprar la Niimbot D110 por los comentarios negativos al respecto en Reddit, pero compré y devolví inmediatamente después de probar la Phomemo D30 (porque hay que pagar 30 dólares por año para poder imprimir una fecha!).
Finalmente compré una TP-110 y una TP-220, de marcas G&G o TPL (son exactamente los mismos productos). Ambas impresoras trabajan con un subconjunto del lenguaje de impresión TSPL 2. Probé las impresoras con el software de Android Print-Label, que es bastante pasable, pero si uno tiene que abrir el smartphone, cargar la APP, conectarse a la impresora, elegir el perfil de impresión (tamaño de las etiquetas, fuente, etc.); lleva varios minutos lograr imprimir una etiqueta...
...y lo que yo quería era imprimir una simple fecha para el pollo del refrigerador!...
Dado que hago desarrollos en Arduino conozco el ESP32, que tiene WiFi, por lo cual la hora la puedo obtener de Internet por NTP (ni siquiera necesito un DS3231). Puedo armar una página WEB para configurar el SSID y los parámetros de la impresora. También tiene Bluetooth, así que la conexión con la impresora no es problema. Todo el hardware que necesito es 1 botón y un par de LEDs para hacer una versión minimalista de un servidor de impresión de etiquetas.
Pensé... esto es muy simple, puedo conectarme por WiFi al ESP32 para cargarle los parámetros de impresión y después simplemente presionar <EL BOTÓN> cada vez que necesito una etiqueta...
El desarrollo "trivial" me llevó más de 2 meses de trabajo full time, hackeo capturando los paquetes Bluetooth con Wireshark y más de 2500 líneas de código entre Arduino y HTML. Lo bueno? Aprendí un montón ;)
Si bien el trabajo de desarrollo hubiera sido el mismo, lamentablemente no encontré en mi país (Argentina) ninguna impresora serial-TTL a un precio razonable para no tener que conectarme por Bluetooth. Descubrí también que las impresoras TTL más comunes como la Adafruit Nano no pueden imprimir etiquetas, ya sea porque no aceptan el grosor de papel o porque el cabezal está tan profundamente dentro de la impresora que en el caso de una etiqueta comienza a imprimir por la mitad...
Futuros desarrollos:
- El primer cambio que quisiera hacer es reemplazar las rutinas de renderizado de fuentes porque las fuentes de Adafruit GFX no contienen caracteres en español. Si bien no se utilizan en la impresión de fechas, con las fuentes actuales no es posible etiquetar ñandúes desde la página principal.
- Cambiar la rutina de impresión a asincrónica (por timer) y así remover casi todos los delay() del programa. No es difícil hacerlo, pero hay que poner flags en varias partes del programa para evitar que otras rutinas accedan al buffer durante la impresión (a pesar de la buena capacidad de RAM del ESP32 no hay suficiente memoria para un segundo buffer cuando se construyen las páginas WEB en Strings). El programa ya funciona y como decía Murphy, "si funciona no lo toque"...
- Sería interesante agregar rutinas que accedan a datos técnicos de las impresoras o por ejemplo al nivel de batería (en el código fuente están listados todos los UUIDs, modelo, versión de firmware, etc. de estas impresoras).
- Otro desarrollo posible es adaptar el software a una impresora Mi17-446 ("gatito"), que tiene prestaciones similares a la TP-220 y es más barata, pero utiliza lenguaje ESC/POS y por lo tanto no es compatible con TSPL. Ya compré una, veremos...
- Quizás crear una versión de Chrono-Labeler con un DS3231, que no requeriría conexión continua a Internet.
- También se podría poner el Chrono-Labeler dentro de la impresora para agregarle el botón "imprimir fecha" y quizás reemplazar la batería de litio por un capacitor para dejar la impresora conectada y encendida.
Hardware:
Bueno, hablé anteriormente de minimalista, así que el hardware está compuesto por un ESP32 Mini, 3 LEDs con sus resistores de 1K y 1 botón con un pullup de 10K a 3.3V...
Adjunto también el STL del gabinete si desean imprimirlo en 3D.
Desarrollo ("Log")
A quienes no estén interesados en temas técnicos del uso de Bluetooth desde el ESP32 les sugiero saltear el siguiente STEP.
Durante la investigación y desarrollo mi primer éxito fue imprimir un bitmap por SPP (Serial Port Profile) utilizando las rutinas BluetoothSerial que son parte de Arduino, pero pronto descubrí que son obsoletas y no serán parte de futuros lanzamientos.
Dichas rutinas trabajan en "Bluetooth Classic", que es un protocolo distinto del actualmente utilizado, llamado "BLE" (Bluetooth Low Energy).
Además, chips de Espressif más nuevos de las series S, C o H, como el ESP32-C3 o el ESP32-S3 tienen solamente BLE y no funcionan con Bluetooth Classic.
Las impresoras que utilicé trabajan en los 2 modos, Classic y BLE, razón por la cual cada una tiene 2 nombres y 2 direcciones MAC (los nombres BLE terminan con "-BLE").
Así que el siguiente paso fue portar el desarrollo a BLE utilizando las rutinas de Arduino: BLEDevice, BLEUtils y BLEClient.
Aquí es donde encontré el primer escollo, porque si bien pude escanear los UUIDs de las impresoras (vean en el código fuente el comentario sobre todos los UUIDs y Characteristics capturados), no lograba imprimir el bitmap que funcionaba bien en el programa SPP.
Horas de debugging después descubrí que la razón del problema es que mi test original estaba basado en la captura con Wireshark de los paquetes enviados por mi vieja tablet Android 7, que mandaba paquetes Bluetooth Classic de 640 bytes durante la transferencia del bitmap. Quienes tengan experiencia en desarrollos BLE seguramente sabrán que los paquetes BLE tienen un límite de datos de 251 bytes (contra los alrededor de 1K del Bluetooth Classic), yo no lo sabía. También descubrí que contrariamente a los paquetes SPP, en modo BLE hay que darle tiempo a la impresora a procesar lo recibido o hay overrun del buffer. Esta última es la razón por la que el software ahora tiene la opción de configuración de tiempo de retardo de los paquetes BLE de la impresora.
También hace falta un retardo al cambiar de conexión, pero esto no afecta si están usando 1 sola impresora.
Maravilloso, ahora que funciona en BLE dejo de transpirar y sigo con el desarrollo... pruebo imprimir con la impresora apagada... se cuelga! Vuelta a investigación y desarrollo... descubro que BLEDevice es BLOCKING, es decir, no tiene límites de tiempo si no hay respuesta del Bluetooth...por suerte hay una library llamada NimBLE-Arduino que implementa BLE con timeout... Porto el software a NimBLE, listo, a imprimir textos a ver como salen...
No salen! Y no salen porque las impresoras TP-110 y TP-220 no implementan todo el lenguaje TSPL 2, solo BITMAP; el comando TEXT de TSPL no está implementado.
Mas desarrollo, crear un buffer en RAM y generar los textos en el buffer usando las fuentes Adafruit GFX. Afortunadamente hay una library llamada Thermal Printer Library escrita por "bitbank2" (Larry Bank) que implementa el renderizado de fuentes; así que importo la parte de la biblioteca que implementa el renderizado... y salen mal las letras (!)... encuentro el bug, lo soluciono y agrego un cambio que me permite utilizar fondos negros o blancos indistintamente. En un próximo release de Chrono-Labeler la idea es reemplazar esta rutina con las de U8g2, que contienen los caracteres del idioma español.
Todo proyecto llega al 90% de avance en el 90% del tiempo disponible para el desarrollo, y el 10% restante lleva OTRO 90% de tiempo... convirtiéndose en más complejo a medida que avanza... porque ahora que tengo un buffer... no sería bueno poder ver cómo queda lo que estoy por imprimir? Bastaría agregarle el encabezado de un BMP y subirlo a la página no? Otra vez me metí una complicación... los BMP tienen que estar alineados a 32 bits y no tengo memoria suficiente para crear otro buffer... y para colmo, parece que un ingeniero de Microsoft estaba fumando algo raro cuando definió el encabezado de los BMPs y puso un hermosa variable de 16 bits en el principio de una estructura que tiene que estar alineada a 32... Ahí es donde tuve que aprender después de horas de debugging qué significa #pragma pack en Arduino...
Finalmente escribí la rutina que alinea los pixels dentro del mismo buffer y agregué previsualización a TODAS las páginas WEB, incluidas las de configuración. Si, hizo falta reescribir todas las páginas WEB para lograr esto.
Solo me faltaría entender los escapes de inicialización de las impresoras, que copié de las capturas de Wireshark y no están documentadas (pero funcionan).
Compilación:
El software se desarrolló utilizando Arduino IDE 2.3.8
Hace falta agregar el siguiente link bajo "Additional boards manager URLs" en el menú de archivo/preferencias:
https://dl.espressif.com/dl/package_esp32_index.json
Luego instalar "esp32" por Espressif Systems en Boards Manager, y "NimBLE-Arduino" en Library Manager.
Hay miles de tutoriales en Internet sobre cómo instalar Arduino IDE, así que no me voy a extender en el tema. Googléenlo si les hace falta.
Descarguen el código fuente del enlace de aquí debajo, copien los archivos a una carpeta con el mismo nombre que el .ino, creen la subcarpeta Fonts (respetando mayúsculas y minúsculas) y copien las fuentes allí.
Seleccionen "ESP32 Dev Module" como procesador de destino, velocidad 240 MHz, esquema de partición "No OTA (2MB APP/2MB SPIFFS)" y velocidad de transferencia a 921600. Listo, ya pueden enviar el sketch a su ESP32 mini.
Código Fuente:
El código fuente completo está disponible en github >>>>>> AQUI <<<<<<
También disponible en inglés >>>>>> AQUI <<<<<<
Cómo Se Usa:
Conectar el Chrono Labeler al WiFi local (SSID y clave), vincular la impresora por Bluetooth y configurar el formato de fecha y hora deseado. Después basta presionar EL BOTÓN para que salga una etiqueta con la fecha y hora.
Una vez conectado a intranet se puede acceder al Chrono-Labeler mediante el IP (si es fijo) o mediante mDNS http://chronolabeler.local
Desde la página WEB principal se puede imprimir cualquier texto (sin acentos ni eñes por ahora). Si se deja la primera línea de texto en blanco salen la fecha y hora actuales tal como si hubieran presionado el <EL BOTÓN>.
Que cómo conecto el Chrono Labeler a WiFi? Fácil:
Descargue y LEA EL MANUAL DEL USUARIO!