+# -*- coding: utf-8 -*-
+import logging
+import os
+import time
+from os import listdir
+from os.path import join
+from threading import Thread, Lock
+from select import select
+from Queue import Queue, Empty
+from bitstring import BitArray
+
+import openerp
+import openerp.addons.hw_proxy.controllers.main as hw_proxy
+from openerp import http
+from openerp.http import request
+from openerp.tools.translate import _
+
+_logger = logging.getLogger(__name__)
+
+try:
+ import serial
+except ImportError:
+ _logger.error('OpenERP module hw_scale depends on the pyserial python module')
+ serial = None
+
+
+class Scale(Thread):
+ def __init__(self):
+ Thread.__init__(self)
+ self.lock = Lock()
+ self.scalelock = Lock()
+ self.status = {'status':'connecting', 'messages':[]}
+ self.input_dir = '/dev/serial/by-id/'
+ self.weight = 0
+ self.weight_info = 'ok'
+ self.device = None
+
+ def lockedstart(self):
+ with self.lock:
+ if not self.isAlive():
+ self.daemon = True
+ self.start()
+
+ 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('Scale Error: '+message)
+ elif status == 'disconnected' and message:
+ _logger.warning('Disconnected Scale: '+message)
+
+ def get_device(self):
+ try:
+ devices = [ device for device in listdir(self.input_dir)]
+ scales = [ device for device in devices if ('mettler' in device.lower()) or ('toledo' in device.lower()) ]
+ if len(scales) > 0:
+ print join(self.input_dir,scales[0])
+ self.set_status('connected','Connected to '+scales[0])
+# s = serial.Serial("/dev/serial/by-id/usb-METTLER_TOLEDO_15_kg_DI_Firmware_CKOR_F_Ser_CDC-if00",baudrate=9600,bytesize=serial.SEVENBITS,parity=serial.PARITY_EVEN)
+ return serial.Serial(join(self.input_dir,scales[0]),
+ baudrate = 9600,
+ bytesize = serial.SEVENBITS,
+ stopbits = serial.STOPBITS_ONE,
+ parity = serial.PARITY_EVEN,
+ #xonxoff = serial.XON,
+ timeout = 0.01,
+ writeTimeout= 0.01)
+ else:
+ self.set_status('disconnected','Scale Not Found')
+ return None
+ except Exception as e:
+ self.set_status('error',str(e))
+ return None
+
+ def get_weight(self):
+ self.lockedstart()
+ return self.weight
+
+ def get_weight_info(self):
+ self.lockedstart()
+ return self.weight_info
+
+ def get_status(self):
+ self.lockedstart()
+ return self.status
+
+ def read_weight(self):
+ with self.scalelock:
+ if self.device:
+ try:
+ self.device.write('W')
+ time.sleep(0.2)
+ answer = []
+
+ while True:
+ char = self.device.read(1)
+ if not char:
+ break
+ else:
+ answer.append(char)
+
+ if '?' in answer:
+ stat = ord(answer[answer.index('?')+1])
+ if stat == 0:
+ self.weight_info = 'ok'
+ else:
+ self.weight_info = []
+ if stat & 1 :
+ self.weight_info.append('moving')
+ if stat & 1 << 1:
+ self.weight_info.append('over_capacity')
+ if stat & 1 << 2:
+ self.weight_info.append('negative')
+ if stat & 1 << 3:
+ self.weight_info.append('outside_zero_capture_range')
+ if stat & 1 << 4:
+ self.weight_info.append('center_of_zero')
+ if stat & 1 << 5:
+ self.weight_info.append('net_weight')
+ else:
+ answer = answer[1:-1]
+ if 'N' in answer:
+ answer = answer[0:-1]
+ self.weight = float(''.join(answer))
+
+ except Exception as e:
+ self.set_status('error',str(e))
+ self.device = None
+
+ def set_zero(self):
+ with self.scalelock:
+ if self.device:
+ try:
+ self.device.write('Z')
+ except Exception as e:
+ self.set_status('error',str(e))
+ self.device = None
+
+ def set_tare(self):
+ with self.scalelock:
+ if self.device:
+ try:
+ self.device.write('T')
+ except Exception as e:
+ self.set_status('error',str(e))
+ self.device = None
+
+ def clear_tare(self):
+ with self.scalelock:
+ if self.device:
+ try:
+ self.device.write('C')
+ except Exception as e:
+ self.set_status('error',str(e))
+ self.device = None
+
+ def run(self):
+ self.device = None
+
+ while True:
+ if self.device:
+ self.read_weight()
+ time.sleep(0.05)
+ else:
+ with self.scalelock:
+ self.device = self.get_device()
+ if not self.device:
+ time.sleep(5)
+
+s = Scale()
+
+hw_proxy.drivers['scale'] = s
+
+class ScaleDriver(hw_proxy.Proxy):
+ @http.route('/hw_proxy/scale_read/', type='json', auth='none', cors='*')
+ def scale_read(self):
+ return {'weight':s.get_weight(), 'unit':'kg', 'info':s.get_weight_info()}
+
+ @http.route('/hw_proxy/scale_zero/', type='json', auth='none', cors='*')
+ def scale_zero(self):
+ s.set_zero()
+ return True
+
+ @http.route('/hw_proxy/scale_tare/', type='json', auth='none', cors='*')
+ def scale_tare(self):
+ s.set_tare()
+ return True
+
+ @http.route('/hw_proxy/scale_clear_tare/', type='json', auth='none', cors='*')
+ def scale_clear_tare(self):
+ s.clear_tare()
+ return True
+
+