From 721c8ef71d1aaf57fcb7d8e54023646cd6a39ef8 Mon Sep 17 00:00:00 2001 From: CruiseDevice Date: Fri, 28 Sep 2018 17:42:53 +0530 Subject: Create Flask API for sbhs devices --- sbhs/sbhs.py | 275 ---------------------------------------- sbhs_raspi/requirements.txt | 1 + sbhs_raspi/sbhs.py | 164 ++++++++++++++++++++++++ sbhs_raspi/sbhs_raspi_server.py | 230 +++++++++++++++++++++++++++++++++ 4 files changed, 395 insertions(+), 275 deletions(-) delete mode 100644 sbhs/sbhs.py create mode 100644 sbhs_raspi/requirements.txt create mode 100644 sbhs_raspi/sbhs.py create mode 100644 sbhs_raspi/sbhs_raspi_server.py diff --git a/sbhs/sbhs.py b/sbhs/sbhs.py deleted file mode 100644 index 3b41a08..0000000 --- a/sbhs/sbhs.py +++ /dev/null @@ -1,275 +0,0 @@ -import serial -import os -from time import localtime, strftime, sleep -# import credentials -import sbhs_server.credentials as credentials - -# MAP_FILE = credentials.MAP_FILE -#LOG_FILE = '../log/sbhserr.log' -# LOG_FILE = credentials.LOG_FILE - -class SbhsServer(object): - """ This is the Single Board Heater System class """ - - def __init__(self): - self.outgoing_machine_id = 252 - self.incoming_fan = 253 - self.incoming_heat = 254 - self.outgoing_temp = 255 - self.max_heat = 100 - self.out_max_fan = 100 - - def get_usb_devices(self): - usb_devices = [] - for tty in os.listdir('/dev'): - if tty.startswith('ttyUSB'): - try: - usb_devices.append(int(tty[6:])) - except ValueError: - pass - - return usb_devices - - def connect_device(self, device_num): - """ - Open a serial connection via USB to the SBHS using USB Device Number - """ - # check for valid device number - - usb_device_file = '/dev/ttyUSB{}'.format(device_num) - try: - self.boardcon = serial.Serial(port=usb_device_file, - baudrate=9600, bytesize=8, - parity='N', stopbits=1, - timeout=2 - ) - self.sbhs = self.get_machine_id() - # org stopbits = 1 - status = True - except Exception as e: - status = False - print(e) - return status - - def map_sbhs_to_usb(self, usb_devices): - sbhs_map = [] - if usb_devices: - for usb in usb_devices: - print("usb", usb) - status = self.connect_device(usb) - if status: - sbhs = self.sbhs - sbhs_map.append({"usb_id": usb, "sbhs_mac_id": sbhs}) - return sbhs_map - - def connect(self, machine_id): - """ - Open a serial connection via USB to the SBHS using the - machine id - """ - # check for valid machine id number - try: - self.machine_id = int(machine_id) - except: - return False - - # get the usb device file from the machine map file - try: - map_file = open(MAP_FILE, 'r') - usb_device_file = False - - for mapping_str in map_file.readlines(): - mapping = mapping_str.split('=') - self.log('mapping: ' + mapping[1], 'ERROR') #srikant - - # if mapping for the machine id found set the usb device - # file and break out of loop - if mapping[0] == str(self.machine_id): - usb_device_file = mapping[1].strip() - #self.log('usb_device_file: ' + usb_device_file, 'ERROR') #srikant - break - - # reached end of file and check if machine id entry is present - # in the machine map file - map_file.close() - if not usb_device_file: - print("Error: cannot locate the USB device in the map table \ - for machine id {}".format(self.machine_id)) - self.log('cannot locate the USB device in the map table for \ - machine id %d' % self.machine_id, 'ERROR') - return False - except: - # map_file.close() - print("Error: cannot get the USB device path for the machine \ - id {}".format(self.machine_id)) - self.log('cannot get the USB device path for the machine id\ - %d' % self.machine_id, 'ERROR') - return False - - # check if SBHS device is connected - if not os.path.exists(usb_device_file): - print("SBHS device file" +usb_device_file + "does not exists") - self.log('SBHS device file ' + usb_device_file + ' does not\ - exists', 'ERROR') - return False - try: - self.boardcon = serial.Serial(port=usb_device_file, \ - baudrate=9600, bytesize=8, parity='N', \ - stopbits=1, timeout=2) #orignal stopbits = 1 - self.status = 1 - return True - except serial.serialutil.SerialException: - print("Error: cannot connect to machine id \ - {}".format(self.machine_id)) - self.log('cannot connect to machine id \ - %d' % self.machine_id, 'ERROR') - - self.machine_id = -1 - self.device_num = -1 - self.boardcon = False - self.status = 0 - - - def setHeat(self, val): - """ Sets the heat, checks if value is valid i.e. within range. - Input: self object, val - Output: Error message if heat cannot be set. - """ - if val > MAX_HEAT or val < 0: - print("Error: heat value cannot be more than {}".format(MAX_HEAT)) - return False - - try: - self._write(chr(INCOMING_HEAT)) - sleep(0.5) - self._write(chr(val)) - return True - except: - print("Error: cannot set heat for machine \ - id {}".format(self.machine_id)) - self.log('cannot set heat for machine id \ - %d' % self.machine_id, 'ERROR') - return False - - def setFan(self, val): - """ Sets the fan speed, checks if value is valid i.e. within range. - Input: self object, val - Output: Error message if fan cannot be set. - """ - if val > MAX_FAN or val < 0: - print("Error: fan value cannot be more than {}".format(MAX_FAN)) - return False - try: - self._write(chr(INCOMING_FAN)) - sleep(0.5) - self._write(chr(val)) - return True - except: - print("Error: cannot set fan for machine id \ - {}".format(self.machine_id)) - self.log('cannot set fan for machine id %d' % self.machine_id, \ - 'ERROR') - return False - - def getTemp(self): - """ Gets the temperature from the machine. - """ - try: - self.boardcon.flushInput() - self._write(chr(OUTGOING_TEMP)) - temp = ord(self._read(1)) + (0.1 * ord(self._read(1))) - return temp - except: - print("Error: cannot read temperature from machine id \ - {}".format(self.machine_id)) - self.log('cannot read temperature from machine id %d' \ - % self.machine_id, 'ERROR') - return 0.0 - - def get_machine_id(self): - """ Gets machine id from the device """ - try: - self.boardcon.flushInput() - self._write(str(self.outgoing_machine_id).encode()) - sleep(0.5) - machine_id = self._read(1) - except Exception as e: - print("e-->", e) - machine_id = -1 - return int(machine_id) - - def disconnect(self): - """ Reset the board fan and heat values and close the USB connection """ - try: - self.boardcon.close() - self.boardcon = False - self.status = 0 - return True - except: - print('Error: cannot close connection to the machine') - self.log('cannot close connection to the machine', 'ERROR') - return False - - def reset_board(self): - return self.setHeat(0) and self.setFan(100) - - def _read(self, size): - try: - data = self.boardcon.read(size).decode("ascii") - print(data) - return data - except Exception as e: - print(e) - - def _write(self, data): - try: - self.boardcon.write(data) - return True - except Exception as e: - print(e) - - def log(self, msg, level): - try: - errfile = open(LOG_FILE, 'a') # open error log file in append mode - if not errfile: - return - log_msg = '%s %s %s\n' %(level, strftime('%d:%m:%Y %H:%M:%S', \ - localtime()), msg) - - errfile.write(log_msg) - errfile.close() - return - except: - return - - -# if no device filename found then exit -# for device in device_files: -# s = sbhs.Sbhs() -# # getting the number from the device filename -# dev_id = device[6:] -# try: -# dev_id = int(dev_id) -# except: -# print('Invalid device name /dev/%s' % device) -# continue -# # connect to device -# res = s.connect_device(dev_id) -# if not res: -# print ('Cannot connect to /dev/%s' % device) -# s.disconnect() -# continue -# # get the machine id from the device -# machine_id = s.getMachineId() -# if machine_id < 0: -# print('Cannot get machine id from /dev/%s' % device) -# s.disconnect() -# continue -# print ('Found SBHS device /dev/%s with machine id %d' % (device, machine_id)) -# map_str = "%d=/dev/%s\n" % (machine_id, device) -# map_machine_file.write(map_str) - -# print ('Done. Exiting...') -# map_machine_file.close() -# sys.exit(1) - diff --git a/sbhs_raspi/requirements.txt b/sbhs_raspi/requirements.txt new file mode 100644 index 0000000..5c8c61b --- /dev/null +++ b/sbhs_raspi/requirements.txt @@ -0,0 +1 @@ +flask==1.0.2 \ No newline at end of file diff --git a/sbhs_raspi/sbhs.py b/sbhs_raspi/sbhs.py new file mode 100644 index 0000000..515c8b6 --- /dev/null +++ b/sbhs_raspi/sbhs.py @@ -0,0 +1,164 @@ +import serial +import os +from time import localtime, strftime, sleep + +# MAP_FILE = credentials.MAP_FILE +#LOG_FILE = '../log/sbhserr.log' +# LOG_FILE = credentials.LOG_FILE + +class SbhsServer(object): + """ This is the Single Board Heater System class """ + + def __init__(self): + self.outgoing_machine_id = 252 + self.incoming_fan = 253 + self.incoming_heat = 254 + self.outgoing_temp = 255 + self.max_heat = 100 + self.max_fan = 100 + + def get_usb_devices(self): + usb_devices = [] + for tty in os.listdir('/dev'): + if tty.startswith('ttyUSB'): + try: + usb_devices.append(int(tty[6:])) + except ValueError: + pass + return usb_devices + + def connect_device(self, device_num): + """ + Open a serial connection via USB to the SBHS using USB Device Number + """ + # check for valid device number + + usb_device_file = '/dev/ttyUSB{}'.format(device_num) + try: + self.boardcon = serial.Serial(port=usb_device_file, + baudrate=9600, bytesize=8, + parity='N', stopbits=1, + timeout=2 + ) + # org stopbits = 1 + status = True + except Exception as e: + status = False + return status + + def map_sbhs_to_usb(self, usb_devices): + sbhs_map = [] + if usb_devices: + for usb in usb_devices: + print("usb", usb) + status = self.connect_device(usb) + if status: + sbhs = self.get_machine_id() + sbhs_map.append({"usb_id": usb, "sbhs_mac_id": sbhs}) + return sbhs_map + + + def setHeat(self, val): + """ Sets the heat, checks if value is valid i.e. within range. + Input: self object, val + Output: Error message if heat cannot be set. + """ + if val > MAX_HEAT or val < 0: + print("Error: heat value cannot be more than {}".format(MAX_HEAT)) + return False + + try: + self._write(chr(INCOMING_HEAT)) + sleep(0.5) + self._write(chr(val)) + return True + except: + print("Error: cannot set heat for machine \ + id {}".format(self.machine_id)) + self.log('cannot set heat for machine id \ + %d' % self.machine_id, 'ERROR') + return False + + def set_fan(self, val): + """ Sets the fan speed, checks if value is valid i.e. within range. + Input: self object, val + Output: Error message if fan cannot be set. + """ + if val > self.out_fan or val < 0: + return False + try: + self._write(chr(self.incoming_fan)) + sleep(0.5) + self._write(chr(val)) + return True + except: + return True + + def getTemp(self): + """ Gets the temperature from the machine. + """ + try: + self.boardcon.flushInput() + self._write(chr(OUTGOING_TEMP)) + temp = ord(self._read(1)) + (0.1 * ord(self._read(1))) + return temp + except: + print("Error: cannot read temperature from machine id \ + {}".format(self.machine_id)) + self.log('cannot read temperature from machine id %d' \ + % self.machine_id, 'ERROR') + return 0.0 + + def get_machine_id(self): + """ Gets machine id from the device """ + try: + self.boardcon.flushInput() + self._write(chr(self.outgoing_machine_id)) + sleep(0.5) + machine_id = ord(self._read(1)) + except Exception as e: + machine_id = -1 + return int(machine_id) + + def disconnect(self): + """ Reset the board fan and heat values and close the USB connection """ + try: + self.boardcon.close() + self.boardcon = False + self.status = 0 + return True + except: + print('Error: cannot close connection to the machine') + self.log('cannot close connection to the machine', 'ERROR') + return False + + def reset_board(self): + return self.setHeat(0) and self.setFan(100) + + def _read(self, size): + try: + data = self.boardcon.read(size) + return data + except Exception as e: + raise + + def _write(self, data): + try: + self.boardcon.write(data) + return True + except Exception as e: + raise + + def log(self, msg, level): + try: + errfile = open(LOG_FILE, 'a') # open error log file in append mode + if not errfile: + return + log_msg = '%s %s %s\n' %(level, strftime('%d:%m:%Y %H:%M:%S', \ + localtime()), msg) + + errfile.write(log_msg) + errfile.close() + return + except: + return diff --git a/sbhs_raspi/sbhs_raspi_server.py b/sbhs_raspi/sbhs_raspi_server.py new file mode 100644 index 0000000..224c75e --- /dev/null +++ b/sbhs_raspi/sbhs_raspi_server.py @@ -0,0 +1,230 @@ +from flask import (Flask, flash, redirect, render_template, request, url_for, + Response, jsonify) +from sbhs import SbhsServer + +app = Flask(__name__) + + +@app.route('/experiment/check_connection') +def check_connection(): + return Response("TESTOK") + +@app.route('/experiment/client_version') +def client_version(): + return Response("3") + +@app.route('/experiment/get_machine_ids') +def get_machine_ids(): + sbhs_server = SbhsServer() + all_mac_ids = sbhs_server.map_sbhs_to_usb(sbhs_server.get_usb_devices()) + return jsonify(all_mac_ids) + +@app.route('/experiment/set_fan//') +def set_fan(dev_num, fan_speed): + sbhs_server = SbhsServer() + connect = sbhs_server.connect_device(dev_num) + status = False + if connect: + status = sbhs_server.set_fan(fan_speed) + return Response(status) + + + +# @csrf_exempt +# def initiation(req): +# username = req.POST.get("username") +# password = req.POST.get("password") +# user = authenticate(username=username, password=password) +# if user is not None: +# if user.is_active: +# user1 = Account.objects.select_related().filter(id=user.id) +# user1 = user1[0] +# user_board = user1.board + +# #allows admin to access the temporary offline devices but prohibits the users to do so +# if user_board.online and (not user_board.temp_offline \ +# or user1.is_admin): +# slots = Slot.slots_now() +# slot_ids = [s.id for s in slots] +# now = datetime.datetime.now() +# bookings = user.booking_set.filter(booking_date__year=now.year, +# booking_date__month=now.month, +# booking_date__day=now.day, +# slot_id__in=slot_ids)\ +# .select_related("slot") +# try: +# cur_booking = bookings[0] +# active_slot = cur_booking.slot +# except: +# cur_booking = None +# active_slot = None + +# if active_slot is not None: +# endtime = cur_booking.end_time() +# if now < endtime: +# filename = datetime.datetime.strftime(now, \ +# "%Y%b%d_%H_%M_%S.txt") +# logdir = os.path.join(settings.EXPERIMENT_LOGS_DIR, \ +# user.username) +# if not os.path.exists(logdir): +# os.makedirs(logdir) + +# f = open(os.path.join(logdir, filename), "a") +# f.close() + +# LOGIN(req, user) + +# e = Experiment() +# e.booking=cur_booking +# e.log=user.username + "/" + filename +# e.save() + +# key = str(user_board.mid) + +# settings.boards[key]["experiment_id"] = e.id + +# reset(req) + +# STATUS = 1 +# MESSAGE = filename +# else: +# reset(req) +# STATUS = 0 +# MESSAGE = "Slot has ended. Please book the next slot \ +# to continue the experiment." +# else: +# STATUS = 0 +# MESSAGE = "You haven't booked this slot." +# else: +# STATUS = 0 +# MESSAGE = "Your SBHS is offline. Please contact the Vlabs \ +# team." +# else: +# STATUS = 0 +# MESSAGE = "Your account is not activated yet. Please check your \ +# email for activation link." +# else: +# STATUS = 0 +# MESSAGE = "Invalid username or password" + +# return HttpResponse(json.dumps({"STATUS": STATUS, "MESSAGE": MESSAGE})) + +# @login_required(redirect_field_name=None) +# @csrf_exempt +# def experiment(req): +# try: +# server_start_ts = int(time.time() * 1000) +# from pi_server.settings import boards +# user = req.user +# key = str(user.board.mid) +# experiment = Experiment.objects.select_related()\ +# .filter(id=boards[key]["experiment_id"]) + +# if len(experiment) == 1 and user.id == experiment[0].booking.account.id and experiment[0].booking.trashed_at == None: +# experiment = experiment[0] +# now = datetime.datetime.now() +# endtime = experiment.booking.end_time() +# if endtime > now: +# timeleft = int((endtime-now).seconds) +# heat = max(min(int(req.POST.get("heat")), 100), 0) +# fan = max(min(int(req.POST.get("fan")), 100), 0) + +# boards[key]["board"].setHeat(heat) +# boards[key]["board"].setFan(fan) +# temperature = boards[key]["board"].getTemp() +# log_data(boards[key]["board"], key, experiment.id, heat=heat, fan=fan, temp=temperature) + +# server_end_ts = int(time.time() * 1000) + +# STATUS = 1 +# MESSAGE = "%s %d %d %2.2f" % (req.POST.get("iteration"), +# heat, +# fan, +# temperature) +# MESSAGE = "%s %s %d %d,%s,%d" % (MESSAGE, +# req.POST.get("timestamp"), +# server_start_ts, +# server_end_ts, +# req.POST.get("variables"), timeleft) + +# f = open(os.path.join(settings.EXPERIMENT_LOGS_DIR, experiment.log), "a") +# f.write(" ".join(MESSAGE.split(",")[:2]) + "\n") +# f.close() +# else: +# # boards[key]["board"].setHeat(0) +# # boards[key]["board"].setFan(100) +# # log_data(boards[key]["board"], key) +# reset(req) + +# STATUS = 0 +# MESSAGE = "Slot has ended. Please book the next slot to continue the experiment." + +# reset(req) +# boards[key]["experiment_id"] = None +# else: +# STATUS = 0 +# MESSAGE = "You haven't booked this slot." + +# return HttpResponse(json.dumps({"STATUS": STATUS, "MESSAGE": MESSAGE})) +# except Exception: +# return HttpResponse(json.dumps({"STATUS": 0, "MESSAGE": "Invalid input. Perhaps the slot has ended. Please book the next slot to continue the experiment."})) + +# @csrf_exempt +# def reset(req): +# try: +# from pi_server.settings import boards +# user = req.user +# if user.is_authenticated(): +# key = str(user.board.mid) +# experiment = Experiment.objects.select_related().filter(id=boards[key]["experiment_id"]) + +# if len(experiment) == 1 and user == experiment[0].booking.account: +# experiment = experiment[0] +# now = datetime.datetime.now() +# endtime = experiment.booking.end_time() + +# boards[key]["board"].setHeat(0) +# boards[key]["board"].setFan(100) + +# log_data(boards[key]["board"], key, experiment.id, 0, 100) +# if endtime < now: +# boards[key]["experiment_id"] = None +# except: +# pass + +# return HttpResponse("") + +# def log_data(sbhs, mid, experiment_id, heat=None, fan=None, temp=None): +# if heat is None: +# heat = sbhs.getHeat() +# if fan is None: +# fan = sbhs.getFan() +# if temp is None: +# temp = sbhs.getTemp() + +# data = "%d %s %s %s\n" % (int(time.time()), str(heat), str(fan), str(temp)) +# global_logfile = settings.SBHS_GLOBAL_LOG_DIR + "/" + str(mid) + ".log" +# with open(global_logfile, "a") as global_loghandler: +# global_loghandler.write(data) + +# def validate_log_file(req): +# import hashlib +# data = req.POST.get("data") +# data = data.strip().split("\n") +# clean_data = "" +# for line in data: +# columns = line.split(" ") +# if len(columns) >= 6: +# clean_data += (" ".join(columns[0:6]) + "\n") + +# checksum = hashlib.sha1(clean_data).hexdigest() + +# try: +# e = Experiment.objects.get(checksum=checksum) +# return HttpResponse("TRUE") +# except: +# return HttpResponse("FALSE") + + +if __name__ == "__main__": + app.run(host="127.0.0.1", port=9876) \ No newline at end of file -- cgit