[Docs] Documented octoprint.comm.protocol.gcode hook
Experimenting with including examples stored on github, let's see if RTD likes that.
This commit is contained in:
parent
af7d2bb8c7
commit
c6e4057add
4 changed files with 145 additions and 7 deletions
|
|
@ -32,7 +32,8 @@ needs_sphinx = '1.3'
|
|||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['codeblockext', 'sphinx.ext.todo', 'sphinx.ext.autodoc', 'sphinxcontrib.httpdomain', 'sphinx.ext.napoleon']
|
||||
extensions = ['codeblockext', 'onlineinclude', 'sphinx.ext.todo', 'sphinx.ext.autodoc', 'sphinxcontrib.httpdomain',
|
||||
'sphinx.ext.napoleon']
|
||||
todo_include_todos = True
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
|
|
|||
|
|
@ -8,12 +8,54 @@ Available plugin hooks
|
|||
octoprint.comm.protocol.gcode
|
||||
-----------------------------
|
||||
|
||||
.. py:function:: hook(comm_instance, cmd, cmd_type=None, with_checksum=None)
|
||||
|
||||
Preprocess and optionally suppress a GCODE command before it is being sent to the printer.
|
||||
|
||||
Hook handlers may use this to rewrite or completely suppress certain commands before they enter the send queue of
|
||||
the communication layer. The hook handler will be called with the ``cmd`` to be sent to the printer as well as
|
||||
the parameters for sending like ``cmd_type`` and ``with_checksum``.
|
||||
|
||||
If the handler does not wish to handle the command, it should simply perform a ``return cmd`` as early as possible,
|
||||
that will ensure that no changes are applied to the command.
|
||||
|
||||
If the handler wishes to suppress sending of the command altogether, it should return None instead. That will tell
|
||||
OctoPrint that the ``cmd`` has been scraped altogether and not send anything.
|
||||
|
||||
More granular manipulation of the sending logic is possible by not just returning ``cmd`` (be it the original, a
|
||||
rewritten variant or a None value) but a 2-tuple (cmd, cmd_type) or a 3-tuple (cmd, cmd_type, with_checksum). This
|
||||
allows to also rewrite the ``cmd_type`` and the ``with_checksum`` parameter used for sending. Note that the latter
|
||||
should only be necessary in very rare circumstances, since usually plugins should not need to have to decide whether
|
||||
a command should be sent with a checksum or not.
|
||||
|
||||
Defining a ``cmd_type`` other than None will make sure OctoPrint takes care of only having one command of that type
|
||||
in its sending queue. Predefined types are ``temperature_poll`` for temperature polling via ``M105`` and
|
||||
``sd_status_poll`` for polling the SD printing status via ``M27``.
|
||||
|
||||
**Example**
|
||||
|
||||
The following hook handler replaces all ``M107`` ("Fan Off", deprecated) with an ``M106 S0`` ("Fan On" with speed
|
||||
parameter)
|
||||
|
||||
.. onlineinclude:: https://raw.githubusercontent.com/OctoPrint/Plugin-Examples/master/rewrite_m107.py
|
||||
:linenos:
|
||||
:lines: 3-
|
||||
|
||||
:param object comm_instance: The :class:`~octoprint.util.comm.MachineCom` instance which triggered the hook.
|
||||
:param str cmd: The GCODE command for which the hook was triggered. This is the full command as taken either
|
||||
from the currently streamed GCODE file or via other means (e.g. user input our status polling).
|
||||
:param str cmd_type: Type of command, ``temperature_poll`` for temperature polling or ``sd_status_poll`` for SD
|
||||
printing status polling.
|
||||
:param boolean with_checksum: Whether the ``cmd`` was to be sent with a checksum (True) or not (False)
|
||||
:return: A rewritten ``cmd``, a tuple of ``cmd`` and ``cmd_type`` or ``cmd``, ``cmd_type`` and ``with_checksum``
|
||||
or None to suppress sending of the ``cmd`` to the printer. See above for details.
|
||||
|
||||
.. _sec-plugins-hook-comm-protocol-action:
|
||||
|
||||
octoprint.comm.protocol.action
|
||||
------------------------------
|
||||
|
||||
.. py:function:: hook(comm_instance, line, action)
|
||||
.. py:function:: hook(comm_instance, line, action, *args, **kwargs)
|
||||
|
||||
React to a :ref:`action command <>` received from the printer.
|
||||
|
||||
|
|
@ -32,7 +74,7 @@ octoprint.comm.protocol.action
|
|||
octoprint.comm.protocol.scripts
|
||||
-------------------------------
|
||||
|
||||
.. py:function:: hook(comm_instance, script_type, script_name)
|
||||
.. py:function:: hook(comm_instance, script_type, script_name, *args, **kwargs)
|
||||
|
||||
Return a prefix to prepend and a postfix to append to the script ``script_name`` of type ``type``. Handlers should
|
||||
make sure to only proceed with returning additional scripts if the ``script_type`` and ``script_name`` match
|
||||
|
|
@ -50,7 +92,7 @@ octoprint.comm.protocol.scripts
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
def hook(comm_instance, script_type, script_name):
|
||||
def handler(comm_instance, script_type, script_name):
|
||||
if not script_type == "gcode" or not script_name == "afterPrinterConnected":
|
||||
return None
|
||||
|
||||
|
|
@ -58,7 +100,8 @@ octoprint.comm.protocol.scripts
|
|||
postfix = ["M117 Connected", "M117 to OctoPrint"]
|
||||
return prefix, postfix
|
||||
|
||||
__plugin_hooks__ = {"octoprint.comm.protocol.scripts": hook}
|
||||
__plugin_name__ = "Example: GCODE script hook demo"
|
||||
__plugin_hooks__ = {"octoprint.comm.protocol.scripts": handler}
|
||||
|
||||
:param MachineCom comm_instance: The :class:`~octoprint.util.comm.MachineCom` instance which triggered the hook.
|
||||
:param str script_type: The type of the script for which the hook was called, currently only "gcode" is supported here.
|
||||
|
|
|
|||
56
docs/sphinxext/onlineinclude.py
Normal file
56
docs/sphinxext/onlineinclude.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# coding=utf-8
|
||||
from __future__ import absolute_import
|
||||
|
||||
__author__ = "Gina Häußge <osd@foosel.net>"
|
||||
__license__ = 'The MIT License <http://opensource.org/licenses/MIT>'
|
||||
__copyright__ = "Copyright (C) 2015 Gina Häußge - Released under terms of the MIT License"
|
||||
|
||||
|
||||
import codecs
|
||||
import urllib2
|
||||
|
||||
from sphinx.directives import LiteralInclude, dedent_lines
|
||||
|
||||
cache = dict()
|
||||
|
||||
class OnlineIncludeDirective(LiteralInclude):
|
||||
|
||||
def read_with_encoding(self, filename, document, codec_info, encoding):
|
||||
global cache
|
||||
|
||||
f = None
|
||||
try:
|
||||
if not self.arguments[0] in cache:
|
||||
f = codecs.StreamReaderWriter(urllib2.urlopen(self.arguments[0]), codec_info[2],
|
||||
codec_info[3], 'strict')
|
||||
lines = f.readlines()
|
||||
cache[self.arguments[0]] = lines
|
||||
else:
|
||||
lines = cache[self.arguments[0]]
|
||||
|
||||
lines = dedent_lines(lines, self.options.get('dedent'))
|
||||
return lines
|
||||
except (IOError, OSError, urllib2.URLError):
|
||||
return [document.reporter.warning(
|
||||
'Include file %r not found or reading it failed' % self.arguments[0],
|
||||
line=self.lineno)]
|
||||
except UnicodeError:
|
||||
return [document.reporter.warning(
|
||||
'Encoding %r used for reading included file %r seems to '
|
||||
'be wrong, try giving an :encoding: option' %
|
||||
(encoding, self.arguments[0]))]
|
||||
finally:
|
||||
if f is not None:
|
||||
f.close()
|
||||
|
||||
def visit_onlineinclude(translator, node):
|
||||
translator.visit_literal_block(node)
|
||||
|
||||
def depart_onlineinclude(translator, node):
|
||||
translator.depart_literal_block(node)
|
||||
|
||||
def setup(app):
|
||||
app.add_directive("onlineinclude", OnlineIncludeDirective)
|
||||
|
||||
handler = (visit_onlineinclude, depart_onlineinclude)
|
||||
app.add_node(OnlineIncludeDirective, html=handler, latex=handler, text=handler)
|
||||
|
|
@ -1362,16 +1362,35 @@ class MachineCom(object):
|
|||
|
||||
if not self.isStreaming():
|
||||
for hook in self._gcode_hooks:
|
||||
hook_cmd = self._gcode_hooks[hook](self, cmd)
|
||||
if hook_cmd and isinstance(hook_cmd, basestring):
|
||||
hook_cmd = self._gcode_hooks[hook](self, cmd, cmd_type=cmd_type, send_checksum=sendChecksum)
|
||||
|
||||
# hook might have returned (cmd, sendChecksum) or (cmd, sendChecksum, cmd_type), split that
|
||||
if isinstance(hook_cmd, tuple):
|
||||
if len(hook_cmd) == 2:
|
||||
hook_cmd, cmd_type = hook_cmd
|
||||
elif len(hook_cmd) == 3:
|
||||
hook_cmd, cmd_type, sendChecksum = hook_cmd
|
||||
|
||||
# hook might have returned None for cmd, if so stop processing, we won't send this command
|
||||
# to the printer
|
||||
if hook_cmd is None:
|
||||
cmd = None
|
||||
break
|
||||
|
||||
# if hook_cmd is a string, we'll replace cmd with it (it's been rewritten by the hook handler
|
||||
elif isinstance(hook_cmd, basestring):
|
||||
cmd = hook_cmd
|
||||
|
||||
# try to parse the cmd and extract the gcode type
|
||||
gcode = self._regex_command.search(cmd)
|
||||
if gcode:
|
||||
gcode = gcode.group(1)
|
||||
|
||||
# fire events if necessary
|
||||
if gcode in gcodeToEvent:
|
||||
eventManager().fire(gcodeToEvent[gcode])
|
||||
|
||||
# send it through the specific handler if it exists
|
||||
gcodeHandler = "_gcode_" + gcode
|
||||
if hasattr(self, gcodeHandler):
|
||||
cmd = getattr(self, gcodeHandler)(cmd)
|
||||
|
|
@ -1388,6 +1407,25 @@ class MachineCom(object):
|
|||
else:
|
||||
self._enqueue_for_sending(cmd, command_type=cmd_type)
|
||||
|
||||
def gcode_command_for_cmd(self, cmd):
|
||||
"""
|
||||
Tries to parse the provided ``cmd`` and extract the GCODE command identifier from it (e.g. "G0" for "G0 X10.0").
|
||||
|
||||
Arguments:
|
||||
cmd (str): The command to try to parse.
|
||||
|
||||
Returns:
|
||||
str or None: The GCODE command identifier if it could be parsed, or None if not.
|
||||
"""
|
||||
if not cmd:
|
||||
return None
|
||||
|
||||
gcode = self._regex_command.search(cmd)
|
||||
if not gcode:
|
||||
return None
|
||||
|
||||
return gcode.group(1)
|
||||
|
||||
##~~ send loop handling
|
||||
|
||||
def _enqueue_for_sending(self, command, linenumber=None, command_type=None):
|
||||
|
|
|
|||
Loading…
Reference in a new issue