Example #1
0
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())
Example #2
0
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())
Example #3
0
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)
Example #4
0
def nodes_trigger_callback():
    """
        Trigger Callback
        Called when node gpio triggered
        ---
        tags:
          - sensors
        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)
Example #5
0
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)
Example #6
0
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
Example #7
0
 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()
Example #8
0
 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()
Example #9
0
 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
Example #10
0
 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
Example #11
0
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
Example #12
0
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
Example #13
0
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
Example #14
0
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
Example #15
0
    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
            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)
Example #16
0
    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)
Example #17
0
 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)
Example #18
0
    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
            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)
Example #19
0
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
Example #20
0
 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)
Example #21
0
def book_adder():
    """
    Assumes that the data has been stripped clean of leading and trailing spaces.

    Possible responses:
        200 Accepted - Book was added to the database successfully.
        302 Error - API endpoint called while not logged in.
        400 Error - The request did not validate. Client _must not_ retry.
        409 IntegrityError - Database error for possible duplicate records.
          Client _must not_ retry.
        500 - Standard server error. Client may retry after some wait period.
    """
    form = AddBooksForm(request.form)
    app.logger.info(str(form))
    app.logger.debug(form.debug_validate())

    if has_equivalent_isbn(form.isbn.data):
        err_str = "A book with that ISBN (in another form) is already in the database."
        app.logger.error(err_str)
        return err_str, 409

    if form.validate_on_submit():
        try:
            from flask_login import current_user
            # Genre first
            genre = get_or_create(Genre,
                                  will_commit=False,
                                  name=form.genre.data,
                                  creator=current_user)

            # Publishing information
            publisher = get_or_create(BookCompany,
                                      will_commit=False,
                                      name=form.publisher.data,
                                      creator=current_user)
            has_printer = form.printer.data.strip()
            if has_printer:
                printer = get_or_create(BookCompany,
                                        will_commit=False,
                                        name=form.printer.data,
                                        creator=current_user)

            # Book
            book = Book(isbn=form.isbn.data,
                        title=form.title.data,
                        genre=genre,
                        creator=current_user,
                        publisher=publisher,
                        publish_year=int(form.year.data))
            db.session.add(book)
            db.session.flush()

            # Create printer entry
            if has_printer:
                printer_record = Printer(company=printer,
                                         book=book,
                                         creator=current_user)
                db.session.add(printer_record)

            __insert_contributions(book, form, db.session)

            db.session.commit()

            return "Accepted", 200
        except IntegrityError, ierr:
            db.session.rollback()
            app.logger.error(traceback.format_exc())
            err_str = '"%s" has been catalogued before. Ignoring.' % (
                form.title.data)
            return err_str, 409
        except ConstraintError, cerr:
            db.session.rollback()
            app.logger.error(traceback.format_exc())
            return cerr.message, 400
Example #22
0
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)
Example #23
0
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)
Example #24
0
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
Example #25
0
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)
Example #26
0
    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
Example #27
0
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)
Example #28
0
    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)
Example #29
0
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
Example #30
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