[IMP] hw_proxy: better driver status reporting with hw_proxy/status, improved printing reliability
bzr revid: fva@openerp.com-20140126183500-ejbm9d4jafl817tq
This commit is contained in:
parent
ee3fa52bbe
commit
f1fa4fa230
|
@ -10,6 +10,8 @@ import random
|
||||||
import math
|
import math
|
||||||
import openerp.addons.hw_proxy.controllers.main as hw_proxy
|
import openerp.addons.hw_proxy.controllers.main as hw_proxy
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from threading import Thread
|
||||||
|
from Queue import Queue, Empty
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import usb.core
|
import usb.core
|
||||||
|
@ -27,11 +29,16 @@ from openerp.addons.web.controllers.main import manifest_list, module_boot, html
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class EscposDriver(hw_proxy.Proxy):
|
class EscposDriver(Thread):
|
||||||
|
def __init__(self):
|
||||||
supported_printers = [
|
Thread.__init__(self)
|
||||||
{ 'vendor' : 0x04b8, 'product' : 0x0e03, 'name' : 'Epson TM-T20' }
|
self.queue = None
|
||||||
]
|
self.status = {'status':'connecting', 'messages':[]}
|
||||||
|
|
||||||
|
self.supported_printers = [
|
||||||
|
{ 'vendor' : 0x04b8, 'product' : 0x0e03, 'name' : 'Epson TM-T20' },
|
||||||
|
{ 'vendor' : 0x04b8, 'product' : 0x0202, 'name' : 'Epson TM-T70' },
|
||||||
|
]
|
||||||
|
|
||||||
def connected_usb_devices(self,devices):
|
def connected_usb_devices(self,devices):
|
||||||
connected = []
|
connected = []
|
||||||
|
@ -41,32 +48,74 @@ class EscposDriver(hw_proxy.Proxy):
|
||||||
return connected
|
return connected
|
||||||
|
|
||||||
def get_escpos_printer(self):
|
def get_escpos_printer(self):
|
||||||
printers = self.connected_usb_devices(self.supported_printers)
|
try:
|
||||||
if len(printers) > 0:
|
printers = self.connected_usb_devices(self.supported_printers)
|
||||||
return escpos.printer.Usb(printers[0]['vendor'], printers[0]['product'])
|
if len(printers) > 0:
|
||||||
else:
|
self.set_status('connected','Connected to '+printers[0]['name'])
|
||||||
|
return escpos.printer.Usb(printers[0]['vendor'], printers[0]['product'])
|
||||||
|
else:
|
||||||
|
self.set_status('disconnected','Printer Not Found')
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
self.set_status('error',str(e))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@http.route('/hw_proxy/open_cashbox', type='json', auth='admin')
|
def get_status(self):
|
||||||
def open_cashbox(self):
|
self.push_task('status')
|
||||||
_logger.info('ESC/POS: OPEN CASHBOX')
|
return self.status
|
||||||
eprint = self.get_escpos_printer()
|
|
||||||
if eprint != None:
|
def open_cashbox(printer):
|
||||||
eprint.cashdraw(2)
|
printer.cashdraw(2)
|
||||||
eprint.cashdraw(5)
|
printer.cashdraw(5)
|
||||||
|
|
||||||
|
def set_status(self, status, message = None):
|
||||||
|
if status == self.status['status']:
|
||||||
|
if message != None and message != self.status['messages'][-1]:
|
||||||
|
self.status['messages'].append(message)
|
||||||
else:
|
else:
|
||||||
_logger.error('ESC/POS: OPEN CASHBOX: could not find printer')
|
self.status['status'] = status
|
||||||
|
if message:
|
||||||
@http.route('/hw_proxy/print_receipt', type='json', auth='admin')
|
self.status['messages'] = [message]
|
||||||
def print_receipt(self, receipt):
|
else:
|
||||||
_logger.info('ESC/POS: PRINT RECEIPT')
|
self.status['messages'] = []
|
||||||
eprint = self.get_escpos_printer()
|
|
||||||
if eprint != None:
|
if status == 'error' and message:
|
||||||
self.print_receipt_body(eprint,receipt)
|
_logger.error('ESC/POS Error: '+message)
|
||||||
eprint.cut()
|
elif status == 'disconnected' and message:
|
||||||
else:
|
_logger.warning('ESC/POS Device Disconnected: '+message)
|
||||||
_logger.error('ESC/POS: PRINT RECEIPT: could not find printer')
|
|
||||||
|
def run(self):
|
||||||
|
self.queue = Queue()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
timestamp, task, data = self.queue.get(True)
|
||||||
|
|
||||||
|
printer = self.get_escpos_printer()
|
||||||
|
|
||||||
|
if printer == None:
|
||||||
|
if task != 'status':
|
||||||
|
self.queue.put((timestamp,task,data))
|
||||||
|
time.sleep(5)
|
||||||
|
continue
|
||||||
|
elif task == 'receipt':
|
||||||
|
if timestamp >= time.time() - 1 * 60 * 60:
|
||||||
|
self.print_receipt_body(printer,data)
|
||||||
|
printer.cut()
|
||||||
|
elif task == 'cashbox':
|
||||||
|
if timestamp >= time.time() * 12:
|
||||||
|
self.open_cashbox(printer)
|
||||||
|
elif task == 'status':
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.set_status('error', str(e))
|
||||||
|
_logger.error(e);
|
||||||
|
|
||||||
|
def push_task(self,task, data = None):
|
||||||
|
if not self.isAlive():
|
||||||
|
self.start()
|
||||||
|
self.queue.put((time.time(),task,data))
|
||||||
|
|
||||||
def print_receipt_body(self,eprint,receipt):
|
def print_receipt_body(self,eprint,receipt):
|
||||||
|
|
||||||
def check(string):
|
def check(string):
|
||||||
|
@ -207,4 +256,20 @@ class EscposDriver(hw_proxy.Proxy):
|
||||||
+'/'+ str(receipt['date']['year']).zfill(4)
|
+'/'+ str(receipt['date']['year']).zfill(4)
|
||||||
+' '+ str(receipt['date']['hour']).zfill(2)
|
+' '+ str(receipt['date']['hour']).zfill(2)
|
||||||
+':'+ str(receipt['date']['minute']).zfill(2) )
|
+':'+ str(receipt['date']['minute']).zfill(2) )
|
||||||
|
|
||||||
|
driver = EscposDriver()
|
||||||
|
|
||||||
|
hw_proxy.drivers['escpos'] = driver
|
||||||
|
|
||||||
|
class EscposProxy(hw_proxy.Proxy):
|
||||||
|
|
||||||
|
@http.route('/hw_proxy/open_cashbox', type='json', auth='admin')
|
||||||
|
def open_cashbox(self):
|
||||||
|
_logger.info('ESC/POS: OPEN CASHBOX')
|
||||||
|
driver.push_task('cashbox')
|
||||||
|
|
||||||
|
@http.route('/hw_proxy/print_receipt', type='json', auth='admin')
|
||||||
|
def print_receipt(self, receipt):
|
||||||
|
_logger.info('ESC/POS: PRINT RECEIPT')
|
||||||
|
driver.push_task('receipt',receipt)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import openerp
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import simplejson
|
||||||
import werkzeug
|
import werkzeug
|
||||||
import werkzeug.wrappers
|
import werkzeug.wrappers
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
@ -17,13 +18,23 @@ from openerp.http import request
|
||||||
from openerp.addons.web.controllers.main import manifest_list, module_boot, html_template
|
from openerp.addons.web.controllers.main import manifest_list, module_boot, html_template
|
||||||
|
|
||||||
|
|
||||||
|
# drivers modules must add to drivers an object with a get_status() method
|
||||||
|
# so that 'status' can return the status of all active drivers
|
||||||
|
drivers = {}
|
||||||
|
|
||||||
class Proxy(http.Controller):
|
class Proxy(http.Controller):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.scale = 'closed'
|
self.scale = 'closed'
|
||||||
self.scale_weight = 0.0
|
self.scale_weight = 0.0
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
statuses = {}
|
||||||
|
for driver in drivers:
|
||||||
|
statuses[driver] = drivers[driver].get_status()
|
||||||
|
return statuses
|
||||||
|
|
||||||
@http.route('/hw_proxy/hello', type='http', auth='admin')
|
@http.route('/hw_proxy/hello', type='http', auth='admin')
|
||||||
def helloajx(self):
|
def hello(self):
|
||||||
return request.make_response('ping', {
|
return request.make_response('ping', {
|
||||||
'Cache-Control': 'no-cache',
|
'Cache-Control': 'no-cache',
|
||||||
'Content-Type': 'text/html; charset=utf-8',
|
'Content-Type': 'text/html; charset=utf-8',
|
||||||
|
@ -31,9 +42,43 @@ class Proxy(http.Controller):
|
||||||
'Access-Control-Allow-Methods': 'GET',
|
'Access-Control-Allow-Methods': 'GET',
|
||||||
})
|
})
|
||||||
|
|
||||||
@http.route('/hw_proxy/handshake', type='json', auth='admin')
|
@http.route('/hw_proxy/status', type='http', auth='admin')
|
||||||
def handshake(self):
|
def status_http(self):
|
||||||
return True
|
resp = '<html>\n<body>\n<h1>Hardware Proxy Status</h1>\n'
|
||||||
|
statuses = self.get_status()
|
||||||
|
for driver in statuses:
|
||||||
|
|
||||||
|
status = statuses[driver]
|
||||||
|
|
||||||
|
if status['status'] == 'connecting':
|
||||||
|
color = 'black'
|
||||||
|
elif status['status'] == 'connected':
|
||||||
|
color = 'green'
|
||||||
|
else:
|
||||||
|
color = 'red'
|
||||||
|
|
||||||
|
resp += "<h2 style='color:"+color+";'>"+driver+' : '+status['status']+"</h2>\n"
|
||||||
|
resp += "<ul>\n"
|
||||||
|
for msg in status['messages']:
|
||||||
|
resp += '<li>'+msg+'</li>\n'
|
||||||
|
resp += "</ul>\n"
|
||||||
|
resp += "<script>\n\tsetTimeout(function(){window.location.reload();},30000);\n</script>\n</body>\n</html>\n\n"
|
||||||
|
|
||||||
|
return request.make_response(resp,{
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
'Content-Type': 'text/html; charset=utf-8',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': 'GET',
|
||||||
|
})
|
||||||
|
|
||||||
|
@http.route('/hw_proxy/status', type='json', auth='admin')
|
||||||
|
def status_json(self):
|
||||||
|
return request.make_response(simplejson.dumps(self.get_status()),{
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
'Content-Type': 'text/html; charset=utf-8',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': 'GET',
|
||||||
|
})
|
||||||
|
|
||||||
@http.route('/hw_proxy/scan_item_success', type='json', auth='admin')
|
@http.route('/hw_proxy/scan_item_success', type='json', auth='admin')
|
||||||
def scan_item_success(self, ean):
|
def scan_item_success(self, ean):
|
||||||
|
|
|
@ -26,7 +26,9 @@ except ImportError:
|
||||||
class Scanner(Thread):
|
class Scanner(Thread):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
|
self.status = {'status':'connecting', 'messages':[]}
|
||||||
self.input_dir = '/dev/input/by-id/'
|
self.input_dir = '/dev/input/by-id/'
|
||||||
|
self.barcodes = Queue()
|
||||||
self.keymap = {
|
self.keymap = {
|
||||||
2: ("1","!"),
|
2: ("1","!"),
|
||||||
3: ("2","@"),
|
3: ("2","@"),
|
||||||
|
@ -84,6 +86,24 @@ class Scanner(Thread):
|
||||||
57:(" "," "),
|
57:(" "," "),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def set_status(self, status, message = None):
|
||||||
|
if status == self.status['status']:
|
||||||
|
if message != None and message != self.status['messages'][-1]:
|
||||||
|
self.status['messages'].append(message)
|
||||||
|
else:
|
||||||
|
self.status['status'] = status
|
||||||
|
if message:
|
||||||
|
self.status['messages'] = [message]
|
||||||
|
else:
|
||||||
|
self.status['messages'] = []
|
||||||
|
|
||||||
|
if status == 'error' and message:
|
||||||
|
_logger.error('Barcode Scanner Error: '+message)
|
||||||
|
elif status == 'disconnected' and message:
|
||||||
|
_logger.warning('Disconnected Barcode Scanner: '+message)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_device(self):
|
def get_device(self):
|
||||||
try:
|
try:
|
||||||
if not evdev:
|
if not evdev:
|
||||||
|
@ -92,14 +112,16 @@ class Scanner(Thread):
|
||||||
keyboards = [ device for device in devices if 'kbd' in device ]
|
keyboards = [ device for device in devices if 'kbd' in device ]
|
||||||
scanners = [ device for device in devices if ('barcode' in device.lower()) or ('scanner' in device.lower()) ]
|
scanners = [ device for device in devices if ('barcode' in device.lower()) or ('scanner' in device.lower()) ]
|
||||||
if len(scanners) > 0:
|
if len(scanners) > 0:
|
||||||
|
self.set_status('connected','Connected to '+scanners[0])
|
||||||
return evdev.InputDevice(join(self.input_dir,scanners[0]))
|
return evdev.InputDevice(join(self.input_dir,scanners[0]))
|
||||||
elif len(keyboards) > 0:
|
elif len(keyboards) > 0:
|
||||||
|
self.set_status('connected','Connected to '+keyboards[0])
|
||||||
return evdev.InputDevice(join(self.input_dir,keyboards[0]))
|
return evdev.InputDevice(join(self.input_dir,keyboards[0]))
|
||||||
else:
|
else:
|
||||||
_logger.error('Could not find the Barcode Scanner')
|
self.set_status('disconnected','Barcode Scanner Not Found')
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.error('Found the Barcode Scanner, but unable to access it\n Exception: ' + str(e))
|
self.set_status('error',str(e))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@http.route('/hw_proxy/Vis_scanner_connected', type='json', auth='admin')
|
@http.route('/hw_proxy/Vis_scanner_connected', type='json', auth='admin')
|
||||||
|
@ -120,6 +142,9 @@ class Scanner(Thread):
|
||||||
return barcode
|
return barcode
|
||||||
except Empty:
|
except Empty:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
return self.status
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
""" This will start a loop that catches all keyboard events, parse barcode
|
""" This will start a loop that catches all keyboard events, parse barcode
|
||||||
|
@ -138,7 +163,7 @@ class Scanner(Thread):
|
||||||
try:
|
try:
|
||||||
device.ungrab()
|
device.ungrab()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.error('Unable to release barcode scanner\n Exception:'+str(e))
|
self.set_status('error',str(e))
|
||||||
device = self.get_device()
|
device = self.get_device()
|
||||||
if not device:
|
if not device:
|
||||||
time.sleep(5) # wait until a suitable device is plugged
|
time.sleep(5) # wait until a suitable device is plugged
|
||||||
|
@ -173,17 +198,13 @@ class Scanner(Thread):
|
||||||
shift = False
|
shift = False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.error('Could not read Barcode Scanner Events:\n Exception: '+str(e))
|
self.set_status('error',str(e))
|
||||||
|
|
||||||
s = Scanner()
|
s = Scanner()
|
||||||
|
|
||||||
|
hw_proxy.drivers['scanner'] = s
|
||||||
|
|
||||||
class ScannerDriver(hw_proxy.Proxy):
|
class ScannerDriver(hw_proxy.Proxy):
|
||||||
@http.route('/hw_proxy/is_scanner_connected', type='json', auth='admin')
|
|
||||||
def is_scanner_connected(self):
|
|
||||||
if not s.isAlive():
|
|
||||||
s.start()
|
|
||||||
return s.get_device() != None
|
|
||||||
|
|
||||||
@http.route('/hw_proxy/scanner', type='json', auth='admin')
|
@http.route('/hw_proxy/scanner', type='json', auth='admin')
|
||||||
def scanner(self):
|
def scanner(self):
|
||||||
if not s.isAlive():
|
if not s.isAlive():
|
||||||
|
|
Loading…
Reference in New Issue