bulmages
Inicio Noticias Truco para redirigir la impresión de tickets de BulmaTPV a una impresora CUPS
Truco para redirigir la impresión de tickets de BulmaTPV a una impresora CUPS
Martes, 11 de Agosto de 2009 08:14


Efectividad: BulmaTPV SVN rev. 3618.
Requisitos: Python
Descripción:
En este artículo se describe como imprimir en una impresora CUPS los tickets generados por BulmaTPV.

En /etc/bulmages/bulmatpv.conf aparece la directiva CONF_TICKET_PRINTER_FILE que se utiliza para establecer el archivo donde se escribirá cada vez que se imprima un ticket. Como norma general apunta a una impresora conectada al puerto paralelo /dev/lp0 ó impresora USB que tiene también una entrada en /dev.

El sistema no permite establecer una impresora de tipo CUPS por lo que imprimir en impresoras remotas no está contemplado de forma nativa.

Para solucionar esta limitación se ha creado un 'script' que actúa como un proceso 'daemon' y que lee desde un archivo de tipo FIFO (First In First Out) y lo redirige a una impresora CUPS.

Lo primero que hay que hacer es crear este archivo con el comando mkfifo y asignarle permisos de escritura para BulmaTPV y lectura para este 'script'.

Para configurar la impresora a la que redirigir la impresión hay que editar el 'script' en la línea salida = os.popen("lp -d bixolonsrp350plus", "wb") y poner el nombre de la impresora CUPS adecuada.


Ejemplo de uso:

  • Por un lado tenemos instalado BulmaTPV en un ordenador servidor donde no hay impresoras conectadas.
  • Por otro lado tenemos un ordenador que hace de terminal que mediante SSH se conecta con el servidor haciendo 'X11 forwarding' utilizando la opción -X de SSH. De esta manera al invocar el ejecutable de BulmaTPV aparecerán las ventanas del programa en el ordenador terminal.
  • El ordenador terminal tiene conectada, al puerto USB, la impresora de tickets 'Bixolon SRP-350 Plus' que aparece en /dev/usblp0
  • En el ordenador terminal configuramos la impresora en CUPS en modo RAW y la compartimos de modo que desde el servidor sea visible.
  • El el ordenador servidor instalamos una impresora CUPS que simplemente redirige lo que imprimamos a la impresora que se compartió en el ordenador terminal.


Para asegurarse que el 'script' se ejecuta al poner en marcha el sistema como cualquier otro 'daemon' hay que copiarlo dentro de /etc/init.d y ejecutar chkconfig para configurar el 'runlevel'. Ejemplo:
chkconfig -a bulmatpv-cups-printer.py
chkconfig bulmatpv-cups-printer.py 35



bulmatpv-cups-printer.py


 

#!/usr/bin/env python

#
# Based on code Sander Marechal
# http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
# (PUBLIC LICENCE)
#
# (c) 2009, Fco. Javier M. C. <fcojavmc @todo-redes.com> (GPL-2 or GPL-3 Licence)
#

import sys, time, os, atexit
from signal import SIGTERM 
#from daemon import Daemon


###### CLASE PARA PYTHON 2.x

class Daemon:
	"""
	A generic daemon class.
	
	Usage: subclass the Daemon class and override the run() method
	"""
	def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
		self.stdin = stdin
		self.stdout = stdout
		self.stderr = stderr
		self.pidfile = pidfile
	
	def daemonize(self):
		"""
		do the UNIX double-fork magic, see Stevens' "Advanced 
		Programming in the UNIX Environment" for details (ISBN 0201563177)
		http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
		"""
		try: 
			pid = os.fork() 
			if pid > 0:
				# exit first parent
				sys.exit(0) 
		except OSError, e: 
			sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
			sys.exit(1)
	
		# decouple from parent environment
		os.chdir("/") 
		os.setsid() 
		os.umask(0) 
	
		# do second fork
		try: 
			pid = os.fork() 
			if pid > 0:
				# exit from second parent
				sys.exit(0) 
		except OSError, e: 
			sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
			sys.exit(1) 
	
		# redirect standard file descriptors
		sys.stdout.flush()
		sys.stderr.flush()
		si = file(self.stdin, 'r')
		so = file(self.stdout, 'a+')
		se = file(self.stderr, 'a+', 0)
		os.dup2(si.fileno(), sys.stdin.fileno())
		os.dup2(so.fileno(), sys.stdout.fileno())
		os.dup2(se.fileno(), sys.stderr.fileno())
	
		# write pidfile
		atexit.register(self.delpid)
		pid = str(os.getpid())
		file(self.pidfile,'w+').write("%s\n" % pid)
	
	def delpid(self):
		os.remove(self.pidfile)

	def start(self):
		"""
		Start the daemon
		"""
		# Check for a pidfile to see if the daemon already runs
		try:
			pf = file(self.pidfile,'r')
			pid = int(pf.read().strip())
			pf.close()
		except IOError:
			pid = None
	
		if pid:
			message = "pidfile %s already exist. Daemon already running?\n"
			sys.stderr.write(message % self.pidfile)
			sys.exit(1)
		
		# Start the daemon
		self.daemonize()
		self.run()

	def stop(self):
		"""
		Stop the daemon
		"""
		# Get the pid from the pidfile
		try:
			pf = file(self.pidfile,'r')
			pid = int(pf.read().strip())
			pf.close()
		except IOError:
			pid = None
	
		if not pid:
			message = "pidfile %s does not exist. Daemon not running?\n"
			sys.stderr.write(message % self.pidfile)
			return # not an error in a restart

		# Try killing the daemon process	
		try:
			while 1:
				os.kill(pid, SIGTERM)
				time.sleep(0.1)
		except OSError, err:
			err = str(err)
			if err.find("No such process") > 0:
				if os.path.exists(self.pidfile):
					os.remove(self.pidfile)
			else:
				print str(err)
				sys.exit(1)

	def restart(self):
		"""
		Restart the daemon
		"""
		self.stop()
		self.start()

	def run(self):
		"""
		You should override this method when you subclass Daemon. It will be called after the process has been
		daemonized by start() or restart().
		"""


#####################################################


class MyDaemon(Daemon):
	def run(self):
		# Aqui se coloca el archivo donde se imprimira desde el programa
		# Se tiene que crear en forma de archivo tipo FIFO.
		# ej: mkfifo /opt/printer_ticket
		# Luego hay que establecer los permisos adecuados para que el programa
		# pueda escribir en el archivo y para que este 'script' pueda leerlo.
		archivo = open('/opt/printer_ticket','r')
		while 1:
			time.sleep(1)
			contenido = archivo.read()
			if contenido:
				# Comando con el nombre de la impresora CUPS a donde se desea redirigir.
				salida = os.popen("lp -d bixolonsrp350plus", "wb")
				salida.write(contenido)
				salida.close()


if __name__ == "__main__":
	daemon = MyDaemon('/tmp/daemon-bulmatpv-cups-printer.pid')
	if len(sys.argv) == 2:
		if 'start' == sys.argv[1]:
			daemon.start()
		elif 'stop' == sys.argv[1]:
			daemon.stop()
		elif 'restart' == sys.argv[1]:
			daemon.restart()
		else:
			print "Unknown command"
			sys.exit(2)
		sys.exit(0)
	else:
		print "usage: %s start|stop|restart" % sys.argv[0]
		sys.exit(2)