More documentation

This commit is contained in:
Gina Häußge 2015-02-10 16:24:28 +01:00
parent 7de90e16f6
commit 197ed7b912
3 changed files with 318 additions and 5 deletions

View file

@ -56,7 +56,7 @@ Example
Placeholders
============
You can use the following generic placeholders in your events:
You can use the following generic placeholders in your event hooks:
* ``{__currentZ}``: the current Z position of the head if known, -1 if not available
* ``{__filename}``: filename of the currently selected file, "NO FILE" if not available

View file

@ -385,13 +385,137 @@ class TemplatePlugin(Plugin):
class SimpleApiPlugin(Plugin):
"""
Utilizing the ``SimpleApiPlugin`` mixin plugins may implement a simple API based around one GET resource and one
resource accepting JSON commands POSTed to it. This is the easy alternative for plugin's which don't need the
full power of a `Flask Blueprint <http://flask.pocoo.org/docs/0.10/blueprints/>`_ that the :class:`BlueprintPlugin`
mixin offers.
Use this mixin if all you need to do is return some kind of dynamic data to your plugin from the backend
and/or want to react to simple commands which boil down to a type of command and a couple of flat parameters
supplied with it.
The simple API constructed by OctoPrint for you will be made available under ``/api/plugin/<plugin identifier>/``.
OctoPrint will do some preliminary request validation for your defined commands, making sure the request body is in
the correct format (content type must be JSON) and contains all obligatory parameters for your command.
Let's take a look at a small example for such a simple API and how you would go about calling it.
Take this example of a plugin registered under plugin identifier ``mysimpleapiplugin``:
.. code-block:: python
:linenos:
import octoprint.plugin
import flask
class MySimpleApiPlugin(octoprint.plugin.SimpleApiPlugin):
def get_api_commands(self):
return dict(
command1=[],
command2=["some_parameter"]
)
def on_api_command(self, command, data):
import flask
if command == "command1":
parameter = "unset"
if "parameter" in data:
parameter = "set"
self._logger.info("command1 called, parameter is {parameter}".format(**locals()))
elif command == "command2":
self._logger.info("command2 called, some_parameter is {some_parameter}".format(**data))
def on_api_get(self, request):
return flask.jsonify(foo="bar")
__plugin_implementations__ = [MySimpleApiPlugin()]
Our plugin defines two commands, ``command1`` with no mandatory parameters and ``command2`` with one
mandatory parameter ``some_parameter``.
``command1`` can also accept an optional parameter ``parameter``, and will log whether
that parameter was set or unset. ``command2`` will log the content of the mandatory ``some_parameter`` parameter.
A valid POST request for ``command2`` sent to ``/api/plugin/mysimpleapiplugin`` would look like this:
.. sourcecode:: http
POST /api/plugin/mysimpleapiplugin HTTP/1.1
Host: example.com
Content-Type: application/json
X-Api-Key: abcdef...
{
"command": "command2",
"some_parameter": "some_value",
"some_optional_parameter": 2342
}
which would produce a response like this:
.. sourcecode:: http
HTTP/1.1 204 No Content
and print something like this line to ``octoprint.log``::
2015-02-12 17:40:21,140 - octoprint.plugins.mysimpleapiplugin - INFO - command2 called, some_parameter is some_value
A GET request on our plugin's simple API resource will only return a JSON document like this:
.. sourcecode:: http
HTTP/1.1 200 Ok
Content-Type: application/json
{
"foo": "bar"
}
"""
def get_api_commands(self):
"""
Return a dictionary here with the keys representing the accepted commands and the values being lists of
mandatory parameter names.
"""
return None
def on_api_command(self, command, data):
"""
Called by OctoPrint upon a POST request to ``/api/plugin/<plugin identifier>``. ``command`` will contain one of
the commands as specified via :func:`get_api_commands`, ``data`` will contain the full request body parsed
from JSON into a Python dictionary. Note that this will also contain the ``command`` attribute itself. For the
example given above, for the ``command2`` request the ``data`` received by the plugin would be equal to
``dict(command="command2", some_parameter="some_value")``.
If your plugin returns nothing here, OctoPrint will return an empty response with return code ``204 No content``
for you. You may also return regular responses as you would return from any Flask view here though, e.g.
``return flask.jsonify(result="some json result")`` or ``return flask.make_response("Not found", 404)``.
:param string command: the command with which the resource was called
:param dict data: the full request body of the POST request parsed from JSON into a Python dictionary
:return: ``None`` in which case OctoPrint will generate a ``204 No content`` response with empty body, or optionally
a proper Flask response.
"""
return None
def on_api_get(self, request):
"""
Called by OctoPrint upon a GET request to ``/api/plugin/<plugin identifier>``. ``request`` will contain the
received `Flask request object <http://flask.pocoo.org/docs/0.9/api/#flask.Request>`_ which you may evaluate
for additional arguments supplied with the request.
If your plugin returns nothing here, OctoPrint will return an empty response with return code ``204 No content``
for you. You may also return regular responses as you would return from any Flask view here though, e.g.
``return flask.jsonify(result="some json result")`` or ``return flask.make_response("Not found", 404)``.
:param request: the Flask request object
:return: ``None`` in which case OctoPrint will generate a ``204 No content`` response with empty body, or optionally
a proper Flask response.
"""
return None
@ -604,15 +728,60 @@ class SettingsPlugin(Plugin):
class EventHandlerPlugin(Plugin):
"""
The ``EventHandlerPlugin`` mixin allows OctoPrint plugins to react to any of :ref:`OctoPrint's events <sec-events>`.
OctoPrint will call the :func:`on_event` method for any event fired on its internal event bus, supplying the
event type and the associated payload. Please note that until your plugin returns from that method, further event
processing within OctoPrint will block - the event queue itself is run asynchronously from the rest of OctoPrint,
but the processing of the events within the queue itself happens consecutively.
This mixin is especially interesting for plugins which want to react on things like print jobs finishing, timelapse
videos rendering etc.
"""
def on_event(self, event, payload):
"""
Called by OctoPrint upon processing of a fired event on the platform.
:param string event: the type of event that got fired, see :ref:`the list of events <sec-events-available_events>`_
for possible values
:param dict payload: the payload as provided with the event
"""
pass
class SlicerPlugin(Plugin):
"""
Via the ``SlicerPlugin`` mixin plugins can add support for slicing engines to be used by OctoPrint.
"""
def is_slicer_configured(self):
"""
Unless the return value of this method is ``True``, OctoPrint will not register the slicer within the slicing
sub system upon startup. Plugins may use this to do some start up checks to verify that e.g. the path to
a slicing binary as set and the binary is executable, or credentials of a cloud slicing platform are properly
entered etc.
"""
return False
def get_slicer_properties(self):
"""
Plugins should override this method to return a ``dict`` containing a bunch of meta data about the implemented slicer.
The expected keys in the returned ``dict`` have the following meaning:
type
The type identifier to use for the slicer. This should be a short unique lower case string which will be
used to store slicer profiles under or refer to the slicer programmatically or from the API.
name
The human readable name of the slicer. This will be displayed to the user during slicer selection.
same_device
``True`` if the slicer runs on the same device as OctoPrint, ``False`` otherwise. Slicers running on the same
device will TODO
progress_report
``True`` if the slicer can report back slicing progress to OctoPrint ``False`` otherwise.
"""
return dict(
type=None,
name=None,
@ -620,22 +789,71 @@ class SlicerPlugin(Plugin):
progress_report=False
)
def get_slicer_profile_options(self):
def get_slicer_default_profile(self):
"""
Should return a :class:`SlicingProfile` containing the default slicing profile to use with this slicer if
no other profile has been selected.
"""
return None
def get_slicer_profile(self, path):
return None
"""
Should return a :class:`SlicingProfile` parsed from the slicing profile stored at the indicated ``path``.
def get_slicer_default_profile(self):
:param string path: the path from which to read the slicing profile
"""
return None
def save_slicer_profile(self, path, profile, allow_overwrite=True, overrides=None):
"""
Should save the provided :class:`SlicingProfile` to the indicated ``path``, after applying any supplied
``overrides``. If a profile is already saved under the indicated path and ``allow_overwrite`` is set to
``False`` (defaults to ``True``), an ``IOError`` should be raised.
:param string path: the path to which to save the profile
:param :class:`SlicingProfile` profile: the profile to save
:param bool allow_overwrite: whether to allow to overwrite an existing profile at the indicated path (``True``, default)
or not (``False``) - if a profile already exists on the path and this is ``False``
and :class:`IOError` should be raised
:param dict overrides: profile overrides to apply to the ``profile`` before saving it
"""
pass
def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_path=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None):
def do_slice(self, model_path, printer_profile, machinecode_path=None, profile_path=None, position=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None):
"""
Called by OctoPrint to slice ``model_path`` for the indicated ``printer_profile``. If the ``machinecode_path`` is ``None``,
slicer implementations should generate it from the provided model_path.
If provided, the ``profile_path`` is guaranteed by OctoPrint to be a serialized slicing profile created through the slicing
plugin's own :func:`save_slicer_profile` method.
If provided, ``position`` will be a ``dict`` containing and ``x`` and a ``y`` key, indicating the position
the center of the model on the print bed should have in the final sliced machine code. If not provided, slicer
implementations should place the model in the center of the print bed.
``on_progress`` will be a callback which expects an additional keyword argument ``_progress`` with the current
slicing progress which - if progress reporting is supported - the slicing plugin should call like the following:
.. code-block:: python
if on_progress is not None:
if on_progress_args is None:
on_progress_args = ()
if on_progress_kwargs is None:
on_progress_kwargs = dict()
on_progress_kwargs["_progress"] = your_plugins_slicing_progress
on_progress(*on_progress_args, **on_progress_kwargs)
Please note that both ``on_progress_args`` and ``on_progress_kwargs`` as supplied by OctoPrint might be ``None``,
so always make sure to initialize those values to sane defaults like depicted above before invoking the callback.
"""
pass
def cancel_slicing(self, machinecode_path):
"""
Cancels the slicing to the indicated file
"""
pass

View file

@ -32,6 +32,101 @@ class BedTypes(object):
return [getattr(cls, name) for name in cls.__dict__ if not name.startswith("__")]
class PrinterProfileManager(object):
"""
Manager for printer profiles. Offers methods to select the globally used printer profile and to list, add, remove,
load and save printer profiles.
A printer profile is a ``dict`` of the following structure:
.. list-table::
:widths: 15 5 10 30
:header-rows: 1
* - Name
- Type
- Description
* - ``id``
- ``string``
- Internal id of the printer profile
* - ``name``
- ``string``
- Human readable name of the printer profile
* - ``model``
- ``string``
- Printer model
* - ``color``
- ``string``
- Color to associate with the printer profile
* - ``volume``
- ``dict``
- Information about the print volume
* - ``volume.width``
- ``float``
- Width of the print volume (X axis)
* - ``volume.depth``
- ``float``
- Depth of the print volume (Y axis)
* - ``volume.height``
- ``float``
- Height of the print volume (Z axis)
* - ``volume.formFactor``
- ``string``
- Form factor of the print bed, either ``rectangular`` or ``circular``
* - ``heatedBed``
- ``bool``
- Whether the printer has a heated bed (``True``) or not (``False``)
* - ``extruder``
- ``dict``
- Information about the printer's extruders
* - ``extruder.count``
- ``int``
- How many extruders the printer has (default 1)
* - ``extruder.offsets``
- ``list`` of ``tuple``s
- Extruder offsets relative to first extruder, list of (x, y) tuples, first is always (0,0)
* - ``extruder.nozzleDiameter``
- ``float``
- Diameter of the printer nozzle
* - ``axes``
- ``dict``
- Information about the printer axes
* - ``axes.x``
- ``dict``
- Information about the printer's X axis
* - ``axes.x.speed``
- ``float``
- Speed of the X axis in mm/s
* - ``axes.x.inverted``
- ``bool``
- Whether a positive value change moves the nozzle away from the print bed's origin (False, default) or towards it (True)
* - ``axes.y``
- ``dict``
- Information about the printer's Y axis
* - ``axes.y.speed``
- ``float``
- Speed of the Y axis in mm/s
* - ``axes.y.inverted``
- ``bool``
- Whether a positive value change moves the nozzle away from the print bed's origin (False, default) or towards it (True)
* - ``axes.z``
- ``dict``
- Information about the printer's Z axis
* - ``axes.z.speed``
- ``float``
- Speed of the Z axis in mm/s
* - ``axes.z.inverted``
- ``bool``
- Whether a positive value change moves the nozzle away from the print bed (False, default) or towards it (True)
* - ``axes.e``
- ``dict``
- Information about the printer's E axis
* - ``axes.e.speed``
- ``float``
- Speed of the E axis in mm/s
* - ``axes.e.inverted``
- ``bool``
- Whether a positive value change extrudes (False, default) or retracts (True) filament
"""
default = dict(
id = "_default",