[IMP] hw_proxy: better driver status reporting with hw_proxy/status, improved printin...
authorFrédéric van der Essen <fva@openerp.com>
Sun, 26 Jan 2014 18:35:00 +0000 (19:35 +0100)
committerFrédéric van der Essen <fva@openerp.com>
Sun, 26 Jan 2014 18:35:00 +0000 (19:35 +0100)
bzr revid: fva@openerp.com-20140126183500-ejbm9d4jafl817tq

addons/hw_escpos/controllers/main.py
addons/hw_proxy/controllers/main.py
addons/hw_scanner/controllers/main.py

index 4fde44d..5d58082 100644 (file)
@@ -10,6 +10,8 @@ import random
 import math
 import openerp.addons.hw_proxy.controllers.main as hw_proxy
 import subprocess
+from threading import Thread
+from Queue import Queue, Empty
 
 try:
     import usb.core
@@ -27,11 +29,16 @@ from openerp.addons.web.controllers.main import manifest_list, module_boot, html
 
 _logger = logging.getLogger(__name__)
 
-class EscposDriver(hw_proxy.Proxy):
-    
-    supported_printers = [
-        { 'vendor' : 0x04b8, 'product' : 0x0e03, 'name' : 'Epson TM-T20' }
-    ]
+class EscposDriver(Thread):
+    def __init__(self):
+        Thread.__init__(self)
+        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):
         connected = []
@@ -41,32 +48,74 @@ class EscposDriver(hw_proxy.Proxy):
         return connected
     
     def get_escpos_printer(self):
-        printers = self.connected_usb_devices(self.supported_printers)
-        if len(printers) > 0:
-            return escpos.printer.Usb(printers[0]['vendor'], printers[0]['product'])
-        else:
+        try:
+            printers = self.connected_usb_devices(self.supported_printers)
+            if len(printers) > 0:
+                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
-    
-    @http.route('/hw_proxy/open_cashbox', type='json', auth='admin')
-    def open_cashbox(self):
-        _logger.info('ESC/POS: OPEN CASHBOX') 
-        eprint = self.get_escpos_printer()
-        if eprint != None:
-            eprint.cashdraw(2)
-            eprint.cashdraw(5)
-        else:
-            _logger.error('ESC/POS: OPEN CASHBOX: could not find printer') 
-        
-    @http.route('/hw_proxy/print_receipt', type='json', auth='admin')
-    def print_receipt(self, receipt):
-        _logger.info('ESC/POS: PRINT RECEIPT') 
-        eprint = self.get_escpos_printer()
-        if eprint != None:
-            self.print_receipt_body(eprint,receipt)
-            eprint.cut()
+
+    def get_status(self):
+        self.push_task('status')
+        return self.status
+
+    def open_cashbox(printer):
+        printer.cashdraw(2)
+        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:
-            _logger.error('ESC/POS: PRINT RECEIPT: could not find printer') 
-    
+            self.status['status'] = status
+            if message:
+                self.status['messages'] = [message]
+            else:
+                self.status['messages'] = []
+
+        if status == 'error' and message:
+            _logger.error('ESC/POS Error: '+message)
+        elif status == 'disconnected' and message:
+            _logger.warning('ESC/POS Device Disconnected: '+message)
+
+    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 check(string):
@@ -207,4 +256,20 @@ class EscposDriver(hw_proxy.Proxy):
                     +'/'+ str(receipt['date']['year']).zfill(4)
                     +' '+ str(receipt['date']['hour']).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)
+    
index 6ddf948..1888c23 100644 (file)
@@ -7,6 +7,7 @@ import openerp
 import time
 import random
 import subprocess
+import simplejson
 import werkzeug
 import werkzeug.wrappers
 _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
 
 
+# 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):
     def __init__(self):
         self.scale = 'closed'
         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')
-    def helloajx(self):
+    def hello(self):
         return request.make_response('ping', {
             'Cache-Control': 'no-cache', 
             'Content-Type': 'text/html; charset=utf-8',
@@ -31,9 +42,43 @@ class Proxy(http.Controller):
             'Access-Control-Allow-Methods': 'GET',
             })
 
-    @http.route('/hw_proxy/handshake', type='json', auth='admin')
-    def handshake(self):
-        return True
+    @http.route('/hw_proxy/status', type='http', auth='admin')
+    def status_http(self):
+        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')
     def scan_item_success(self, ean):
index cd70a35..3e487ca 100644 (file)
@@ -26,7 +26,9 @@ except ImportError:
 class Scanner(Thread):
     def __init__(self):
         Thread.__init__(self)
+        self.status = {'status':'connecting', 'messages':[]}
         self.input_dir = '/dev/input/by-id/'
+        self.barcodes = Queue()
         self.keymap = {
             2: ("1","!"),
             3: ("2","@"),
@@ -84,6 +86,24 @@ class Scanner(Thread):
             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):
         try:
             if not evdev:
@@ -92,14 +112,16 @@ class Scanner(Thread):
             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()) ]
             if len(scanners) > 0:
+                self.set_status('connected','Connected to '+scanners[0])
                 return evdev.InputDevice(join(self.input_dir,scanners[0]))
             elif len(keyboards) > 0:
+                self.set_status('connected','Connected to '+keyboards[0])
                 return evdev.InputDevice(join(self.input_dir,keyboards[0]))
             else:
-                _logger.error('Could not find the Barcode Scanner')
+                self.set_status('disconnected','Barcode Scanner Not Found')
                 return None
         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
 
     @http.route('/hw_proxy/Vis_scanner_connected', type='json', auth='admin')
@@ -120,6 +142,9 @@ class Scanner(Thread):
                     return barcode
             except Empty:
                 return ''
+    
+    def get_status(self):
+        return self.status
 
     def run(self):
         """ This will start a loop that catches all keyboard events, parse barcode
@@ -138,7 +163,7 @@ class Scanner(Thread):
                 try:
                     device.ungrab() 
                 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()
             if not device:
                 time.sleep(5)   # wait until a suitable device is plugged
@@ -173,17 +198,13 @@ class Scanner(Thread):
                                         shift = False
 
                 except Exception as e:
-                    _logger.error('Could not read Barcode Scanner Events:\n Exception: '+str(e))
+                    self.set_status('error',str(e))
 
 s = Scanner()
 
+hw_proxy.drivers['scanner'] = s
+
 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')
     def scanner(self):
         if not s.isAlive():