def print_status(id): """ Print Status Get printer status --- tags: - printer parameters: - in: path description: ID of the printer required: true type: integer name: id responses: 200: description: returns printer information schema: $ref: "#/definitions/Web_Printer" """ internal = request.args.get("internal", "false") if internal.lower() == "true": printer = Printer.get_by_id(id) if printer == None: abort(404) return json.jsonify(printer.to_dict()) printer = Printer.get_by_webid(id) if printer == None: abort(404) return json.jsonify(printer.to_web())
def nodes_trigger_callback(): """ Trigger Callback Called when node gpio triggered --- tags: - nodemcu responses: 200: description: Returns node data """ payload = request.get_json() id = int(payload.get("id")) data = payload.get("data") node = Node.get_by_id(id) if node.printer_id: printer = Printer.get_by_id(node.printer_id) if printer.status in ["completed", "cancelled"]: t = Command(printer.id, hub.log, "clear", hub.Webapi) else: t = Command(printer.id, hub.log, "cancel", hub.Webapi) t.start() for sensor in node.sensors: if sensor.sensor_type == "LED": url = sensor.led_on() t = threading.Thread(target=requests.get, args=(url,)) t.start() #r = requests.get(url, timeout=10) d = {'id': id, 'data': data} return json.jsonify(d)
def jobs_current(id): """ Jobs Current Get current job information --- tags: - printer parameters: - in: path description: ID of the printer required: true type: integer name: id responses: 200: description: Returns current status of job schema: $ref: "#/definitions/Web_Job" """ printer = Printer.get_by_id(id) if printer: job = printer.current_job() if job: return json.jsonify(job.to_web()) else: return json.jsonify({}) abort(404)
def print_action(id): """ Print Action Add print action --- tags: - printer parameters: - in: path required: true name: id description: ID of printer type: integer - in: body name: Command description: Command to be excecuted required: true schema: required: - id - type properties: id: type: integer description: id of the command name: type: string description: name of command to send [start, pause, cancel, clear] responses: 201: description: Returns "(action) successfully sent to the printer." """ printer = Printer.get_by_webid(id) if printer == None: abort(404) id = printer.id ip = printer.ip port = printer.port key = printer.key jobs = printer.jobs url = ip + ":" + str(port) log = hub.log data = request.get_json() command_id = data.get("id") action = data.get("name") if action == "start": t = Command(id, log, "start", hub.Webapi, command_id=command_id) elif action == "pause": t = Command(id, log, "pause", hub.Webapi, command_id=command_id) elif action == "cancel": t = Command(id, log, "cancel", hub.Webapi, command_id=command_id) elif action in ["clear", "next"]: t = Command(id, log, "clear", hub.Webapi, command_id=command_id) t.start() return json.jsonify( {"message": action + " successfully sent to the printer."}), 201
def __init__(self, printer_id, webapi, log): """TODO: to be defined1. """ threading.Thread.__init__(self) self.printer_id = printer_id printer = Printer.get_by_id(printer_id) status = printer.status self.stopped = False self.webapi = webapi self.log = log self.lock = threading.Lock()
def __init__(self, printer_id, webapi, log): """TODO: to be defined1. """ threading.Thread.__init__(self) self.printer_id = printer_id job = Printer.get_by_id(printer_id, fresh=True).current_job() self.stopped = False self.webapi = webapi if job: self.status = job.status else: self.status = None self.log = log
def delete_job(job_id): """ Delete Job Action Stops and Deletes Job --- tags: - printer parameters: - in: path type: integer name: id description: ID of the Job required: true responses: 200: description: TODO """ job = Job.get_by_webid(job_id) if job: printer_id = job.printer_id if printer_id != None: printer = Printer.get_by_id(printer_id) if printer != None: if job.position == 0: if printer.state("cancelled"): printer.cancel_job() payload = printer.to_web() hub.Webapi.patch_printer(payload) else: printer.remove_job(job.id) if job.state("cancelled"): payload = job.to_web() hub.Webapi.patch_job(payload) return json.jsonify( {"message": "Job " + str(job_id) + " has been deleted"}), 200
def run(self): id = self.id log = self.log command = self.command webapi = self.webapi loc = octopi.local printer = Printer.get_by_id(id, fresh=True) ip = printer.ip port = printer.port key = printer.key status = printer.status url = ip + ":" + str(port) if command == "start": if status == "paused": i = 0 r = octopi.toggle_pause(url, key) while r == None and i < 10: log.log("ERROR: Could not pause printer " + str(id)) sleep(1) r = octopi.toggle_pause(url, key) i += 1 if r and r.status_code == 204: self.success = True elif r: log.log("ERROR: Could not start printer " + str(id) + ". Status code was " + str(r.status_code)) elif status == "ready": cjob = printer.current_job() t = JobUploader(id, cjob.id, log, webapi) t.start() t.join() printer = Printer.get_by_id(id, fresh=True) cjob = printer.current_job() i = 0 r = octopi.select_and_print(url, key, cjob.remote_name) while r == None and i < 10: log.log("ERROR: Could not start printer " + str(id)) sleep(1) r = octopi.select_and_print(url, key, cjob.remote_name) i += 1 if r and r.status_code == 204: self.success = True elif r: log.log("ERROR: Could not start printer " + str(id) + ". Status code was " + str(r.status_code)) else: log.log("ERROR: Printer " + str(id) + " was told to " + "start but wasn't paused or ready") elif command == "pause": if status == "printing": i = 0 r = octopi.toggle_pause(url, key) while r == None and i < 10: log.log("ERROR: Could not pause printer " + str(id)) sleep(1) r = octopi.toggle_pause(url, key) i += 1 if r and r.status_code == 204: self.success = True elif r: log.log("ERROR: Could not pause printer " + str(id) + ". Status code was " + str(r.status_code)) else: log.log("ERROR: Printer " + str(id) + " was told to " + " pause but was not printing") elif command == "cancel": if status in ["printing", "paused"]: i = 0 r = octopi.cancel(url, key) while r == None and i < 10: log.log("ERROR: Could not cancel printer " + str(id)) sleep(1) r = octopi.cancel(url, key) i += 1 if r and r.status_code == 204: self.success = True printer = Printer.get_by_id(id, fresh=True) printer.state("cancelled") elif r: log.log("ERROR: Could not cancel printer " + str(id) + ". Status code was " + str(r.status_code)) else: log.log("ERROR: Printer " + str(id) + " was told to " + " cancel but isn't printing or paused") elif command == "clear": if status == "cancelled": if printer.cancel_job(): self.success = True payload = printer.to_web() i = 0 while not webapi.patch_printer(payload) and i < 10: i += 1 if printer.current_job() != None: c = Command(printer.id, log, "start", webapi) c.start() elif status == "completed": if printer.complete_job(): self.success = True self.success = True payload = printer.to_web() i = 0 while not webapi.patch_printer(payload) and i < 10: i += 1 if printer.current_job() != None: c = Command(printer.id, log, "start", webapi) c.start() else: log.log("ERROR: Printer " + str(id) + " received command bed is clear" + " but current print isn't finished.") if self.command_id != None and self.webapi != None: d = {"id": self.command_id, "type": command} if self.success == True: d['status'] = 'executed' else: d['status'] = 'errored' i = 0 while webapi.callback_command(d) == False and i < 10: i += 1 return 0
def run(self): """Function that will upload a new file, slice it if needed, and delete stl files from the octopi. Should be used whenever a new job is uploaded to the hub :returns: boolean of success """ id = self.id log = self.log job_id = self.job_id webapi = self.webapi loc = octopi.local printer = Printer.get_by_id(id, fresh=True) ip = printer.ip port = printer.port key = printer.key job = Job.get_by_id(job_id) log.log("Starting job upload to " + str(id) + " for job " + str(job.id)) fpath = job.file.path job.state("processing") url = ip + ":" + str(port) r = octopi.upload_file(url, key, fpath, loc) if r == None: log.log("ERROR: Did not have a response from " + str(id) + ". File upload canceled for " + fpath + ".") self.success = False return False if r.status_code != 201: log.log("ERROR: Could not upload file " + fpath + ". Return code from printer " + str(r.status_code)) return False data = r.json() fname = data['files']['local']['name'] ext = get_extension(fname) if ext in ['stl']: job.state("slicing") webapi.patch_job(job.to_web()) r = octopi.slice(url, key, fname, loc) if r == None: log.log("ERROR: Did not have a response from " + str(id) + ". Job upload canceled for job " + str(job_id) + ".") self.success = False return False if r.status_code != 202: log.log("ERROR: Job upload failed for " + str(job_id) + ". Return code from printer " + str(r.status_code)) self.success = False return False j = r.json() rname = j.get('name') r = octopi.get_one_file_info(url, key, rname, loc) while r == None or r.status_code != 200: #This is really f*****g hacky log.log("Could not retrieve file info for " + str(job.id)) sleep(10) r = octopi.get_one_file_info(url, key, rname, loc) job.set_remote_name(rname) r = octopi.delete_file(url, key, fname, loc) while r == None: sleep(10) r = octopi.delete_file(url, key, fname, loc) elif ext in ['gcode', 'gco']: r = octopi.get_one_file_info(url, key, fname, loc) while r == None or r.status_code != 200: #This is really f*****g hacky log.log("Could not retrieve file info for " + str(job.id)) sleep(10) r = octopi.get_one_file_info(url, key, fname, loc) job.set_remote_name(fname) else: self.success = False return False log.log("Completed job upload to " + str(id) + " for job " + str(job.id)) self.success = True return True
def add_printer(): """ Add Printer Adds or updates printer --- tags: - printer parameters: - in: body name: Printer description: Printer object to be added/activated required: true schema: id: Post_Printer required: - id - ip - key properties: ip: type: string description: ip address of connecting printer key: type: string description: api key for octopi id: type: integer description: uid of the printer activating port: type: integer description: port number to communicate on box: type: integer description: UID of black box that pairs with the printer responses: 201: description: Returns 201 created """ log = hub.log listener = hub.printer_listeners id = int(request.form.get("id")) ip = str(request.form.get("ip")) port = int(request.form.get("port", 80)) key = str(request.form.get("key")) box = int(request.form.get("box")) printer = Printer.get_by_id(id, box) listener = hub.printer_listeners if printer: printer.update(box=box, ip=ip, port=port, key=key) if not listener.is_alive(id): t = PrinterCollector(id, hub.Webapi, hub.log) t.start() listener.add_thread(id, t) log.log("Printer " + str(id) + " is now online.") return json.jsonify( {'message': 'Printer ' + str(id) + ' is now online.'}), 201 if listener.is_alive(id): log.log("Printer " + str(id) + " is already online but tried" + " to activate again. Updated it's data") return json.jsonify( {'message': 'Printer ' + str(id) + ' was already online.'}), 201 else: #Add printer to database printer = Printer(id, box, key=key, ip=ip, port=port) t = PrinterCollector(id, hub.Webapi, hub.log) t.start() listener.add_thread(id, t) return json.jsonify({ 'message': 'Printer ' + str(id) + ' has been added and is online.' }), 201
def jobs_post(id): """ Add a Job Add job to printer --- tags: - printer parameters: - in: path description: ID of the printer required: true type: integer name: id - in: body description: Job to add to the printer required: true name: Job schema: $ref: "#/definitions/Web_Job" responses: 201: description: returns "(job) has been uploaded successfully" 400: description: no file was provided 404: description: printer isn't found """ printer = Printer.get_by_webid(id) if printer == None: abort(404) id = printer.id f = request.files.get('file', None) if f: webid = request.form.get('id') job = Job.get_by_webid(webid) if not job: job = Job(int(webid)) ext = f.filename.rsplit(".", 1)[1] name = str(job.id) + "." + ext fpath = os.path.join(app.config['UPLOAD_FOLDER'], name) f.save(fpath) file = File(f.filename, fpath) job.set_file(file) elif job.file == None: ext = f.filename.rsplit(".", 1)[1] name = str(job.id) + "." + ext fpath = os.path.join(app.config['UPLOAD_FOLDER'], name) f.save(fpath) file = File(f.filename, fpath) job.set_file(file) printer = Printer.get_by_id(id) printer.add_job(job) t = threading.Thread(target=hub.Webapi.patch_job, args=(job.to_web(), )) t.start() # if printer.current_job().id == job.id: # t = Command(printer.id, hub.log, "start", # hub.Webapi) # t.start() else: abort(400) return json.jsonify( {"message": "Job " + str(webid) + " has been uploaded successfully"}), 201
def jobs_list(id): """ Jobs List Get list of queued jobs --- tags: - printer parameters: - in: path description: ID of the printer required: true type: integer name: id definitions: - schema: id: Web_Job required: - id properties: id: type: integer description: ID of the printer data: schema: id: Web_Job_Data properties: estimated_print_time: type: integer description: size of the job in bytes status: type: string description: status of the job file: schema: id: Web_Job_File properties: name: type: string description: name of the file origin: type: string description: origin of the file size: type: integer description: size of the file in bytes date: type: string description: date the file was created responses: 200: description: returns json of queued jobs schema: properties: jobs: type: array items: $ref: "#/definitions/Web_Job" """ printer = Printer.get_by_webid(id) if printer: jobs = {"jobs": [job.to_web() for job in printer.jobs]} return json.jsonify(jobs) abort(404)
def run(self): id = self.printer_id webapi = self.webapi log = self.log log.log("JobCollector starting for printer " + str(id)) failures = 0 #url = "http://" + ip + ":" + port prev_data = {} recent_json = None while (True): if self.stopped: log.log("JobCollector stop signal received for " + str(id) + ", exiting.") return 0 printer = Printer.get_by_id(id, fresh=True) ip = printer.ip port = printer.port key = printer.key jobs = printer.jobs status = printer.status cjob = printer.current_job() url = ip + ":" + str(port) #If no current job, simply stop tracking. PrinterCollector # will spawn a new job thread when needed if cjob == None: log.log("No current job exists for " + str(id) + ". JobCollector exiting.") return 0 if cjob.status == "completed": return 0 if cjob.status == "cancelled": return 0 if cjob.status == "queued": t = Command(id, log, "start", webapi) t.start() if cjob.status == "errored" and status == "ready": printer.remove_job(cjob.id) #If printer status is set to completed, cancelled, #or errored, exit. a new job thread will be spawned #by printer collector when needed if status == "offline": cjob.state("errored") data = cjob.to_web() i = 0 # Try to update to web api 10 times while not webapi.patch_job(data) and i < 10: i += 1 sleep(5) return 0 if status == "completed" and prev_data\ and prev_data.get("data")\ .get("progress").get("completion") == 100: # this ensures it will have updated to the web api cjob.state("completed") data = cjob.to_web() i = 0 # Try to update to web api 10 times while not webapi.patch_job(data) and i < 10: i += 1 sleep(5) return 0 if status == "cancelled": cjob.state("cancelled") data = cjob.to_web() i = 0 # Try to update to web api 10 times while not webapi.patch_job(data) and i < 10: i += 1 sleep(5) return 0 if status == "errored": cjob.state("errored") data = cjob.to_web() i = 0 # Try to update to web api 10 times while not webapi.patch_job(data) and i < 10: i += 1 sleep(5) return 0 if status == "paused": cjob.state("paused") if status == "printing": cjob.state("printing") response = octopi.get_job_info(url, key) if response != None: failures = 0 else: failures += 1 log.log("ERROR: Could not collect" + " job data from printer " + str(id) + " on " + url) if failures > 5: cjob.state("errored") webapi.patch_job(cjob.to_web()) return -1 continue if response.status_code != 200: log.log("ERROR: Response from " + str(id) + " returned status code " + str(response.status_code) + " on " + response.url) else: recent_json = response.json() ret = cjob.set_meta(recent_json) data = cjob.to_web() if data != None: # Check to see if data is the same as last collected # if so, do not send it if cmp(prev_data, data): prev_data = data.copy() webapi.patch_job(data) #print(data) else: log.log("ERROR: Did not get proper job data from " + str(id)) sleep(10) sleep(1)
def printers_list(): """ Printers List Returns a json of printers --- tags: - printer definitions: - schema: id: Web_Printer properties: id: type: integer description: id of the printer on web api friendly_id: type: string description: friendly_id of the printer manufacturer: type: string description: manufacturer of the printer model: type: string description: model of the printer num_jobs: type: integer description: number of jobs the printer current has description: type: string description: user description of the printer status: type: string description: status of the printer produces: - application/json responses: 200: description: Returns a list of printers schema: properties: printers: type: array items: $ref: "#/definitions/Web_Printer" """ log = hub.log listener = hub.printer_listeners internal = request.args.get("internal", "false") online = request.args.get('online_only', 'false') online = request.args.get("online", online) data = {"printers": []} printers = data.get("printers") for printer in Printer.get_printers(): id = printer.id if online.lower() == 'true': with listener.lock: if listener.is_alive(id): if internal.lower() == "true": printers.append(printer.to_dict()) else: printers.append(printer.to_web()) else: if internal.lower() == "true": printers.append(printer.to_dict()) else: printers.append(printer.to_web()) return json.jsonify(data)
l.extend(line.split()) set_args(l) return 0 set_args(sys.argv[1:]) if config != None: load_config(config) hub.log = Log(print_enabled=print_enabled) hub.log.log("Starting up HUB webserver") hub.Webapi = WebAPI(hub.WEB_API_URL, hub.WEB_API_KEY, hub.log) hub.Webapi.sign_in() init_db() updates = {"nodes": []} node_updates = updates.get("nodes") for printer in Printer.get_all(): id = printer.id t = PrinterCollector(id, hub.Webapi, hub.log) t.start() hub.printer_listeners.add_thread(id, t) for node in Node.get_all(): id = node.id if node.printer_id == None: node_updates.append(id) t = NodeCollector(id, hub.Webapi, hub.log) t.start() hub.node_listeners.add_thread(id, t) hub.Webapi.update_nodes(updates) app.run(host=host, debug=debug, port=port,threaded=threaded)
def run(self): id = self.printer_id webapi = self.webapi log = self.log printer = Printer.get_by_id(id, fresh=True) # loop until the printer has a webid, # otherwise we can't update while printer.webid == None: webid = webapi.add_printer(printer.first_web()) if webid: printer.set_webid(webid) else: sleep(10) printer = Printer.get_by_id(id, fresh=True) job_thread = JobCollector(id, webapi, log) job_thread.start() log.log("PrinterCollector starting for printer " + str(id)) failures = 0 #url = "http://" + ip + ":" + port prev_data = {} while (True): printer = Printer.get_by_id(id, fresh=True) ip = printer.ip port = printer.port key = printer.key jobs = printer.jobs status = printer.status cjob = printer.current_job() if self.stopped: webapi.patch_printer(printer.to_web()) log.log("PrinterCollector stop signal received for " + str(id) + ". Telling JobCollector to stop.") job_thread.stop() job_thread.join() log.log("JobCollector stopped." + " Exiting PrinterCollector.") return 0 # If status is set to completed, don't do anyting else if status in ["completed", "cancelled"]: if job_thread.is_alive(): job_thread.join(10) if job_thread.is_alive(): job_thread.stop() data = printer.to_web() if cmp(prev_data, data): prev_data = data.copy() webapi.patch_printer(printer.to_web()) if not job_thread.is_alive() and cjob != None\ and status not in ["errored", "cancelled", "completed"]: log.log("JobCollector thread died for " + str(id) + ". Starting new JobCollector.") job_thread = JobCollector(id, webapi, log) job_thread.start() url = ip + ":" + str(port) response = octopi.get_printer_info(url, key) if response != None: failures = 0 else: failures += 1 if failures > 2: printer = Printer.get_by_id(id, fresh=True) if printer.state("offline"): data = printer.to_web() if cmp(prev_data, data): prev_data = data.copy() webapi.patch_printer(data) log.log("ERROR: Could not collect printer" + " data from printer " + str(id)) job_thread.join() log.log("JobCollector stopped." + " Exiting PrinterCollector.") return -1 sleep(5) continue if response.status_code != 200: log.log("ERROR: Response from " + str(id) + " returned status code " + str(response.status_code) + " on " + response.url) else: #data = response.json() state = response.json() printer = Printer.get_by_id(id, fresh=True) if printer.state_from_octopi(state): data = printer.to_web() if prev_data.get("status") == "printing"\ and data.get("status") == "ready": printer.state("completed") continue # Check to see if data is the same as last collected # if so, do not send it if cmp(prev_data, data): prev_data = data.copy() webapi.patch_printer(data) sleep(1)
def run(self): """TODO: Docstring for run. :returns: TODO """ id = self.node_id webapi = self.webapi log = self.log node = Node.get_by_id(id) log.log("NodeCollector starting for node " + str(id)) sleep(10) failures = 0 while (True): node = Node.get_by_id(id, fresh=True) ip = node.ip sensors = node.sensors if self.stopped == True: log.log("NodeCollector for node " + str(id) + " was requested to stop. Exiting...") return 0 if ip != '0': for sensor in sensors: pin = sensor.pin webid = sensor.webid sensor_type = sensor.sensor_type if pin == None or sensor_type == None: continue if sensor_type in ["TEMP", "DOOR", "HUMI", "TRIG"]: url = sensor.get_url() elif sensor_type in ["LED"]: printer = Printer.get_by_id(node.printer_id) if printer: if printer.status in ["completed", "cancelled"]: url = sensor.led_flash() else: url = sensor.led_on() else: continue elif sensor_type in ["POWER"]: url = sensor.power_on() else: continue try: response = requests.get(url, timeout=10) except requests.ConnectionError: log.log("ERROR: Could not connect to " + url) response = None except requests.exceptions.Timeout: log.log("ERROR: Timeout occured on " + url) response = None if response == None: failures += 1 if failures > 10: log.log("ERROR: Could not collect" + " sensor data from node " + str(id) + ". NodeCollector exiting...") return -1 continue if response.status_code != 200: log.log("ERROR Response from " + str(id) + " returned status code " + str(response.status_code) + " on " + response.url) else: recent_json = response.json() ret = sensor.set_value(recent_json) data = sensor.to_web() if data != None and data.get("id") != None: webapi.add_data(data) sleep(3) sleep(3)