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))
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'])
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")
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)
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))
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)
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])
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)
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)