From 1f845e9110529963f360a9dcab07eeb99cda9431 Mon Sep 17 00:00:00 2001 From: lejeune quentin Date: Wed, 7 Nov 2018 09:35:26 +0100 Subject: [PATCH 1/5] [IMP] IoT : IoT refactoring - With longpolling Improve the implementation of IoT. Allow both-direction communication between iot box and devices. Now a device can send its value / status as soon as it changes. Not only when he receives a request. Now the box have only 3 routes: /hw_drivers/action parameter: session_id, device_id, data used to ask at a device to make a action (take picture, make print, ect...) /hw_drivers/event parameter: listener listener is a dict where you have the session_id and a list of device_id to listen this route wait to answer that we call device_changed for a device_id with data or value /hw_drivers/box/connect parameter: token used to register the box to a Odoo database token contain the url of Odoo database and a unique number that allow the IoT Box to connect box in the hour task : 1906910 --- addons/hw_drivers/controllers/__init__.py | 3 +- addons/hw_drivers/controllers/driver.py | 720 +++++++++--------- addons/hw_drivers/controllers/loading.py | 34 - addons/hw_posbox_homepage/controllers/main.py | 158 ++-- addons/hw_posbox_homepage/views/homepage.html | 3 +- .../views/remote_connect.html | 2 +- .../etc/nginx/sites-enabled/default | 6 +- .../odoo/addons/point_of_sale/__manifest__.py | 2 + .../python3.5/dist-packages/v4l2.py.iotpatch | 20 + .../etc/init_posbox_image.sh | 17 +- .../tools/posbox/posbox_create_image.sh | 8 + .../tools/posbox/posbox_download_images.sh | 5 +- 12 files changed, 457 insertions(+), 521 deletions(-) delete mode 100644 addons/hw_drivers/controllers/loading.py create mode 100644 addons/point_of_sale/tools/posbox/overwrite_after_init/home/pi/odoo/addons/point_of_sale/__manifest__.py create mode 100644 addons/point_of_sale/tools/posbox/overwrite_after_init/usr/local/lib/python3.5/dist-packages/v4l2.py.iotpatch diff --git a/addons/hw_drivers/controllers/__init__.py b/addons/hw_drivers/controllers/__init__.py index 3bd726d7111..8a59703b3c1 100644 --- a/addons/hw_drivers/controllers/__init__.py +++ b/addons/hw_drivers/controllers/__init__.py @@ -1,2 +1 @@ -from . import driver -from . import loading \ No newline at end of file +from . import driver \ No newline at end of file diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py index 3772dfa32f9..233b7422ea5 100755 --- a/addons/hw_drivers/controllers/driver.py +++ b/addons/hw_drivers/controllers/driver.py @@ -1,67 +1,95 @@ #!/usr/bin/python3 import logging import time -from threading import Thread -import usb -import gatt +from threading import Thread, Event +from usb import core +from gatt import DeviceManager as Gatt_DeviceManager import subprocess -import netifaces as ni +import netifaces import json -import re -from odoo import http +from re import sub import urllib3 -from odoo.http import request as httprequest -import datetime +import os +import socket +from importlib import util +import v4l2 +from fcntl import ioctl +from cups import Connection as cups_connection +from glob import glob +from base64 import b64decode +from pathlib import Path -logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s: %(message)s') -_logger = logging.getLogger('dispatcher') +from odoo import http, _ +from odoo.modules.module import get_resource_path -owner_dict = {} -last_ping = {} +_logger = logging.getLogger(__name__) + + +#---------------------------------------------------------- +# Helper +#---------------------------------------------------------- + +def get_mac_address(): + try: + return netifaces.ifaddresses('eth0')[netifaces.AF_LINK][0]['addr'] + except: + return netifaces.ifaddresses('wlan0')[netifaces.AF_LINK][0]['addr'] + +def get_ip(): + try: + return netifaces.ifaddresses('eth0')[netifaces.AF_INET][0]['addr'] + except: + return netifaces.ifaddresses('wlan0')[netifaces.AF_INET][0]['addr'] + +def read_file_first_line(filename): + path = Path.home() / filename + if path.exists(): + with path.open('r') as f: + return f.readline().strip('\n') + return '' + +def get_odoo_server_url(): + return read_file_first_line('odoo-remote-server.conf') + +def get_token(): + return read_file_first_line('token') + +def get_version(): + return '19_04' + +#---------------------------------------------------------- +# Controllers +#---------------------------------------------------------- class StatusController(http.Controller): + @http.route('/hw_drivers/action', type='json', auth='none', cors='*', csrf=False, save_session=False) + def action(self, session_id, device_id, data): + """ + This route is called when we want to make a action with device (take picture, printing,...) + We specify in data from which session_id that action is called + And call the action of specific device + """ + iot_device = iot_devices.get(device_id) + if iot_device: + iot_device.data['owner'] = session_id + data = json.loads(data) + iot_device.action(data) + return True + return False - @http.route('/hw_drivers/owner/check', type='json', auth='none', cors='*', csrf=False) - def check_cantakeowner(self): #, devices, tab - data = httprequest.jsonrequest - for device in data['devices']: - if owner_dict.get(device) and owner_dict[device] != data['tab']: - before_date = datetime.datetime.now() - datetime.timedelta(seconds=10) - if last_ping.get(owner_dict[device]) and last_ping.get(owner_dict[device]) > before_date: - return 'no' - else: - old_tab = owner_dict[device] - for dev2 in owner_dict: - if owner_dict[dev2] == old_tab: - owner_dict[dev2] = '' - return 'yes' - - @http.route('/hw_drivers/owner/take', type='json', auth='none', cors='*', csrf=False) - def take_ownership(self): #, devices, tab - data = httprequest.jsonrequest - for device in data['devices']: - owner_dict[device] = data['tab'] - last_ping[data['tab']] = datetime.datetime.now() - return data['tab'] - - @http.route('/hw_drivers/owner/ping', type='json', auth='none', cors='*', csrf=False) - def ping_trigger(self): #, tab - data = httprequest.jsonrequest - ping_dict = {} - last_ping[data['tab']] = datetime.datetime.now() - for dev in data['devices']: - if owner_dict.get(dev) and owner_dict[dev] == data['tab']: - for driver_path in drivers: - if driver_path.find(dev) == 0 and drivers[driver_path].ping_value: - ping_dict[dev] = drivers[driver_path].ping_value - drivers[driver_path].ping_value = '' # or set it to nothing - else: - ping_dict[dev] = 'STOP' - return ping_dict + @http.route('/hw_drivers/event', type='json', auth='none', cors='*', csrf=False, save_session=False) + def event(self, listener): + """ + listener is a dict in witch there are a sessions_id and a dict of device_id to listen + """ + req = event_manager.add_request(listener) + if req['event'].wait(50): + req['event'].clear() + req['result']['session_id'] = req['session_id'] + return req['result'] @http.route('/hw_drivers/box/connect', type='json', auth='none', cors='*', csrf=False) - def connect_box(self): - data = httprequest.jsonrequest + def connect_box(self, token): server = "" # read from file try: f = open('/home/pi/odoo-remote-server.conf', 'r') @@ -75,358 +103,298 @@ class StatusController(http.Controller): return 'This IoTBox has already been connected' else: iotname = '' - token = data['token'].split('|')[1] - url = data['token'].split('|')[0] + token = token.split('|')[1] + url = token.split('|')[0] reboot = 'noreboot' - subprocess.call(['/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh', url, iotname, token, reboot]) + subprocess.call([home() + '/odoo/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh', url, iotname, token, reboot]) send_iot_box_device(False) return 'IoTBox connected' - @http.route('/hw_drivers/drivers/status', type='http', auth='none', cors='*') - def status(self): - result = "List of drivers and values:
" - result +=" " - return result - - @http.route('/hw_drivers/driverdetails/', type='http', auth='none', cors='*') - def statusdetail(self, identifier): - for device in drivers: - if device.find(identifier) != -1: - return str(drivers[device].value) - return '' - - @http.route('/hw_drivers/driveraction/', type='json', auth='none', cors='*', csrf=False) - def driveraction(self, identifier): - data = httprequest.jsonrequest - result = 'device not found' - if data.get('action') == 'print': - with open('/tmp/toprinter', 'w') as file: - file.write(data['data']) - subprocess.call("cat /tmp/toprinter | base64 -d | lp -d " + identifier, shell=True) - result = 'ok' - if data.get('action') == 'camera': - cameras = subprocess.check_output("v4l2-ctl --list-devices", shell=True).decode('utf-8').split('\n\n') - adrress = '/dev/video0' - for camera in cameras: - if camera: - camera = camera.split('\n\t') - serial = re.sub('[^a-zA-Z0-9 ]+', '', camera[0].split(': ')[0]).replace(' ','_') - if serial == data.get('identifier'): - adrress = camera[1] - picture = subprocess.check_output("v4l2-ctl --list-formats-ext|grep 'Size'|awk '{print $3}'|sort -rn|awk NR==1", shell=True).decode('utf-8') - subprocess.call("fswebcam -d " + adrress + " /tmp/testimage -r " + picture, shell=True) - image_bytes = subprocess.check_output('cat /tmp/testimage | base64',shell=True) - result = {'image': image_bytes} - return result - - @http.route('/hw_drivers/send_iot_box', type='http', auth='none', cors='*') - def send_iot_box(self): - send_iot_box_device(False) - return 'ok' - #---------------------------------------------------------- -# Driver common interface +# Drivers #---------------------------------------------------------- -class Driver(Thread): - ping_value = "" - def supported(self): - pass +drivers = [] +bt_devices = {} +iot_devices = {} - def value(self): - pass - - def get_name(self): - pass - - def get_connection(self): - pass - - def action(self, action): - pass - -#---------------------------------------------------------- -# Usb drivers -#---------------------------------------------------------- -usbdrivers = [] -drivers = {} - -class UsbMetaClass(type): +class DriverMetaClass(type): def __new__(cls, clsname, bases, attrs): - newclass = super(UsbMetaClass, cls).__new__(cls, clsname, bases, attrs) - usbdrivers.append(newclass) + newclass = super(DriverMetaClass, cls).__new__(cls, clsname, bases, attrs) + drivers.append(newclass) return newclass -class USBDriver(Driver,metaclass=UsbMetaClass): - def __init__(self, dev): - super(USBDriver, self).__init__() +class Driver(Thread, metaclass=DriverMetaClass): + """ + Hook to register the driver into the drivers list + """ + connection_type = "" + + def __init__(self, device): + super(Driver, self).__init__() + self.dev = device + self.data = {'value': ''} + self.gatt_device = False + + @property + def device_name(self): + return self._device_name + + @property + def device_identifier(self): + return self._device_identifier + + @property + def device_connection(self): + """ + On specific driver override this method to give connection type of device + return string + possible value : direct - network - bluetooth + """ + return self._device_connection + + @property + def device_type(self): + """ + On specific driver override this method to give type of device + return string + possible value : printer - camera - device + """ + return self._device_type + + @classmethod + def supported(cls, device): + """ + On specific driver override this method to check if device is supported or not + return True or False + """ + pass + + def get_message(self): + return '' + + def action(self, data): + """ + On specific driver override this method to make a action with device (take picture, printing,...) + """ + raise NotImplementedError() + + def disconnect(self): + del iot_devices[self.device_identifier] + + +#---------------------------------------------------------- +# Device manager +#---------------------------------------------------------- + +class EventManager(object): + def __init__(self): + self.sessions = {} + + def _delete_expired_sessions(self, max_time=70): + ''' + Clears sessions that are no longer called. + + :param max_time: time a session can stay unused before being deleted + ''' + now = time.time() + expired_sessions = [session for session in self.sessions if now - self.sessions[session]['time_request'] > max_time] + for session in expired_sessions: + del self.sessions[session] + + def add_request(self, listener): + self.session = { + 'session_id': listener['session_id'], + 'devices': listener['devices'], + 'event': Event(), + 'result': {}, + 'time_request': time.time(), + } + self._delete_expired_sessions() + self.sessions[listener['session_id']] = self.session + return self.sessions[listener['session_id']] + + def device_changed(self, device): + for session in self.sessions: + if device.device_identifier in self.sessions[session]['devices']: + self.sessions[session]['result'] = device.data + self.sessions[session]['result']['device_id'] = device.device_identifier + self.sessions[session]['event'].set() + + +class IoTDevice(object): + + def __init__(self, dev, connection_type): self.dev = dev - self.value = "" + self.connection_type = connection_type - def get_name(self): - lsusb = str(subprocess.check_output('lsusb')).split("\\n") - for usbpath in lsusb: # Should filter on usb devices or inverse loops? - device = self.dev - if "%04x:%04x" % (device.idVendor, device.idProduct) in usbpath: - return usbpath.split("%04x:%04x" % (device.idVendor, device.idProduct))[1] - return str(device.idVendor) + ":" + str(device.idProduct) - - def get_connection(self): - return 'direct' - - def value(self): - return self.value +event_manager = EventManager() #---------------------------------------------------------- -# Bluetooth +# Manager #---------------------------------------------------------- -class GattBtManager(gatt.DeviceManager): + +class Manager(Thread): + + def __init__(self): + super(Manager, self).__init__() + self.load_drivers() + + def load_drivers(self): + """ + This method loads local files: 'odoo/addons/hw_drivers/drivers' + And execute these python drivers + """ + path = get_resource_path('hw_drivers', 'drivers') + driversList = os.listdir(path) + for driver in driversList: + path_file = os.path.join(path, driver) + spec = util.spec_from_file_location(driver, path_file) + if spec: + module = util.module_from_spec(spec) + spec.loader.exec_module(module) + + def send_alldevices(self): + """ + This method send IoT Box and devices informations to Odoo database + """ + server = get_odoo_server_url() + if server: + iot_box = { + 'name': socket.gethostname(), + 'identifier': get_mac_address(), + 'ip': get_ip(), + 'token': get_token(), + 'version': get_version() + } + devices_list = {} + for device in iot_devices: + identifier = iot_devices[device].device_identifier + devices_list[identifier] = { + 'name': iot_devices[device].device_name, + 'type': iot_devices[device].device_type, + 'connection': iot_devices[device].device_connection, + } + data = { + 'params': { + 'data' : iot_box, + 'devices' : devices_list, + } + } + # disable certifiacte verification + urllib3.disable_warnings() + http = urllib3.PoolManager(cert_reqs='CERT_NONE') + try: + http.request( + 'POST', + server + "/iot/setup", + body = json.dumps(data).encode('utf8'), + headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} + ) + except Exception as e: + _logger.error('Could not reach configured server') + _logger.error('A error encountered : %s ' % e) + else: + _logger.warning('Odoo server not set') + + def usb_loop(self): + usb_devices = {} + devs = core.find(find_all=True) + for dev in devs: + path = "usb_%04x:%04x_%03d_%03d_" % (dev.idVendor, dev.idProduct, dev.bus, dev.address) + iot_device = IoTDevice(dev, 'usb') + usb_devices[path] = iot_device + return usb_devices + + def video_loop(self): + camera_devices = {} + videos = glob('/dev/video*') + for video in videos: + with open(video, 'w') as path: + dev = v4l2.v4l2_capability() + ioctl(path, v4l2.VIDIOC_QUERYCAP, dev) + dev.interface = video + iot_device = IoTDevice(dev, 'video') + camera_devices[dev.bus_info.decode('utf-8')] = iot_device + return camera_devices + + def printer_loop(self): + printer_devices = {} + devices = conn.getDevices() + for path in [printer_lo for printer_lo in devices if devices[printer_lo]['device-make-and-model'] != 'Unknown']: + if 'uuid=' in path: + serial = sub('[^a-zA-Z0-9 ]+', '', path.split('uuid=')[1]) + elif 'serial=' in path: + serial = sub('[^a-zA-Z0-9 ]+', '', path.split('serial=')[1]) + else: + serial = sub('[^a-zA-Z0-9 ]+', '', path) + devices[path]['identifier'] = serial + devices[path]['url'] = path + iot_device = IoTDevice(devices[path], 'printer') + printer_devices[serial] = iot_device + return printer_devices + + def run(self): + """ + Thread that will check connected/disconnected device, load drivers if needed and contact the odoo server with the updates + """ + devices = {} + updated_devices = {} + self.send_alldevices() + cpt = 0 + while 1: + updated_devices = self.usb_loop() + updated_devices.update(self.video_loop()) + updated_devices.update(bt_devices) + if cpt % 40 == 0: + printer_devices = self.printer_loop() + cpt = 0 + updated_devices.update(printer_devices) + cpt += 1 + added = updated_devices.keys() - devices.keys() + removed = devices.keys() - updated_devices.keys() + devices = updated_devices + for path in [device_rm for device_rm in removed if device_rm in iot_devices]: + iot_devices[path].disconnect() + for path in [device_add for device_add in added if device_add not in iot_devices]: + for driverclass in [d for d in drivers if d.connection_type == devices[path].connection_type]: + if driverclass.supported(device = updated_devices[path].dev): + _logger.info('For device %s will be driven', path) + d = driverclass(device = updated_devices[path].dev) + d.daemon = True + d.start() + iot_devices[path] = d + self.send_alldevices() + break + time.sleep(3) + +class GattBtManager(Gatt_DeviceManager): def device_discovered(self, device): - # TODO: need some kind of updated_devices mechanism or not? path = "bt_%s" % (device.mac_address,) - if path not in drivers: - for driverclass in btdrivers: - d = driverclass(device = device, manager=self) - if d.supported(): - drivers[path] = d - d.connect() - send_iot_box_device(False) - + if path not in bt_devices: + device.manager = self + iot_device = IoTDevice(device, 'bluetooth') + bt_devices[path] = iot_device class BtManager(Thread): - gatt_manager = False def run(self): dm = GattBtManager(adapter_name='hci0') - self.gatt_manager = dm + for device in [device_con for device_con in dm.devices() if device_con.is_connected()]: + device.disconnect() dm.start_discovery() dm.run() -#---------------------------------------------------------- -# Bluetooth drivers -#---------------------------------------------------------- -btdrivers = [] - -class BtMetaClass(type): - def __new__(cls, clsname, bases, attrs): - newclass = super(BtMetaClass, cls).__new__(cls, clsname, bases, attrs) - btdrivers.append(newclass) - return newclass - - -class BtDriver(Driver, metaclass=BtMetaClass): - - - def __init__(self, device, manager): - super(BtDriver, self).__init__() - self.dev = device - self.manager = manager - self.value = '' - self.gatt_device = False - - def disconnect(self): - path = "bt_%s" % (self.dev.mac_address,) - del drivers[path] - - def get_name(self): - return self.dev.alias() - - def value(self): - return self.value - - def action(self, action): - pass - - def get_connection(self): - return 'bluetooth' - - def connect(self): - pass - - - - - - -class USBDeviceManager(Thread): - devices = {} - def run(self): - first_time = True - send_iot_box_device(False) - while 1: - sendJSON = False - devs = usb.core.find(find_all=True) - updated_devices = {} - for dev in devs: - path = "usb_%04x:%04x_%03d_%03d_" % (dev.idVendor, dev.idProduct, dev.bus, dev.address) - updated_devices[path] = self.devices.get(path, dev) - added = updated_devices.keys() - self.devices.keys() - removed = self.devices.keys() - updated_devices.keys() - self.devices = updated_devices - if (removed): - for path in list(drivers): - if (path in removed): - del drivers[path] - sendJSON = True - for path in added: - dev = updated_devices[path] - for driverclass in usbdrivers: - d = driverclass(updated_devices[path]) - if d.supported(): - _logger.info('For device %s will be driven', path) - drivers[path] = d - # launch thread - d.daemon = True - d.start() - sendJSON = True - if sendJSON or first_time: - send_iot_box_device(send_printer = first_time) - first_time = False - time.sleep(3) - - - - - -def send_iot_box_device(send_printer): - maciotbox = subprocess.check_output("/sbin/ifconfig eth0 |grep -Eo ..\(\:..\){5}", shell=True).decode('utf-8').split('\n')[0] - server = "" # read from file - try: - f = open('/home/pi/odoo-remote-server.conf', 'r') - for line in f: - server += line - f.close() - except: #In case the file does not exist - server='' - server = server.split('\n')[0] - if server: - url = server + "/iot/setup" - interfaces = ni.interfaces() - for iface_id in interfaces: - iface_obj = ni.ifaddresses(iface_id) - ifconfigs = iface_obj.get(ni.AF_INET, []) - for conf in ifconfigs: - if conf.get('addr') and conf.get('addr') != '127.0.0.1': - ips = conf.get('addr') - break - - # Build device JSON - devicesList = {} - for path in drivers: - device_name = drivers[path].get_name() - device_connection = drivers[path].get_connection() - identifier = path.split('_')[0] + '_' + path.split('_')[1] - devicesList[identifier] = {'name': device_name, - 'type': 'device', - 'connection': device_connection} - - # Build camera JSON - try: - cameras = subprocess.check_output("v4l2-ctl --list-devices", shell=True).decode('utf-8').split('\n\n') - for camera in cameras: - if camera: - camera = camera.split('\n\t') - serial = re.sub('[^a-zA-Z0-9 ]+', '', camera[0].split(': ')[0]).replace(' ','_') - devicesList[serial] = { - 'name': camera[0].split(': ')[0], - 'connection': 'direct', - 'type': 'camera' - } - except: - pass - - # Build printer JSON - printerList = {} - if send_printer: - printers = subprocess.check_output("sudo lpinfo -lv", shell=True).decode('utf-8').split('Device') - printers_installed = '' - try: - printers_installed = subprocess.check_output("sudo lpstat -a", shell=True).decode('utf-8') - except: - pass - for printer in printers: - printerTab = printer.split('\n') - if printer and printerTab[4].split('=')[1] != ' ' or 'lpd://' in printerTab[0]: - device_connection = printerTab[1].split('= ')[1] - model = '' - for device_id in printerTab[4].split('= ')[1].split(';'): - if any(x in device_id for x in ['MDL','MODEL']): - model = device_id.split(':')[1] - serial = re.sub('[^a-zA-Z0-9 ]+', '', model).replace(' ','_') - identifier = '' - if device_connection == 'direct': - identifier = serial + '_' + maciotbox #name + macIOTBOX - elif device_connection == 'network' and 'socket' in printerTab[0]: - socketIP = printerTab[0].split('://')[1] - macprinter = subprocess.check_output("arp -a " + socketIP + " |awk NR==1'{print $4}'", shell=True).decode('utf-8').split('\n')[0] - identifier = macprinter # macPRINTER - elif device_connection == 'network' and 'lpd' in printerTab[0]: - identifier = re.sub('[^a-zA-Z0-9 ]+', '', printerTab[0].split('://')[1]) - model = printerTab[2].split('= ')[1] - elif device_connection == 'network' and 'dnssd' in printerTab[0]: - hostname_printer = subprocess.check_output("ippfind -n \"" + model + "\" | awk \'{split($0,a,\"/\"); print a[3]}\' | awk \'{split($0,b,\":\"); print b[1]}\'", shell=True).decode('utf-8').split('\n')[0] - if hostname_printer: - macprinter = subprocess.check_output("arp -a " + hostname_printer + " |awk NR==1'{print $4}'", shell=True).decode('utf-8').split('\n')[0] - identifier = macprinter # macprinter - - identifier = identifier.replace(':','_') - if identifier and identifier not in printerList: - printerList[identifier] = { - 'name': model, - 'connection': device_connection, - 'type': 'printer' - } - - if identifier not in printers_installed: - # install these printers - try: - ppd = subprocess.check_output("sudo lpinfo -m |grep '" + model + "'", shell=True).decode('utf-8').split('\n') - if len(ppd) > 2: - subprocess.call("sudo lpadmin -p '" + identifier + "' -E -v '" + printerTab[0].split('= ')[1] + "'", shell=True) - else: - subprocess.call("sudo lpadmin -p '" + identifier + "' -E -v '" + printerTab[0].split('= ')[1] + "' -m '" + ppd[0].split(' ')[0] + "'", shell=True) - except: - subprocess.call("sudo lpadmin -p '" + identifier + "' -E -v '" + printerTab[0].split('= ')[1] + "'", shell=True) - subprocess.call('> /tmp/printers', shell=True) - for printer in printerList: - subprocess.call('echo "' + printerList[printer]['name'] + '" >> /tmp/printers', shell=True) - - if devicesList: - subprocess.call('> /tmp/devices', shell=True) - for device in devicesList: - subprocess.call('echo "' + str(device) + '|' + devicesList[device]['name'] + '" >> /tmp/devices', shell=True) - - #build JSON with all devices - hostname = subprocess.check_output('hostname').decode('utf-8').split('\n')[0] - token = "" # read from file - try: - f = open('/home/pi/token', 'r') - for line in f: - token += line - f.close() - except: #In case the file does not exist - token='' - token = token.split('\n')[0] - data = {'name': hostname,'identifier': maciotbox, 'ip': ips, 'token': token} - devicesList.update(printerList) - data['devices'] = devicesList - data_json = json.dumps(data).encode('utf8') - headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} - urllib3.disable_warnings() - http = urllib3.PoolManager(cert_reqs='CERT_NONE') - req = False - try: - req = http.request('POST', - url, - body=data_json, - headers=headers) - except Exception as e: - _logger.warning('Could not reach configured server') - _logger.error('A error encountered : %s ' % e) +conn = cups_connection() +PPDs = conn.getPPDs() +printers = conn.getPrinters() +m = Manager() +m.daemon = True +m.start() +bm = BtManager() +bm.daemon = True +bm.start() diff --git a/addons/hw_drivers/controllers/loading.py b/addons/hw_drivers/controllers/loading.py deleted file mode 100644 index cd02d3dd82f..00000000000 --- a/addons/hw_drivers/controllers/loading.py +++ /dev/null @@ -1,34 +0,0 @@ -import importlib.util -import os -from .driver import BtManager -from .driver import USBDeviceManager -from odoo import modules - -driversList = os.listdir("/home/pi/odoo/addons/hw_drivers/drivers") -for driver in driversList: - path = "/home/pi/odoo/addons/hw_drivers/drivers/" + driver - spec = importlib.util.spec_from_file_location(driver, path) - if spec: - foo = importlib.util.module_from_spec(spec) - spec.loader.exec_module(foo) - - -if not getattr(modules, '_iot_daemon_started', False): - # ---------------------------------------------------------- - # Bluetooth start - # ---------------------------------------------------------- - bm = BtManager() - bm.daemon = True - bm.start() - - #---------------------------------------------------------- - #USB start - #---------------------------------------------------------- - - udm = USBDeviceManager() - udm.daemon = True - udm.start() - - # Did this because of the - modules._iot_daemon_started = True - diff --git a/addons/hw_posbox_homepage/controllers/main.py b/addons/hw_posbox_homepage/controllers/main.py index f3de5a0d138..538b6acbf42 100644 --- a/addons/hw_posbox_homepage/controllers/main.py +++ b/addons/hw_posbox_homepage/controllers/main.py @@ -7,7 +7,7 @@ import jinja2 import subprocess import socket import sys -import netifaces as ni +import netifaces import odoo from odoo import http import zipfile @@ -15,12 +15,28 @@ import io import os from odoo.tools import misc import urllib3 +from pathlib import Path from uuid import getnode as get_mac from odoo.addons.hw_proxy.controllers import main as hw_proxy +from odoo.addons.web.controllers import main as web +from odoo.modules.module import get_resource_path +from odoo.addons.hw_drivers.controllers.driver import iot_devices, get_ip, get_odoo_server_url _logger = logging.getLogger(__name__) + +#---------------------------------------------------------- +# Helper +#---------------------------------------------------------- + +def access_point(): + return get_ip() == '10.11.12.1' + +#---------------------------------------------------------- +# Controllers +#---------------------------------------------------------- + if hasattr(sys, 'frozen'): # When running on compiled windows binary, we don't have access to package loader. path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'views')) @@ -38,18 +54,7 @@ driver_list_template = jinja_env.get_template('driver_list.html') remote_connect_template = jinja_env.get_template('remote_connect.html') configure_wizard_template = jinja_env.get_template('configure_wizard.html') -class IoTboxHomepage(odoo.addons.web.controllers.main.Home): - - def get_ip_iotbox(self): - interfaces = ni.interfaces() - for iface_id in interfaces: - iface_obj = ni.ifaddresses(iface_id) - ifconfigs = iface_obj.get(ni.AF_INET, []) - for conf in ifconfigs: - if conf.get('addr') and conf.get('addr') != '127.0.0.1': - ips = conf.get('addr') - break - return ips +class IoTboxHomepage(web.Home): def get_hw_screen_message(self): return """ @@ -67,18 +72,6 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): statuses[driver] = hw_proxy.drivers[driver].get_status() return statuses - def get_server_status(self): - server_template = "" - try: - f = open('/home/pi/odoo-remote-server.conf', 'r') - for line in f: - server_template += line - f.close() - except: - return '' - - return server_template.split('\n')[0] - def get_homepage_data(self): hostname = str(socket.gethostname()) mac = get_mac() @@ -88,7 +81,7 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): if wired == 'up': network = 'Ethernet' elif ssid: - if self.get_ip_iotbox() == '10.11.12.1': + if access_point(): network = 'Wifi access point' else: network = 'Wifi : ' + ssid @@ -105,70 +98,33 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): 'message': ' '.join(pos_device[status]['messages']) }) - hdmi_name = subprocess.check_output('tvservice -n', shell=True).decode('utf-8') - if hdmi_name.find('=') != -1: - hdmi_name = hdmi_name.split('=')[1] - hdmi_message = subprocess.check_output('tvservice -s', shell=True).decode('utf-8') + for device in iot_devices: iot_device.append({ - 'name': 'display : ' + hdmi_name, - 'type': 'device', - 'message': hdmi_message - }) - - try: - f = open('/tmp/devices', 'r') - for line in f: - url = 'http://' + self.get_ip_iotbox() + ':8069/hw_drivers/driverdetails/' + line.split('|')[0] - urllib3.disable_warnings() - http = urllib3.PoolManager(cert_reqs='CERT_NONE') - value = '' - try: - req = http.request('GET', url) - except Exception as e: - req = '' - _logger.warning('Could not reach configured server') - _logger.error('A error encountered : %s ' % e) - - if req: - value = req.data.decode('utf-8') - iot_device.append({ - 'name': line.split('|')[1], - 'message': line.split('|')[0] + ' : ' + value, - 'type': 'device', - }) - f.close() - except: - pass - - try: - f = open('/tmp/printers', 'r') - for line in f: - iot_device.append({ - 'name': line, - 'type': 'printer', - }) - f.close() - except: - pass + 'name': iot_devices[device].device_name + ' : ' + str(iot_devices[device].data['value']), + 'type': iot_devices[device].device_type, + 'message': iot_devices[device].device_identifier + iot_devices[device].get_message() + }) return { 'hostname': hostname, - 'ip': self.get_ip_iotbox(), + 'ip': get_ip(), 'mac': ":".join(i + next(h) for i in h), 'iot_device_status': iot_device, - 'server_status': self.get_server_status() or 'Not Configured', + 'server_status': get_odoo_server_url() or 'Not Configured', 'network_status': network, } @http.route('/', type='http', auth='none') def index(self): - if (os.path.isfile('/home/pi/wifi_network.txt') == False or os.path.isfile('/home/pi/odoo-remote-server.conf') == False) and self.get_ip_iotbox() == '10.11.12.1': + wifi = Path.home() / 'wifi_network.txt' + remote_server = Path.home() / 'odoo-remote-server.conf' + if (wifi.exists() == False or remote_server.exists() == False) and access_point(): return configure_wizard_template.render({ 'title': 'Configure IoT Box', 'breadcrumb': 'Configure IoT Box', 'loading_message': 'Configuring your IoT Box', 'ssid': self.get_wifi_essid(), - 'server': self.get_server_status(), + 'server': get_odoo_server_url(), 'hostname': subprocess.check_output('hostname').decode('utf-8'), }) else: @@ -177,7 +133,7 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): @http.route('/list_drivers', type='http', auth='none', website=True) def list_drivers(self): drivers_list = [] - for driver in os.listdir("/home/pi/odoo/addons/hw_drivers/drivers"): + for driver in os.listdir(get_resource_path('hw_drivers', 'drivers')): if driver != '__pycache__': drivers_list.append(driver) return driver_list_template.render({ @@ -188,13 +144,13 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): @http.route('/load_drivers', type='http', auth='none', website=True) def load_drivers(self): - subprocess.call("sudo mount -o remount,rw /", shell=True) - subprocess.call("sudo mount -o remount,rw /root_bypass_ramdisks", shell=True) + subprocess.check_call("sudo mount -o remount,rw /", shell=True) + subprocess.check_call("sudo mount -o remount,rw /root_bypass_ramdisks", shell=True) mac = subprocess.check_output("/sbin/ifconfig eth0 |grep -Eo ..\(\:..\){5}", shell=True).decode('utf-8').split('\n')[0] #response = requests.get(url, auth=(username, db_uuid.split('\n')[0]), stream=True) - server = self.get_server_status() + server = get_odoo_server_url() if server: urllib3.disable_warnings() pm = urllib3.PoolManager(cert_reqs='CERT_NONE') @@ -205,17 +161,16 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): server, fields={'mac': mac}) except Exception as e: - req = '' - _logger.warning('Could not reach configured server') + _logger.error('Could not reach configured server') _logger.error('A error encountered : %s ' % e) if resp and resp.data: zip_file = zipfile.ZipFile(io.BytesIO(resp.data)) - zip_file.extractall("/home/pi/odoo/addons/hw_drivers/drivers") - subprocess.call("sudo service odoo restart", shell=True) - subprocess.call("sudo mount -o remount,ro /", shell=True) - subprocess.call("sudo mount -o remount,ro /root_bypass_ramdisks", shell=True) + zip_file.extractall(get_resource_path('hw_drivers', 'drivers')) + subprocess.check_call("sudo service odoo restart", shell=True) + subprocess.check_call("sudo mount -o remount,ro /", shell=True) + subprocess.check_call("sudo mount -o remount,ro /root_bypass_ramdisks", shell=True) - return "" + return "" def get_wifi_essid(self): wifi_options = [] @@ -247,8 +202,8 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): else: persistent = "" - subprocess.call(['/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/connect_to_wifi.sh', essid, password, persistent]) - server = self.get_server_status() + subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_wifi.sh'), essid, password, persistent]) + server = get_odoo_server_url() res_payload = { 'message': 'Connecting to ' + essid, } @@ -262,29 +217,29 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): @http.route('/wifi_clear', type='http', auth='none', cors='*', csrf=False) def clear_wifi_configuration(self): - os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/clear_wifi_configuration.sh') + os.system(get_resource_path('point_of_sale', 'tools/posbox/configuration/clear_wifi_configuration.sh')) - return "" + return "" @http.route('/server_clear', type='http', auth='none', cors='*', csrf=False) def clear_server_configuration(self): - os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/clear_server_configuration.sh') + os.system(get_resource_path('point_of_sale', 'tools/posbox/configuration/clear_server_configuration.sh')) - return "" + return "" @http.route('/drivers_clear', type='http', auth='none', cors='*', csrf=False) def clear_drivers_list(self): - os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/clear_drivers_list.sh') + os.system(get_resource_path('point_of_sale', 'tools/posbox/configuration/clear_drivers_list.sh')) - return "" + return "" @http.route('/server_connect', type='http', auth='none', cors='*', csrf=False) def connect_to_server(self, token, iotname): url = token.split('|')[0] token = token.split('|')[1] reboot = 'reboot' - subprocess.call(['/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh', url, iotname, token, reboot]) - return 'http://' + self.get_ip_iotbox() + ':8069' + subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, iotname, token, reboot]) + return 'http://' + get_ip() + ':8069' @http.route('/steps', type='http', auth='none', cors='*', csrf=False) def step_by_step_configure_page(self): @@ -293,7 +248,7 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): 'breadcrumb': 'Configure IoT Box', 'loading_message': 'Configuring your IoT Box', 'ssid': self.get_wifi_essid(), - 'server': self.get_server_status(), + 'server': get_odoo_server_url(), 'hostname': subprocess.check_output('hostname').decode('utf-8').strip('\n'), }) @@ -304,7 +259,7 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): token = token.split('|')[1] else: url = '' - subprocess.call(['/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/connect_to_server_wifi.sh',url, iotname, token, essid, password, persistent]) + subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server_wifi.sh'), url, iotname, token, essid, password, persistent]) return url # Set server address @@ -314,12 +269,19 @@ class IoTboxHomepage(odoo.addons.web.controllers.main.Home): 'title': 'IoT -> Odoo server configuration', 'breadcrumb': 'Configure Odoo Server', 'hostname': subprocess.check_output('hostname').decode('utf-8').strip('\n'), - 'server_status': self.get_server_status() or 'Not configured yet', + 'server_status': get_odoo_server_url() or 'Not configured yet', 'loading_message': 'Configure Domain Server' }) @http.route('/remote_connect', type='http', auth='none', cors='*') def remote_connect(self): + """ + Establish a link with a customer box trough internet with a ssh tunnel + 1 - take a new auth_token on https://dashboard.ngrok.com/ + 2 - copy past this auth_token on the IoT Box : http://IoT_Box:8069/remote_connect + 3 - check on ngrok the port and url to get access to the box + 4 - you can connect to the box with this command : ssh -p port -v pi@url + """ return remote_connect_template.render({ 'title': 'Remote debugging', 'breadcrumb': 'Remote Debugging', diff --git a/addons/hw_posbox_homepage/views/homepage.html b/addons/hw_posbox_homepage/views/homepage.html index 71c0f26c565..b14573e9805 100644 --- a/addons/hw_posbox_homepage/views/homepage.html +++ b/addons/hw_posbox_homepage/views/homepage.html @@ -28,6 +28,7 @@ } .device-status .message { font-size: 0.8rem; + max-width: 350px; } .device-status .indicator { margin-left: 4px; @@ -90,7 +91,7 @@ Version - V18.12 update + V19.04 update IP Address diff --git a/addons/hw_posbox_homepage/views/remote_connect.html b/addons/hw_posbox_homepage/views/remote_connect.html index e83ced4653c..ab9628ec36a 100644 --- a/addons/hw_posbox_homepage/views/remote_connect.html +++ b/addons/hw_posbox_homepage/views/remote_connect.html @@ -31,7 +31,7 @@ {% block content %}

Remote Debugging

- This allows someone to gain remote access to your IoT Box, and + This allows someone who give a ngrok authtoken to gain remote access to your IoT Box, and thus your entire local network. Only enable this for someone you trust.

diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/nginx/sites-enabled/default b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/nginx/sites-enabled/default index cd95a43753a..fc802829d69 100644 --- a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/nginx/sites-enabled/default +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/nginx/sites-enabled/default @@ -85,7 +85,7 @@ server { root /var/www/; index index.html; # -# location / { -# try_files $uri $uri/ =404; -# } + location /hw_drivers/ { + proxy_pass http://127.0.0.1:8069; + } } diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/home/pi/odoo/addons/point_of_sale/__manifest__.py b/addons/point_of_sale/tools/posbox/overwrite_after_init/home/pi/odoo/addons/point_of_sale/__manifest__.py new file mode 100644 index 00000000000..67dee8c60db --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/home/pi/odoo/addons/point_of_sale/__manifest__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/local/lib/python3.5/dist-packages/v4l2.py.iotpatch b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/local/lib/python3.5/dist-packages/v4l2.py.iotpatch new file mode 100644 index 00000000000..5cc87a78c88 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/local/lib/python3.5/dist-packages/v4l2.py.iotpatch @@ -0,0 +1,20 @@ +--- v4l2_old.py 2019-01-23 12:49:01.081564000 +0100 ++++ v4l2_new.py 2019-01-23 12:50:32.369730171 +0100 +@@ -194,7 +194,7 @@ + V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, + V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + V4L2_BUF_TYPE_PRIVATE, +-) = range(1, 9) + [0x80] ++) = list(range(1, 9)) + [0x80] + + + v4l2_ctrl_type = enum +@@ -245,7 +245,7 @@ + V4L2_PRIORITY_INTERACTIVE, + V4L2_PRIORITY_RECORD, + V4L2_PRIORITY_DEFAULT, +-) = range(0, 4) + [2] ++) = list(range(0, 4)) + [2] + + + class v4l2_rect(ctypes.Structure): diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh index 85c1933f096..53ab15a8748 100755 --- a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh @@ -28,6 +28,8 @@ PKGS_TO_INSTALL=" cups \ printer-driver-all \ cups-ipp-utils \ + libcups2-dev \ + pcscd \ localepurge \ vim \ mc \ @@ -37,6 +39,7 @@ PKGS_TO_INSTALL=" hostapd \ git \ rsync \ + swig \ console-data \ lightdm \ xserver-xorg-video-fbdev \ @@ -49,7 +52,9 @@ PKGS_TO_INSTALL=" rpi-update \ adduser \ postgresql \ + python-cups \ python3 \ + python3-pyscard \ python3-urllib3 \ python3-dateutil \ python3-decorator \ @@ -104,9 +109,14 @@ rm -rf /usr/share/doc # this may be fixed with libusb>2:1.0.11-1, but that's the most recent one in raspbian # so we install the latest pyusb that works with this libusb. # Even in stretch, we had an error with langid (but worked otherwise) -pip3 install pyusb==1.0.0b1 -pip3 install evdev -pip3 install gatt +PIP_TO_INSTALL=" + pyusb==1.0.0b1 \ + evdev \ + gatt \ + v4l2 \ + pycups" + +pip3 install ${PIP_TO_INSTALL} groupadd usbusers @@ -148,6 +158,7 @@ if [ $SYSTEMD -eq 1 ]; then systemctl set-default graphical.target ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service rm /etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service + rm /etc/systemd/system/hostapd.service else update-rc.d lightdm enable 2 fi diff --git a/addons/point_of_sale/tools/posbox/posbox_create_image.sh b/addons/point_of_sale/tools/posbox/posbox_create_image.sh index 0c517da73d7..6401444200c 100755 --- a/addons/point_of_sale/tools/posbox/posbox_create_image.sh +++ b/addons/point_of_sale/tools/posbox/posbox_create_image.sh @@ -120,6 +120,14 @@ qemu-system-arm "${QEMU_OPTS[@]}" mount "${LOOP_MAPPER_PATH}" "${MOUNT_POINT}" cp -av "${OVERWRITE_FILES_AFTER_INIT_DIR}"/* "${MOUNT_POINT}" +find "${MOUNT_POINT}"/usr -type f -name "*.iotpatch"|while read iotpatch; do + DIR=$(dirname "${iotpatch}") + BASE=$(basename "${iotpatch%.iotpatch}") + find "${DIR}" -type f -name "${BASE}" ! -name "*.iotpatch"|while read file; do + patch -f "${file}" < "${iotpatch}" + done +done + # cleanup sleep 2 umount "${MOUNT_POINT}" diff --git a/addons/point_of_sale/tools/posbox/posbox_download_images.sh b/addons/point_of_sale/tools/posbox/posbox_download_images.sh index b13505ce16b..939e9879c2c 100755 --- a/addons/point_of_sale/tools/posbox/posbox_download_images.sh +++ b/addons/point_of_sale/tools/posbox/posbox_download_images.sh @@ -1,8 +1,7 @@ #!/bin/sh -wget 'http://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2018-06-29/2018-06-27-raspbian-stretch-lite.zip' -O raspbian.img.zip +wget 'http://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2018-11-15/2018-11-13-raspbian-stretch-lite.zip' -O raspbian.img.zip unzip raspbian.img.zip -wget 'https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu-4.9.59-stretch' -O kernel-qemu +wget 'https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu-4.14.79-stretch' -O kernel-qemu wget 'https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/versatile-pb.dtb' - From db9385b708953646b6e066fea9da1dccd778ecbb Mon Sep 17 00:00:00 2001 From: lejeune quentin Date: Fri, 15 Feb 2019 09:47:13 +0100 Subject: [PATCH 2/5] [FIX] IoT : Waiting for wifi connection This loop try to get "screen_url" from "URL_SERVER" So IoT Box need to be connected to the same network as "URL_SERVER". ( Inetrnet or locally ) If can not reach "URL_SERVER" he return a default screen_url When IoT Box is wired connected there are no problem. But with Wifi the wireless service take some time to by enabled. With this fix the loop wait 1 second on every loop. So if can not reach "URL_SERVER" in 30 seconds he return a default screen_url --- .../tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart index 96ea352c761..d7b5349a74f 100755 --- a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart @@ -15,6 +15,7 @@ if [ -e /home/pi/odoo-remote-server.conf ] var=0 while [ ${var} -lt 30 ]; do var=$((var+1)) + sleep 1 status_code=$(wget ${URL_SERVER} --server-response 2>&1|grep 'HTTP/'|awk '{print $2}') if [ ${status_code} -eq 200 ] then From 61c824764c9e8f4e6441f04e1fab506aaf369d7c Mon Sep 17 00:00:00 2001 From: lejeune quentin Date: Fri, 15 Feb 2019 10:32:33 +0100 Subject: [PATCH 3/5] [FIX] IoT : Variable name correction This commit replace "data" by "iot_box" which is more representative of the values it contains --- addons/hw_drivers/controllers/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py index 233b7422ea5..0fbc9962e56 100755 --- a/addons/hw_drivers/controllers/driver.py +++ b/addons/hw_drivers/controllers/driver.py @@ -278,7 +278,7 @@ class Manager(Thread): } data = { 'params': { - 'data' : iot_box, + 'iot_box' : iot_box, 'devices' : devices_list, } } From ae35e160931c420076a0fbe5ef31f3f57761e1ad Mon Sep 17 00:00:00 2001 From: lejeune quentin Date: Fri, 15 Feb 2019 11:52:55 +0100 Subject: [PATCH 4/5] [IMP] IoT : Automatic registration of the IoT Box in HTTPS without certificate When we are on HTTPS and we want to connect a box with the scan we need to accept manually the certificate of the box. With this commit we don't need to accept manually the certificate. We don't have problem of mixed content if we use the onload method of Image object So we load a image and put on parameter the token of the odoo DB to make a connection. --- addons/hw_drivers/controllers/driver.py | 41 ++++++++++++------------ addons/hw_drivers/static/img/False.jpg | Bin 0 -> 546 bytes addons/hw_drivers/static/img/True.jpg | Bin 0 -> 542 bytes 3 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 addons/hw_drivers/static/img/False.jpg create mode 100644 addons/hw_drivers/static/img/True.jpg diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py index 0fbc9962e56..64d45a1fcfc 100755 --- a/addons/hw_drivers/controllers/driver.py +++ b/addons/hw_drivers/controllers/driver.py @@ -88,27 +88,28 @@ class StatusController(http.Controller): req['result']['session_id'] = req['session_id'] return req['result'] - @http.route('/hw_drivers/box/connect', type='json', auth='none', cors='*', csrf=False) + @http.route('/hw_drivers/box/connect', type='http', auth='none', cors='*', csrf=False, save_session=False) def connect_box(self, token): - server = "" # read from file - try: - f = open('/home/pi/odoo-remote-server.conf', 'r') - for line in f: - server += line - f.close() - server = server.split('\n')[0] - except: - server = '' - if server: - return 'This IoTBox has already been connected' - else: - iotname = '' - token = token.split('|')[1] - url = token.split('|')[0] - reboot = 'noreboot' - subprocess.call([home() + '/odoo/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh', url, iotname, token, reboot]) - send_iot_box_device(False) - return 'IoTBox connected' + """ + This route is called when we want that a IoT Box will be connected to a Odoo DB + token is a base 64 encoded string and have 2 argument separate by | + 1 - url of odoo DB + 2 - token. This token will be compared to the token of Odoo. He have 1 hour lifetime + """ + server = get_odoo_server_url() + image = get_resource_path('hw_drivers', 'static/img', 'False.jpg') + if server == '': + token = b64decode(token).decode('utf-8') + url, token = token.split('|') + try: + subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, '', token, 'noreboot']) + m.send_alldevices() + image = get_resource_path('hw_drivers', 'static/img', 'True.jpg') + except subprocess.CalledProcessError as e: + _logger.error('A error encountered : %s ' % e.output) + if os.path.isfile(image): + with open(image, 'rb') as f: + return f.read() #---------------------------------------------------------- # Drivers diff --git a/addons/hw_drivers/static/img/False.jpg b/addons/hw_drivers/static/img/False.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f8e6489b30a389e475551b03ade16dc9257cfe1 GIT binary patch literal 546 zcmb78u^izoN#@|~P>({p-c^|Kg1Yq_h>i>!(ND?`Gh2UGSyM46ADv=e=9x0 zYXk&I9>SCKl%5c|KfX)zI{exqy~0X@aMA(vFaf#^=ziKy8PseiB}NV4{{|#cMf(8p l1?-GyRhx*N09D7MZEr|E)7{l4_Xk?JL#;Nzo=^r}J^_c1N>Ts- literal 0 HcmV?d00001 diff --git a/addons/hw_drivers/static/img/True.jpg b/addons/hw_drivers/static/img/True.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0488574a699b8dcf2e9cdd48ac8896aa339d3805 GIT binary patch literal 542 zcmb7=sE2fY_bi*omlvb)J zlqt)ecE&kttgY&Suj)`+>qkBeV@k;#9F9kEJcucFpO9ovq54YoV`Z!OZ{-IB4Fe-7 zKm?M3@*@)W$9HL7$6s6I7dS}}UV4D;kIN48Kg|ten$4udqyxg=fFx>Z7a+cXtr5L; d6R{Pb_Gt3i8j_FncgsDU{Ju^bU`Hea&mS2iNcjK& literal 0 HcmV?d00001 From 7c2ba9dc3028fae04165f4d22c97cc807a3d2a07 Mon Sep 17 00:00:00 2001 From: Antoine Prieels Date: Thu, 7 Mar 2019 14:16:26 +0100 Subject: [PATCH 5/5] [IMP] point_of_sale: Do not share printers to the network Add Cups configuration to not share printers to the network by default. When multiple IoTBoxes were on the same network they would share printers with each other, creating multiple duplicates of the same printer. --- .../tools/posbox/overwrite_after_init/etc/cups/cupsd.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/cups/cupsd.conf b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/cups/cupsd.conf index ee6cbbf93d4..cefc3cf06ab 100644 --- a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/cups/cupsd.conf +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/cups/cupsd.conf @@ -20,6 +20,9 @@ Listen /run/cups/cups.sock Browsing On BrowseLocalProtocols dnssd +# Local printers are not shared by default +DefaultShared No + # Default authentication type, when authentication is required... DefaultAuthType Basic