Ticket impreso con Python en impresora térmica usando Plugin v3

Conectar impresora térmica con Python – Imprimir tickets usando plugin v3

El día de hoy veremos cómo imprimir recibos, facturas o tickets en una impresora térmica usando Python a través de un plugin desarrollado por mí.

Con esto podrás imprimir tickets desde Python sin importar si usas la terminal, Flask, Tkinter, Django o cualquier otra cosa, pues mientras uses Python podrás imprimir en una impresora térmica.

Con el plugin presentado aquí podrás imprimir imágenes, códigos de barras, texto con acentos, cambiar fuentes, rotar texto y mucho más en la impresora térmica usando Python y comandos ESC POS.

Prueba el nuevo diseñador

En estos días he creado un nuevo diseñador web para impresoras térmicas. El diseñador te guiará en el proceso de instalar tu impresora, compartirla e instalar lo necesario para imprimir tus diseños. Pruébalo en:

https://parzibyte.me/apps/ticket-designer/#/first-steps

Una vez que tengas tus diseños vas a poder imprimirlos desde cualquier lenguaje de programación, incluyendo Python.

Conector de Python

Para imprimir en una impresora térmica desde Python necesitamos un conector que sirva como enlace entre Python y el plugin. Lo he programado yo mismo y queda así:

import requests

URL_PLUGIN_POR_DEFECTO = "http://localhost:8000"
TAMAÑO_IMAGEN_NORMAL = 0
TAMAÑO_IMAGEN_DOBLE_ANCHO = 1
TAMAÑO_IMAGEN_DOBLE_ALTO = 2
TAMAÑO_IMAGEN_DOBLE_ANCHO_Y_ALTO = 3
ALINEACION_IZQUIERDA = 0
ALINEACION_CENTRO = 1
ALINEACION_DERECHA = 2
RECUPERACION_QR_BAJA = 0
RECUPERACION_QR_MEDIA = 1
RECUPERACION_QR_ALTA = 2
RECUPERACION_QR_MEJOR = 3


class ConectorV3:

    def __init__(self, ruta=URL_PLUGIN_POR_DEFECTO, serial=""):
        self.operaciones = []
        self.ruta = ruta
        self.serial = serial

    def agregar_operacion(self, nombre, argumentos):
        self.operaciones.append({
            "nombre": nombre,
            "argumentos": argumentos,
        })

    def obtenerImpresoras(ruta=URL_PLUGIN_POR_DEFECTO):
        respuesta = requests.get(ruta+"/impresoras")
        return respuesta.json()

    def CargarImagenLocalEImprimir(self, ruta: str, tamaño: float, maximoAncho: float):
        return self.agregar_operacion("CargarImagenLocalEImprimir", [ruta, tamaño, maximoAncho])

    def Corte(self, lineas):
        return self.agregar_operacion("Corte", [lineas])

    def CorteParcial(self):
        return self.agregar_operacion("CorteParcial", [])

    def DefinirCaracterPersonalizado(self, caracterRemplazoComoCadena: str, matrizComoCadena: str):
        return self.agregar_operacion("DefinirCaracterPersonalizado", [caracterRemplazoComoCadena, matrizComoCadena])

    def DescargarImagenDeInternetEImprimir(self, urlImagen: str, tamaño: float, maximoAncho: float):
        return self.agregar_operacion("DescargarImagenDeInternetEImprimir", [urlImagen, tamaño, maximoAncho])

    def DeshabilitarCaracteresPersonalizados(self, ):
        return self.agregar_operacion("DeshabilitarCaracteresPersonalizados", [])

    def DeshabilitarElModoDeCaracteresChinos(self, ):
        return self.agregar_operacion("DeshabilitarElModoDeCaracteresChinos", [])

    def EscribirTexto(self, texto: str):
        return self.agregar_operacion("EscribirTexto", [texto])

    def EstablecerAlineacion(self, alineacion: float):
        return self.agregar_operacion("EstablecerAlineacion", [alineacion])

    def EstablecerEnfatizado(self, enfatizado: bool):
        return self.agregar_operacion("EstablecerEnfatizado", [enfatizado])

    def EstablecerFuente(self, fuente: float):
        return self.agregar_operacion("EstablecerFuente", [fuente])

    def EstablecerImpresionAlReves(self, alReves: bool):
        return self.agregar_operacion("EstablecerImpresionAlReves", [alReves])

    def EstablecerImpresionBlancoYNegroInversa(self, invertir: bool):
        return self.agregar_operacion("EstablecerImpresionBlancoYNegroInversa", [invertir])

    def EstablecerRotacionDe90Grados(self, rotar: bool):
        return self.agregar_operacion("EstablecerRotacionDe90Grados", [rotar])

    def EstablecerSubrayado(self, subrayado: bool):
        return self.agregar_operacion("EstablecerSubrayado", [subrayado])

    def EstablecerTamañoFuente(self, multiplicadorAncho: float, multiplicadorAlto: float):
        return self.agregar_operacion("EstablecerTamañoFuente", [multiplicadorAncho, multiplicadorAlto])

    def Feed(self, lineas):
        return self.agregar_operacion("Feed", [lineas])

    def HabilitarCaracteresPersonalizados(self):
        return self.agregar_operacion("HabilitarCaracteresPersonalizados", [])

    def HabilitarElModoDeCaracteresChinos(self):
        return self.agregar_operacion("HabilitarElModoDeCaracteresChinos", [])

    def ImprimirCodigoDeBarrasCodabar(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCodabar", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasCode128(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCode128", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasCode39(self, contenido: str, incluirSumaDeVerificacion: bool, modoAsciiCompleto: bool, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCode39", [contenido, incluirSumaDeVerificacion, modoAsciiCompleto, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasCode93(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCode93", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasEan(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasEan", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasEan8(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasEan8", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasPdf417(self, contenido: str, nivelSeguridad: float, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasPdf417", [contenido, nivelSeguridad, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasTwoOfFiveITF(self, contenido: str, intercalado: bool, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasTwoOfFiveITF", [contenido, intercalado, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasUpcA(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasUpcA", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasUpcE(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasUpcE", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoQr(self, contenido: str, anchoMaximo: float, nivelRecuperacion: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoQr", [contenido, anchoMaximo, nivelRecuperacion, tamañoImagen])

    def ImprimirImagenEnBase64(self, imagenCodificadaEnBase64: str, tamaño: float, maximoAncho: float):
        return self.agregar_operacion("ImprimirImagenEnBase64", [imagenCodificadaEnBase64, tamaño, maximoAncho])

    def Iniciar(self, ):
        return self.agregar_operacion("Iniciar", [])

    def Pulso(self, pin: float, tiempoEncendido: float, tiempoApagado: float):
        return self.agregar_operacion("Pulso", [pin, tiempoEncendido, tiempoApagado])

    def TextoSegunPaginaDeCodigos(self, numeroPagina: float, pagina: str, texto: str):
        return self.agregar_operacion("TextoSegunPaginaDeCodigos", [numeroPagina, pagina, texto])

    def imprimirEn(self, nombreImpresora):
        payload = {
            "operaciones": self.operaciones,
            "nombreImpresora": nombreImpresora,
            "serial": self.serial,
        }
        respuesta = requests.post(self.ruta+"/imprimir", json=payload)
        return respuesta.json()

Nota: vas a necesitar el paquete requests, que puedes instalar fácilmente con pip install requests.

Lo que te mostré anteriormente es el conector. Tu código de Python usa el conector y el conector se comunica con el plugin para imprimir en las impresoras térmicas.

Hola mundo en impresora térmica con Python

Entonces en nuestro archivo donde tengamos nuestro código de Python vamos a importar al conector así:

import ConectorPython

El conector debe estar en un archivo llamado ConectorPython.py, pero si no quieres importarlo también puedes copiar y pegar todo el código en tu proyecto, solo ten cuidado de no confundirte.

Ahora puedes obtener la lista de impresoras así:

impresoras = ConectorPython.ConectorV3.obtenerImpresoras()
print("Las impresoras son:")
print(impresoras)

Eso devolverá la lista de impresoras. Es una lista de tipo cadena, y te será útil si quieres darle al usuario la oportunidad de elegir su impresora o cosas por el estilo.

Ahora creamos una instancia de ConectorV3 y hacemos un hola mundo:

nombreImpresora = "ZJ-58"; # Puede venir de la lista o puedes escribirlo si sabes el nombre
conector = ConectorPython.ConectorV3()
conector.Iniciar()
conector.EscribirTexto("Hola mundo")
conector.Feed(1)
respuesta = conector.imprimirEn(nombreImpresora)
if respuesta == True:
    print("Impreso correctamente")
else:
    print("Error: " + respuesta)

Nota: si el plugin está escuchando en un puerto distinto recuerda que puedes indicar la URL al construir el objeto ConectorV3 o al invocar a obtenerImpresoras.

Descarga del plugin

Lo presentado aquí es un conector para un plugin gratuito que he desarrollado. Este plugin permite imprimir en impresoras térmicas desde cualquier lenguaje de programación, por ello es que ahora escribí un conector en Python.

Entonces antes de usar el código aquí presente debes configurar tu impresora y descargar el plugin.

Para instalar tu impresora y compartirla: https://parzibyte.me/blog/2017/12/11/instalar-impresora-termica-generica/

Después descarga el plugin desde: https://github.com/parzibyte/plugin-impresora-termica-v3/releases/tag/3.2.1

Una vez que hayas hecho todos los pasos necesarios y que veas que el plugin funciona entonces puedes comenzar a imprimir desde Python.

Ejemplo de ticket impreso con Python usando ESC POS

Ahora veamos un ejemplo completo de un ticket impreso con Python en una impresora térmica.

En este caso yo le estoy pasando el nombre de la impresora directamente porque ya sé cuál es la impresora en la que quiero imprimir. Si tú quieres puedes hacer que el usuario elija según la lista.

import ConectorPython

impresoras = ConectorPython.ConectorV3.obtenerImpresoras()
print("Las impresoras son:")
print(impresoras)

nombreImpresora = "PT210"  # Nota: esta impresora debe existir y estar compartida como se indica en https://parzibyte.me/blog/2017/12/11/instalar-impresora-termica-generica/
# Aquí va tu serial por si tienes uno:
serial = ""

amongUsComoCadena = """000001111000
000010000100
000100011110
000100100001
011100100001
010100100001
010100100001
010100011110
010100000010
011100000010
000100111010
000100101010
000111101110
000000000000
000000000000
000000000000
111010101110
100010101000
111010101110
001010100010
111011101110
000000000000
000000000000
000000000000"""
conector = ConectorPython.ConectorV3(serial=serial)
conector.Iniciar()
conector.DeshabilitarElModoDeCaracteresChinos()
conector.EstablecerAlineacion(ConectorPython.ALINEACION_CENTRO)
conector.DescargarImagenDeInternetEImprimir(
    "http://assets.stickpng.com/thumbs/587e32259686194a55adab73.png", 0, 216)
conector.Feed(1)
conector.EscribirTexto("Parzibyte's blog\n")
conector.EscribirTexto("Blog de un programador\n")
conector.TextoSegunPaginaDeCodigos(2, "cp850", "Teléfono: 123456798\n")
conector.EscribirTexto("Fecha y hora: 29/9/2022")
conector.Feed(1)
conector.EstablecerAlineacion(ConectorPython.ALINEACION_IZQUIERDA)
conector.EscribirTexto("____________________\n")
conector.TextoSegunPaginaDeCodigos(
    2, "cp850", "Venta de plugin para impresoras versión 3\n")
conector.EstablecerAlineacion(ConectorPython.ALINEACION_DERECHA)
conector.EscribirTexto("$25\n")
conector.EscribirTexto("____________________\n")
conector.EscribirTexto("TOTAL: $25\n")
conector.EscribirTexto("____________________\n")
conector.EstablecerAlineacion(ConectorPython.ALINEACION_CENTRO)
conector.HabilitarCaracteresPersonalizados()
conector.DefinirCaracterPersonalizado("$", amongUsComoCadena)
conector.EscribirTexto(
    "En lugar del simbolo de pesos debe aparecer un among us\n")
conector.EscribirTexto("TOTAL: $25\n")
conector.EstablecerEnfatizado(True)
conector.EstablecerTamañoFuente(1, 1)
conector.TextoSegunPaginaDeCodigos(2, "cp850", "¡Gracias por su compra!\n")
conector.Feed(1)
conector.ImprimirCodigoQr("https://parzibyte.me/blog", 160,
                          ConectorPython.RECUPERACION_QR_MEJOR, ConectorPython.TAMAÑO_IMAGEN_NORMAL)
conector.Feed(1)
conector.ImprimirCodigoDeBarrasCode128(
    "parzibyte.me", 80, 192, ConectorPython.TAMAÑO_IMAGEN_NORMAL)
conector.Feed(1)
conector.EstablecerTamañoFuente(1, 1)
conector.EscribirTexto("parzibyte.me\n")
conector.Feed(3)
conector.Corte(1)
conector.Pulso(48, 60, 120)
respuesta = conector.imprimirEn(nombreImpresora)
if respuesta == True:
    print("Impreso correctamente")
else:
    print("Error: " + respuesta)

Debe imprimirse algo como lo siguiente:

Ticket impreso con Python en impresora térmica usando Plugin v3
Ticket impreso con Python en impresora térmica usando Plugin v3

Como puedes ver, estamos imprimiendo imágenes en una thermal printer usando Python, además de códigos QR, códigos de barra, texto con estilo y caracteres personalizados.

Lo que resta ahora es leer la documentación en la página del plugin para que conozcas todos los métodos y de todo lo que es capaz o para que contrates una licencia y remuevas mis créditos del pie de página: https://parzibyte.me/blog/2022/09/30/plugin-impresoras-termicas-version-3/

Te dejo con más tutoriales de Python y más detalles sobre el plugin.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *