def connect(self, params):
        if len(params) > 3:
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Too many parameters',
                                     description='Should be: %sconnect [port] [baudrate]' % self.plugin.get_settings().get(
                                         ["prefix"]))
        if self.plugin.get_printer().is_operational():
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Printer already connected',
                                     description='Disconnect first')

        port = None
        baudrate = None
        if len(params) >= 2:
            port = params[1]
        if len(params) == 3:
            try:
                baudrate = int(params[2])
            except ValueError:
                return None, error_embed(author=self.plugin.get_printer_name(),
                                         title='Wrong format for baudrate',
                                         description='should be a number')

        self.plugin.get_printer().connect(port=port, baudrate=baudrate, profile=None)

        # Check every second for 30 seconds, to see if it has connected.
        for i in range(30):
            time.sleep(1)
            if self.plugin.get_printer().is_operational():
                return None, success_embed('Connected to printer')

        return None, error_embed(author=self.plugin.get_printer_name(),
                                 title='Failed to connect',
                                 description='try: "%sconnect [port] [baudrate]"' % self.plugin.get_settings().get(
                                     ["prefix"]))
    def off(self, params):
        if len(params) > 2:
            return None, error_embed(
                author=self.plugin.get_printer_name(),
                title='Too many parameters',
                description='Should be: %soutputoff {ID}' %
                self.plugin.get_settings().get(["prefix"]))
        elif len(params) < 2:
            return None, error_embed(
                author=self.plugin.get_printer_name(),
                title='Missing parameters',
                description='Should be: %soutputoff {ID}' %
                self.plugin.get_settings().get(["prefix"]))

        result = self.api_command("off", params[1])
        data = result.json()

        if data['success']:
            return None, success_embed(author=self.plugin.get_printer_name(),
                                       title="Turned ID %i off." %
                                       int(params[1]))
        return None, error_embed(author=self.plugin.get_printer_name(),
                                 title="Failed to turn ID %i off." %
                                 int(params[1]),
                                 description=unicode(result.content))
Beispiel #3
0
    def start_print(self, params):
        if len(params) != 2:
            return None, error_embed(
                author=self.plugin.get_printer_name(),
                title='Wrong number of arguments',
                description='try "%sprint [filename]"' %
                self.plugin.get_settings().get(["prefix"]))
        if not self.plugin.get_printer().is_ready():
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Printer is not ready')

        file = self.find_file(params[1])
        if file is None:
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Failed to find the file')

        is_sdcard = (file['location'] == 'sdcard')
        try:
            file_path = self.plugin.get_file_manager().path_on_disk(
                file['location'], file['path'])
            self.plugin.get_printer().select_file(file_path,
                                                  is_sdcard,
                                                  printAfterSelect=True)
        except InvalidFileType:
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Invalid file type selected')
        except InvalidFileLocation:
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Invalid file location?')
        return None, success_embed(author=self.plugin.get_printer_name(),
                                   title='Successfully started print',
                                   description=file['path'])
Beispiel #4
0
    def gcode(self, params):
        if not self.plugin.get_printer().is_operational():
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title="Printer not connected",
                                     description="Connect to printer first.")

        allowed_gcodes = self.plugin.get_settings().get(["allowed_gcode"])
        allowed_gcodes = re.split('[^0-9a-zA-Z]+', allowed_gcodes.upper())
        script = "".join(params[1:]).upper()
        lines = script.split(';')
        for line in lines:
            first = line.strip().replace(' ', '').replace('\t', '')
            first = re.findall('^[a-zA-Z]+[0-9]+', first)
            if first is None or \
                    len(first) == 0 or \
                    first[0] not in allowed_gcodes:
                return None, error_embed(
                    author=self.plugin.get_printer_name(),
                    title="Invalid GCODE",
                    description=
                    "If you want to use \"%s\", add it to the allowed GCODEs" %
                    line)
        try:
            self.plugin.get_printer().commands(lines)
        except Exception as e:
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title="Failed to execute gcode",
                                     description="Error: %s" % e)

        return None, success_embed(author=self.plugin.get_printer_name(),
                                   title="Sent script")
Beispiel #5
0
 def poweroff(self):
     result = self.api_command("turnPSUOff")
     if result:
         return None, success_embed(author=self.plugin.get_printer_name(),
                                    title="Turned PSU off")
     return None, error_embed(author=self.plugin.get_printer_name(),
                              title="Failed to turn PSU off",
                              description=unicode(result.content))
 def resume(self):
     self.plugin.get_printer().resume_print()
     snapshot = None
     snapshots = self.plugin.get_snapshot()
     if snapshots and len(snapshots) == 1:
         snapshot = snapshots[0]
     return None, success_embed(author=self.plugin.get_printer_name(),
                                title='Print resumed', snapshot=snapshot)
 def poweron(self):
     result = self.api_command("turnPSUOn")
     if result:
         return success_embed(author=self.plugin.get_printer_name(),
                              title="Turned PSU on")
     return error_embed(author=self.plugin.get_printer_name(),
                        title="Failed to turn PSU on",
                        description=result.content)
Beispiel #8
0
    def test_success_embed(self):
        messages = success_embed(author="OctoPrint", title="title", description="description")
        self.assertEqual(1, len(messages))
        embed, snapshot = messages[0]
        self.assertBasicEmbed(embed,
                              author="OctoPrint",
                              title="title",
                              description="description",
                              color=COLOR_SUCCESS)

        if "NET_TEST" in os.environ:
            self.discord.send(messages=(embed, snapshot))
Beispiel #9
0
    def disconnect(self):
        if not self.plugin.get_printer().is_operational():
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Printer is not connected')
        self.plugin.get_printer().disconnect()
        # Sleep a while before checking if disconnected
        time.sleep(10)
        if self.plugin.get_printer().is_operational():
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Failed to disconnect')

        return None, success_embed(author=self.plugin.get_printer_name(),
                                   title='Disconnected from printer')
    def test_success_embed(self):
        embeds = success_embed(author="OctoPrint",
                               title="title",
                               description="description")

        self.assertBasicEmbed(embeds,
                              author="OctoPrint",
                              title="title",
                              description="description",
                              color=COLOR_SUCCESS)

        if "NET_TEST" in os.environ:
            self.assertTrue(self.discord.send(embeds=embeds))
    def download_file(self, filename, url, user):
        if user and not self.check_perms('upload', user):
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title="Permission Denied")
        upload_file_path = self.plugin.get_file_manager().path_on_disk('local', filename)

        r = requests.get(url, stream=True)
        with open(upload_file_path, 'wb') as f:
            for chunk in r.iter_content(chunk_size=1024):
                if chunk:  # filter out keep-alive new chunks
                    f.write(chunk)
        return None, success_embed(author=self.plugin.get_printer_name(),
                                   title='File Received',
                                   description=filename)
Beispiel #12
0
 def system_command(self, command):
     if len(command) != 2:
         return None, error_embed(
             author=self.plugin.get_printer_name(),
             title='Wrong number of args',
             description='/systemcommand {source/command}')
     api_key = self.plugin.get_settings().global_get(['api', 'key'])
     port = self.plugin.get_settings().global_get(['server', 'port'])
     header = {'X-Api-Key': api_key, 'Content-Type': 'application/json'}
     if requests.post('http://127.0.0.1:%s/api/system/commands/%s' %
                      (port, command[1]),
                      headers=header):
         return None, success_embed(author=self.plugin.get_printer_name(),
                                    title='Successfully ran command',
                                    description=command[1])
     else:
         return None, error_embed(author=self.plugin.get_printer_name(),
                                  title='Failed to run command',
                                  description=command[1])
Beispiel #13
0
    def removejob(self, params):
        if len(params) < 4:
            return error_embed(author=self.plugin.get_printer_name(),
                               title='Wrong number of args',
                               description='%sremovejob {YYYY-MM-DD} {HH:MM} {path}' % self.plugin.get_settings().get(["prefix"]))
        try:
            files = list(self.plugin.get_settings().global_get(["plugins", "printscheduler", "scheduled_jobs"]))
            params.pop(0)  # remove the command from params
            file_start_at = "%s %s" % (params.pop(0), params.pop(0))
            file_path = " ".join(params)
            for file in files:
                if file["path"] == file_path and file["start_at"] == file_start_at:
                    files.remove(file)
            self.plugin.get_settings().global_set(["plugins", "printscheduler", "scheduled_jobs"], files)
            self.plugin.get_settings().save(trigger_event=True)

            return success_embed(author=self.plugin.get_printer_name(),
                                 title="%s unscheduled for %s" % (file_path, file_start_at))
        except Exception as e:
            return error_embed(author=self.plugin.get_printer_name(),
                               title='Error',
                               description='%s' % e)
Beispiel #14
0
 def unmute(self):
     self.plugin.unmute()
     return None, success_embed(author=self.plugin.get_printer_name(),
                                title='Notifications Unmuted')
 def mute(self):
     self.plugin.mute()
     return success_embed(author=self.plugin.get_printer_name(),
                          title='Notifications Muted')
 def resume(self):
     self.plugin.get_printer().resume_print()
     snapshot = self.plugin.get_snapshot()
     return success_embed(author=self.plugin.get_printer_name(),
                          title='Print resumed',
                          snapshot=snapshot)
    def unzip(self, params):
        if len(params) != 2:
            return None, error_embed(author=self.plugin.get_printer_name(),
                                     title='Wrong number of arguments',
                                     description='try "%sunzip [filename]"' % self.plugin.get_settings().get(
                                         ["prefix"]))

        file_name = params[1]

        flat_filelist = self.get_flat_file_list()

        unzippable = None

        if file_name.endswith('.zip'):
            for file in flat_filelist:
                if file_name.upper() in file.get('path').upper():
                    unzippable = self.plugin.get_file_manager().path_on_disk(file.get('location'), file_name)
                    break

        elif file_name.endswith('.zip.001'):
            files = []
            truncated = file_name[:-3]
            current = 1
            found = True
            while found:
                found = False
                fn = truncated + str(current).zfill(3)
                for file in flat_filelist:
                    if fn.upper() in file.get('path').upper():
                        files.append(fn)
                        current += 1
                        found = True
                        break
            upload_file_path = self.plugin.get_file_manager().path_on_disk('local', truncated[:-1])
            if self.plugin.get_file_manager().file_exists('local', upload_file_path.rpartition('/')[2]):
                self.plugin.get_file_manager().remove_file('local', upload_file_path.rpartition('/')[2])
            with open(upload_file_path, 'ab') as combined:
                for f in files:
                    path = self.plugin.get_file_manager().path_on_disk('local', f)
                    with open(path, 'rb') as temp:
                        combined.write(temp.read())
                    self.plugin.get_file_manager().remove_file('local', f.rpartition('/')[2])


            unzippable = upload_file_path

        else:
            return None, error_embed(author=self.plugin.get_printer_name(), title="Not a valid Zip file.", description='try "%sunzip [filename].zip or %sunzip [filename].zip.001 for multi-volume files."' % (self.plugin.get_settings().get(
                                         ["prefix"]), self.plugin.get_settings().get(
                                         ["prefix"])))

        if unzippable == None:
            return None, error_embed(author=self.plugin.get_printer_name(), title="File %s not found." % file_name)


        try:
            with zipfile.ZipFile(unzippable) as zip:

                fileOK = zip.testzip()

                if fileOK is not None:
                    return None, error_embed(author=self.plugin.get_printer_name(), title="Bad zip file.", description='In case of multi-volume files, one could be missing.')

                availablefiles = zip.namelist()
                filestounpack = []
                for f in availablefiles:
                    if f.endswith('.gcode'):
                        filestounpack.append(f)

                path = unzippable.rpartition('/')[0] + '/'

                for f in filestounpack:
                    with open(path + f, 'wb') as file:
                        with zip.open(f) as source:
                            file.write(source.read())

                self.plugin.get_file_manager().remove_file('local', unzippable.rpartition('/')[2])

        except:
            return None, error_embed(author=self.plugin.get_printer_name(), title="Bad zip file.",
                                 description='In case of multi-volume files, one could be missing.')

        return None, success_embed(author=self.plugin.get_printer_name(), title='File(s) unzipped. ', description=str(filestounpack))
    def judge_is_unzippable(self, filename):

        autounzip = self.plugin.get_settings().get(['auto_unzip'])
        truncated = filename[:-4]

        # file is a single zip
        if filename.endswith('.zip'):
            #unzip
            if autounzip:
                return True, success_embed(
                    author=self.plugin.get_printer_name(),
                    title='File Received, starting to unzip....',
                    description=filename)

            # inform the user that they can unzip the file themselves
            else:
                descr = filename + '\n'
                descr += 'Use %sunzip %s to extract all gcode files.' % (
                    self.plugin.get_settings().get(["prefix"]), filename)
                return False, success_embed(
                    author=self.plugin.get_printer_name(),
                    title='File Received',
                    description=descr)

        # file is part of a multi-volume zip
        elif truncated.endswith('.zip'):

            # find all available multi-volumes belonging to the file in question
            filelist = self.get_flat_file_list()
            available_files = []

            # get all available parts of the zip
            for f in filelist:

                temp_path = f.get('path')

                # check for file ending in .zip.XXX
                if truncated.upper() in temp_path.upper():

                    trunc_filename = filename[:-3] + temp_path[-3:]
                    real_path = self.plugin.get_file_manager().path_on_disk(
                        f.get('location'), trunc_filename)

                    available_files.append(real_path)

            # sort the filenames nicely so missing files can be easily identified
            # for multiple files in a row, don't display all of them
            available_files.sort(key=lambda x: int(x[-3:]))

            blocks_availablefiles = []
            current_block = []
            prev_index = int(available_files[0][-3:]) - 1
            for i in range(0, len(available_files)):
                curr_index = int(available_files[i][-3:])
                if curr_index is prev_index + 1:
                    current_block.append(available_files[i].rpartition('/')[2])
                else:
                    blocks_availablefiles.append(current_block)
                    current_block = [available_files[i].rpartition('/')[2]]

                prev_index = curr_index
            blocks_availablefiles.append(current_block)

            differing_found = False
            last_index = -1

            # search for signature in last block
            # it could be that the EOCD signature is split between two or more volumes if volumes are smaller than 65kb
            # search for volumes in reverse order until combined size exceeds MAX_ZIP_SIGNATURE_BLOCK
            signatureblock = blocks_availablefiles[-1]
            temp_filename = 'TEMP_' + signatureblock[-1]
            temp_filepath = self.plugin.get_file_manager().path_on_disk(
                'local', temp_filename)
            temp_combinedsize = 0
            minimized_block_paths = []

            # minimize block size, take only as many volumes as needed to grow beyond MAX_ZIP_SIGNATURE_BLOCK
            # the rest of the block's volumes can't have the signature inside them if it exists
            for i in range(len(signatureblock) - 1, 0, -1):
                path = self.plugin.get_file_manager().path_on_disk(
                    'local', signatureblock[i])
                temp_combinedsize += os.path.getsize(path)
                minimized_block_paths.append(path)
                if temp_combinedsize >= MAX_ZIP_SIGNATURE_BLOCK:
                    # if the signature exists it's guaranteed to be found inside combined now
                    break

            # concatenate the shortened block
            with open(temp_filepath, 'ab') as combined:
                for path in reversed(minimized_block_paths):
                    with open(path, 'rb') as temp:
                        combined.write(temp.read())
                combined.close()

            # search for signature
            with open(temp_filepath, 'rb') as combined:
                if os.path.getsize(temp_filepath) > MAX_ZIP_SIGNATURE_BLOCK:
                    combined.seek(-MAX_ZIP_SIGNATURE_BLOCK, os.SEEK_END)
                block = bytearray(combined.read())

                if ZIP_EOCD_SIGNATURE in block:
                    differing_found = True
                    last_index = int(temp_filepath[-3:])

                #for some reason, the file manager doesn't find these files
                combined.close()
                os.remove(temp_filepath)

            string_availablefiles = ''

            for b in blocks_availablefiles:
                line = b[0]
                if len(b) >= 2:
                    line += ' - ' + b[-1]

                string_availablefiles += line + '\n'

            #we don't have the last file yet, can't find out how many volumes
            if differing_found is not True:
                return False, info_embed(author=self.plugin.get_printer_name(),
                                         title='%s of ??? Files Received' %
                                         (str(len(available_files))),
                                         description=string_availablefiles)

            #we have the last file, volumes are missing but we know how many volumes there are now
            elif len(available_files) is not last_index:
                return False, info_embed(
                    author=self.plugin.get_printer_name(),
                    title='%s of %s Files Received' %
                    (str(len(available_files)), str(last_index)),
                    description=string_availablefiles)

            #still inform the user how many files there are and how to unzip them
            elif autounzip is not True:
                descr = string_availablefiles
                descr += 'Use %sunzip %s to extract all gcode files.' % (
                    self.plugin.get_settings().get(
                        ["prefix"]), available_files[0].rpartition('/')[2])
                return False, success_embed(
                    author=self.plugin.get_printer_name(),
                    title='%s of %s Files Received' %
                    (str(len(available_files)), str(last_index)),
                    description=descr)

            else:
                return True, success_embed(
                    author=self.plugin.get_printer_name(),
                    title='All Files Received, starting to unzip....',
                    description=string_availablefiles)

        return False, success_embed(author=self.plugin.get_printer_name(),
                                    title='File Received',
                                    description=filename)