Merge pull request #1383 from odoo-dev/master-quote-remove-editbutton-jas
[odoo/odoo.git] / addons / hw_scale / controllers / main.py
1 # -*- coding: utf-8 -*-
2 import logging
3 import os
4 import time
5 from os import listdir
6 from os.path import join
7 from threading import Thread, Lock
8 from select import select
9 from Queue import Queue, Empty
10
11 import openerp
12 import openerp.addons.hw_proxy.controllers.main as hw_proxy
13 from openerp import http
14 from openerp.http import request
15 from openerp.tools.translate import _
16
17 _logger = logging.getLogger(__name__)
18
19 try:
20     import serial
21 except ImportError:
22     _logger.error('OpenERP module hw_scale depends on the pyserial python module')
23     serial = None
24
25
26 class Scale(Thread):
27     def __init__(self):
28         Thread.__init__(self)
29         self.lock = Lock()
30         self.scalelock = Lock()
31         self.status = {'status':'connecting', 'messages':[]}
32         self.input_dir = '/dev/serial/by-id/'
33         self.weight = 0
34         self.weight_info = 'ok'
35         self.device = None
36
37     def lockedstart(self):
38         with self.lock:
39             if not self.isAlive():
40                 self.daemon = True
41                 self.start()
42
43     def set_status(self, status, message = None):
44         if status == self.status['status']:
45             if message != None and message != self.status['messages'][-1]:
46                 self.status['messages'].append(message)
47         else:
48             self.status['status'] = status
49             if message:
50                 self.status['messages'] = [message]
51             else:
52                 self.status['messages'] = []
53
54         if status == 'error' and message:
55             _logger.error('Scale Error: '+message)
56         elif status == 'disconnected' and message:
57             _logger.warning('Disconnected Scale: '+message)
58
59     def get_device(self):
60         try:
61             devices = [ device for device in listdir(self.input_dir)]
62             scales  = [ device for device in devices if ('mettler' in device.lower()) or ('toledo' in device.lower()) ]
63             if len(scales) > 0:
64                 print join(self.input_dir,scales[0])
65                 self.set_status('connected','Connected to '+scales[0])
66                 return serial.Serial(join(self.input_dir,scales[0]), 
67                         baudrate = 9600, 
68                         bytesize = serial.SEVENBITS, 
69                         stopbits = serial.STOPBITS_ONE, 
70                         parity   = serial.PARITY_EVEN, 
71                         #xonxoff  = serial.XON,
72                         timeout  = 0.01, 
73                         writeTimeout= 0.01)
74             else:
75                 self.set_status('disconnected','Scale Not Found')
76                 return None
77         except Exception as e:
78             self.set_status('error',str(e))
79             return None
80
81     def get_weight(self):
82         self.lockedstart()
83         return self.weight
84
85     def get_weight_info(self):
86         self.lockedstart()
87         return self.weight_info
88     
89     def get_status(self):
90         self.lockedstart()
91         return self.status
92
93     def read_weight(self):
94         with self.scalelock:
95             if self.device:
96                 try:
97                     self.device.write('W')
98                     time.sleep(0.1)
99                     answer = []
100
101                     while True:
102                         char = self.device.read(1)
103                         if not char: 
104                             break
105                         else:
106                             answer.append(char)
107
108                     if '?' in answer:
109                         stat = ord(answer[answer.index('?')+1])
110                         if stat == 0: 
111                             self.weight_info = 'ok'
112                         else:
113                             self.weight_info = []
114                             if stat & 1 :
115                                 self.weight_info.append('moving')
116                             if stat & 1 << 1:
117                                 self.weight_info.append('over_capacity')
118                             if stat & 1 << 2:
119                                 self.weight_info.append('negative')
120                                 self.weight = 0.0
121                             if stat & 1 << 3:
122                                 self.weight_info.append('outside_zero_capture_range')
123                             if stat & 1 << 4:
124                                 self.weight_info.append('center_of_zero')
125                             if stat & 1 << 5:
126                                 self.weight_info.append('net_weight')
127                     else:
128                         answer = answer[1:-1]
129                         if 'N' in answer:
130                             answer = answer[0:-1]
131                         try:
132                             self.weight = float(''.join(answer))
133                         except ValueError as v:
134                             self.set_status('error','No data Received, please power-cycle the scale');
135                             self.device = None
136                         
137                 except Exception as e:
138                     self.set_status('error',str(e))
139                     self.device = None
140
141     def set_zero(self):
142         with self.scalelock:
143             if self.device:
144                 try: 
145                     self.device.write('Z')
146                 except Exception as e:
147                     self.set_status('error',str(e))
148                     self.device = None
149
150     def set_tare(self):
151         with self.scalelock:
152             if self.device:
153                 try: 
154                     self.device.write('T')
155                 except Exception as e:
156                     self.set_status('error',str(e))
157                     self.device = None
158
159     def clear_tare(self):
160         with self.scalelock:
161             if self.device:
162                 try: 
163                     self.device.write('C')
164                 except Exception as e:
165                     self.set_status('error',str(e))
166                     self.device = None
167
168     def run(self):
169         self.device   = None
170
171         while True: 
172             if self.device:
173                 self.read_weight()
174                 time.sleep(0.05)
175             else:
176                 with self.scalelock:
177                     self.device = self.get_device()
178                 if not self.device:
179                     time.sleep(5)
180
181 s = Scale()
182
183 hw_proxy.drivers['scale'] = s
184
185 class ScaleDriver(hw_proxy.Proxy):
186     @http.route('/hw_proxy/scale_read/', type='json', auth='none', cors='*')
187     def scale_read(self):
188         return {'weight':s.get_weight(), 'unit':'kg', 'info':s.get_weight_info()}
189
190     @http.route('/hw_proxy/scale_zero/', type='json', auth='none', cors='*')
191     def scale_zero(self):
192         s.set_zero()
193         return True
194
195     @http.route('/hw_proxy/scale_tare/', type='json', auth='none', cors='*')
196     def scale_tare(self):
197         s.set_tare()
198         return True
199
200     @http.route('/hw_proxy/scale_clear_tare/', type='json', auth='none', cors='*')
201     def scale_clear_tare(self):
202         s.clear_tare()
203         return True
204         
205