Module pipettin-piper.piper.plugins.plugin
Functions
def load_plugin(controller: "'Controller'", **kwargs)-
Expand source code
def load_plugin(controller: "Controller", **kwargs): """ Plugins are expected to have a function named 'load_plugin' which will instantiate the plugin's class and returning it to the main Commander class. If they fail to load, they must raise a PluginError exception. """ logging.debug(f"load_plugin: loading {plugin_name} plugin.") try: class_instance = Plugin(controller=controller, **kwargs) except Exception as e: msg = f"Failed to load with error: {e}" logging.error(msg) raise PluginError(msg) from e return class_instancePlugins are expected to have a function named 'load_plugin' which will instantiate the plugin's class and returning it to the main Commander class. If they fail to load, they must raise a PluginError exception.
Classes
class Plugin (controller: Controller)-
Expand source code
class Plugin: """Base class for plugins.""" def __init__(self, controller: Controller): # Log messages. logging.info("Loading plugin %s", plugin_name) # Stop here if a plugin has not implemented its own __init__. raise PluginError("Plugins must override the init method of the base class") # Save the Controller and GCODE builder objects. self.controller = controller self.gcode_builder: GcodeBuilder = controller.builder # Get the gcode generator. self.gcode: GcodePrimitives = controller.builder.gcode # Add your handlers for new protocol actions. # The builder handler is used by 'builder.parseAction' to generate GCODE. self.controller.builder.add_action_handler(name=self.action_name, function=self.action_handler) # The controller handler is used by 'controller.run_actions_protocol', # to execute the action. self.controller.add_action_runner(name=self.action_name, function=self.action_runner) # Add socket.io handlers. self.register_event_handlers() # Example: add a coroutine for the controller to launch at start. self.controller.coroutine_methods.extend([ self.example_coroutine() ]) # Set status. self._status = True @staticmethod def make_cmd_id(data: str = ""): """Generate an MD5 hash from the provided string. The current time is appended to the string, to make hashes more unique. """ # Should be unique by using the current time uid = str(data) + str(time.time()) uid_md5 = md5(uid.encode()) cmd_id = uid_md5.hexdigest() return cmd_id action_name = "MAGIC" def action_handler(self, action: dict, i: int): """This method must generate GCODE for the provided action. Args: action (dict): Raw action data. i (int): Action index. """ # GCODE must be saved in a list. commands = [] # Append a comment to the GCODE command list. commands.append( self.gcode.comment("Use the GcodePrimitives class (or whatever) to generate GCODE for this action.") ) # Commit the command to the GcodeBuilder class. self.gcode_builder.extend_commands(commands, action) # The return values are not used. You're free. def action_runner(self, action: dict, i: int, wait:bool, check:bool, timeout:float): """This method must execute provided action. Args: action (dict): Processed action data. i (int): Action index. wait (bool): Check that the action "finishes" before returning. check (bool): Check that the action completed "successfully" before returning. timeout (float): Timeout for the "wait" and "check" checks. """ # Do your thing here. The return values are not used. async def example_coroutine(self): """Minimal coroutine object, started by the controller.""" try: while True: asyncio.sleep(1) except asyncio.CancelledError: pass def register_event_handlers(self): """ Add event handlers to the socket.io object from the controller class. The events will typically originate from the Pipettin Writer GUI's backend. """ if self.controller.comms.sio: # Register an event handler. This uses the socket.io object from the controller class. @self.controller.comms.sio.on('example_event') async def example_event_handler(data: dict): # Log the event. logging.info("Received 'example_event' command: %s", pformat(data)) # Do something with the data... cmd_id = data.get("id", None) # Get the ID property, returning "-1" if not found. # Make a unique ID for the command if cmd_id is None: cmd_id = self.make_cmd_id('example_event_handler') # Respond to the event. return {"id": cmd_id, "data": "example response data"} _status = None @property def status(self): """This method reports the status of the plugin. This helps the rest of the program know what's up over here. Must be an atrribute or a property.""" return self._status @status.setter def status(self, value): self._status = True if value else FalseBase class for plugins.
Subclasses
- BaseActions
- ToolHandler
- ColorController
- PluginMonitor
- ToolHandler
- CommandRouter
- TemplateRouter
- PipetteHandler
- PocketController
- StatusUpdater
Class variables
var action_name
Static methods
def make_cmd_id(data: str = '')-
Expand source code
@staticmethod def make_cmd_id(data: str = ""): """Generate an MD5 hash from the provided string. The current time is appended to the string, to make hashes more unique. """ # Should be unique by using the current time uid = str(data) + str(time.time()) uid_md5 = md5(uid.encode()) cmd_id = uid_md5.hexdigest() return cmd_idGenerate an MD5 hash from the provided string. The current time is appended to the string, to make hashes more unique.
Instance variables
prop status-
Expand source code
@property def status(self): """This method reports the status of the plugin. This helps the rest of the program know what's up over here. Must be an atrribute or a property.""" return self._statusThis method reports the status of the plugin. This helps the rest of the program know what's up over here. Must be an atrribute or a property.
Methods
def action_handler(self, action: dict, i: int)-
Expand source code
def action_handler(self, action: dict, i: int): """This method must generate GCODE for the provided action. Args: action (dict): Raw action data. i (int): Action index. """ # GCODE must be saved in a list. commands = [] # Append a comment to the GCODE command list. commands.append( self.gcode.comment("Use the GcodePrimitives class (or whatever) to generate GCODE for this action.") ) # Commit the command to the GcodeBuilder class. self.gcode_builder.extend_commands(commands, action) # The return values are not used. You're free.This method must generate GCODE for the provided action.
Args
action:dict- Raw action data.
i:int- Action index.
def action_runner(self, action: dict, i: int, wait: bool, check: bool, timeout: float)-
Expand source code
def action_runner(self, action: dict, i: int, wait:bool, check:bool, timeout:float): """This method must execute provided action. Args: action (dict): Processed action data. i (int): Action index. wait (bool): Check that the action "finishes" before returning. check (bool): Check that the action completed "successfully" before returning. timeout (float): Timeout for the "wait" and "check" checks. """ # Do your thing here. The return values are not used.This method must execute provided action.
Args
action:dict- Processed action data.
i:int- Action index.
wait:bool- Check that the action "finishes" before returning.
check:bool- Check that the action completed "successfully" before returning.
timeout:float- Timeout for the "wait" and "check" checks.
async def example_coroutine(self)-
Expand source code
async def example_coroutine(self): """Minimal coroutine object, started by the controller.""" try: while True: asyncio.sleep(1) except asyncio.CancelledError: passMinimal coroutine object, started by the controller.
def register_event_handlers(self)-
Expand source code
def register_event_handlers(self): """ Add event handlers to the socket.io object from the controller class. The events will typically originate from the Pipettin Writer GUI's backend. """ if self.controller.comms.sio: # Register an event handler. This uses the socket.io object from the controller class. @self.controller.comms.sio.on('example_event') async def example_event_handler(data: dict): # Log the event. logging.info("Received 'example_event' command: %s", pformat(data)) # Do something with the data... cmd_id = data.get("id", None) # Get the ID property, returning "-1" if not found. # Make a unique ID for the command if cmd_id is None: cmd_id = self.make_cmd_id('example_event_handler') # Respond to the event. return {"id": cmd_id, "data": "example response data"}Add event handlers to the socket.io object from the controller class. The events will typically originate from the Pipettin Writer GUI's backend.