From 3995a65f6ce363188cb35aae9fcc40178022eb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 9 Jul 2015 16:39:29 +0200 Subject: [PATCH] WIP: Moving bundled plugin docs to official docs The wiki is not a prominent enough location for these kind of things apparently. --- docs/bundledplugins/cura.rst | 122 +++++++ docs/bundledplugins/discovery.rst | 0 docs/bundledplugins/index.rst | 13 + docs/bundledplugins/pluginmanager.rst | 0 docs/bundledplugins/softwareupdate.rst | 341 ++++++++++++++++++ ...ins-softwareupdate-yaml_octoprintsetup.png | Bin 0 -> 37654 bytes docs/index.rst | 1 + docs/plugins/hooks.rst | 20 +- 8 files changed, 487 insertions(+), 10 deletions(-) create mode 100644 docs/bundledplugins/cura.rst create mode 100644 docs/bundledplugins/discovery.rst create mode 100644 docs/bundledplugins/index.rst create mode 100644 docs/bundledplugins/pluginmanager.rst create mode 100644 docs/bundledplugins/softwareupdate.rst create mode 100644 docs/images/bundledplugins-softwareupdate-yaml_octoprintsetup.png diff --git a/docs/bundledplugins/cura.rst b/docs/bundledplugins/cura.rst new file mode 100644 index 00000000..a2f84de9 --- /dev/null +++ b/docs/bundledplugins/cura.rst @@ -0,0 +1,122 @@ +.. _sec-bundledplugins_cura: + +Cura +==== + +The Cura Plugin allows slicing of STL files uploaded to OctoPrint directly via +the `CuraEngine `_ **up to and +including version 15.04** and supersedes the slicing support integrated into +OctoPrint so far. + +.. note:: + + The current development version of CuraEngine has changed its calling + parameters in such a way that the current implementation of the Cura plugin + is not compatible to it. Until the plugin can be updated to be compatible + to these changes, please use only CuraEngine versions up to and including + 15.04 (or the ``legacy`` branch in the CuraEngine repository). + +The plugin offers a settings module that allows configuring the path to the +CuraEngine executable to use, as well as importing and managing slicing +profiles to be used. Please note that the Cura Plugin will use the printer +parameters you configured within OctoPrint (meaning bed size and extruder +count and offsets) for slicing. + +.. _sec-bundledplugins-cura-firststeps: + +First Steps +----------- + +Before you can slice from within OctoPrint, you'll need to + + #. :ref:`Install CuraEngine ` + #. :ref:`Configure the path to CuraEngine within OctoPrint ` + #. :ref:`Export a slicing profile from Cura and import it within OctoPrint ` + +.. note:: + + OctoPi 0.12.0 ships with steps 1 and 2 already done, you only need to + supply one or more slicing profiles to get going :) + +.. _sec-bundledplugins-cura-installing: + +Installing CuraEngine +--------------------- + +You'll need a current build of `CuraEngine `_ +in order to be able to use the Cura OctoPrint plugin. If you are running OctoPrint +on a desktop PC (Window, Mac, i386 Linux), you can take this from a full +install of `Cura `_ (you'll find it in the +installation directory). Otherwise you'll need to compile it yourself. + +If you previously used the `old variant of the Cura integration `_, +you probably still have a fully functional binary lying around in the +installation folder of the full install of Cura you used then -- just put the +path to that in the plugin settings. + +.. _sec-bundledplugins-cura-installing-raspbian: + +Compiling for Raspbian +++++++++++++++++++++++ + +.. note:: + + A binary of CuraEngine 14.12 precompiled on Raspbian 2015-01-31 is available + `here `_. Don't forget to make it + executable after copying it to your preferred destination on your Pi + (suggestion: ``/usr/local/bin``) with ``chmod +x cura_engine``. Use at your + own risk. + +You'll need to install a new version of gcc and g++ and patch CuraEngine's +Makefile (see `this post `_) +in order for the compilation to work on current Raspbian builds (e.g. OctoPi):: + + sudo apt-get -y install gcc-4.7 g++-4.7 + git clone -b legacy https://github.com/Ultimaker/CuraEngine.git + cd CuraEngine + wget http://bit.ly/curaengine_makefile_patch -O CuraEngine.patch + patch < CuraEngine.patch + make CXX=g++-4.7 + +After this has completed, you'll find your shiny new build of CuraEngine in +the `build` folder (full path for above example: +``~/CuraEngine/build/CuraEngine``). + +.. _sec-bundledplugins-cura-configuring: + +Configuring the plugin +---------------------- + +The Cura plugin needs to be configured with the full path to your copy of the +CuraEngine executable that it's supposed to use. You can do this either via +the Cura plugin settings dialog or by manually configuring the path to the +executable via ``config.yaml``, example: + +.. code-block:: yaml + + plugins: + cura: + cura_engine: /path/to/CuraEngine + +.. _sec-bundledplugins-cura-profiles: + +Using Cura Profiles +------------------- + +The Cura Plugin supports importing your existing profiles for Cura **up to and +including Cura 15.04**. Newer Cura releases (e.g. 15.06) do not allow to +export the slicing profile anymore and also use a different internal format +that will *not* work with the current version of the Cura Plugin. + +In order to export a slicing profile from the Cura desktop UI, open it, +set up your profile, then click on "File" and there on "Save Profile". You can +import the .ini-file this creates via the "Import Profile" button in the +Cura Settings within OctoPrint. + +.. _sec-bundledplugins-cura-sourcecode: + +Source code +----------- + +The source of the Cura plugin is bundled with OctoPrint and can be found in +its source repository under ``src/octoprint/plugins/cura``. diff --git a/docs/bundledplugins/discovery.rst b/docs/bundledplugins/discovery.rst new file mode 100644 index 00000000..e69de29b diff --git a/docs/bundledplugins/index.rst b/docs/bundledplugins/index.rst new file mode 100644 index 00000000..d5935a96 --- /dev/null +++ b/docs/bundledplugins/index.rst @@ -0,0 +1,13 @@ +.. _sec-bundledplugins: + +############### +Bundled Plugins +############### + +.. toctree:: + :maxdepth: 2 + + cura.rst + discovery.rst + pluginmanager.rst + softwareupdate.rst diff --git a/docs/bundledplugins/pluginmanager.rst b/docs/bundledplugins/pluginmanager.rst new file mode 100644 index 00000000..e69de29b diff --git a/docs/bundledplugins/softwareupdate.rst b/docs/bundledplugins/softwareupdate.rst new file mode 100644 index 00000000..fcbe49ac --- /dev/null +++ b/docs/bundledplugins/softwareupdate.rst @@ -0,0 +1,341 @@ +.. sec-bundledplugins-softwareupdate: + +Software Update Plugin +====================== + +The Software Update Plugin allows receiving notifications about new releases +of OctoPrint or installed plugins which registered with it and -- if properly +configured -- also applying the found updates. + +.. sec-bundledplugins-softwareupdate-firststeps: + +First Steps +----------- + +Out of the box the Software Update Plugin will be able to notify you of any +updates that might be available for your OctoPrint installation or any plugins +that registered themselves with it. In order to also be able to update +your OctoPrint installation, you'll need to :ref:`configure ` +at least OctoPrint's checkout folder, and you also should +configure the restart commands for OctoPrint and the whole server. + +.. sec-bundledplugins-softwareupdate-octoprintsetup: + +Making OctoPrint updateable on existing installations ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. note:: + + OctoPi releases 0.12.0 and later ship with this already setup for you! + +.. note:: + + **OctoPi 0.11.0 users**: Please also take a look at + `the note at the very end of this FAQ entry `_. + Due to a little issue in that OctoPi release 0.11.0 you might have to fix + the URL your OctoPrint checkout is using for updating. This can easily be + done by SSHing into your OctoPi instance and doing this:: + + cd ~/OctoPrint + git remote set-url origin https://github.com/foosel/OctoPrint.git + +If you updated OctoPrint to 1.2.0 or later from a previous existing install, +you'll probably want to set up its software update configuration to allow it +to update itself from now on. For this you'll need to edit ``config.yaml`` and +make it look like this (``# ...`` indicates where your ``config.yaml`` might +contain additional lines that are not of interest here): + +.. code-block:: yaml + + # ... + plugins: + # ... + softwareupdate: + # ... + checks: + # ... + octoprint: + update_folder: /home/pi/OctoPrint + # ... + octoprint_restart_command: sudo service octoprint restart + environment_restart_command: sudo shutdown -r now + # ... + +.. note:: + + You can copy and paste this YAML snippet into the `Yamlpatcher `_ + to apply it to your ``config.yaml`` without having to edit it manually. Your + preview should look something like the screenshot below. + + .. image:: ../images/bundledplugins-softwareupdate-yaml_octoprintsetup.png + :align: center + :alt: Yamlpatcher preview + +If you are not running OctoPi or didn't setup OctoPrint following the +`Raspberry Pi setup guide `_ +you'll need to substitute ``/home/pi/OctoPrint`` with the folder you originally +cloned OctoPrint into during initial setup. + +Save the file, exit the editor, restart OctoPrint. Whenever new releases +become available, you should now be able to update right from the update +notification. + +.. sec-bundledplugins-softwareupdate-configuration: + +Configuring the Plugin +---------------------- + +.. code-block:: yaml + + plugins: + softwareupdate: + # the time-to-live of the version cache, in minutes + cache_ttl: 60 + + # command to restart OctoPrint (no automatic restart if unset) + octoprint_restart_command: sudo service octoprint restart + + # command to reboot OctoPrint's host (no automatic reboot if unset) + environment_restart_command: sudo shutdown -r now + + # configured version check and update methods + checks: + # "octoprint" is reserved for OctoPrint + octoprint: + # this defines an version check that will check against releases + # published on OctoPrint's Github repository and an update method + # utilizing an (included) update script that will be run on + # OctoPrint's checkout folder + type: github_release + user: foosel + repo: OctoPrint + update_script: '{python} "/path/to/octoprint-update.py" --python="{python}" "{folder}" "{target}"' + update_folder: /path/to/octoprint/checkout/folder + + # further checks may be define here + +.. sec-bundledplugins-softwareupdate-configuration-versionchecks: + +Version checks +++++++++++++++ + + * ``github_release``: Checks against releases published on Github. Additional + config parameters: + + * ``user``: (mandatory) Github user the repository to check belongs to + * ``repo``: (mandatory) Github repository to check + * ``prerelease``: ``True`` or ``False``, default ``False``, set to + ``True`` to also include releases on Github marked as prerelease. + * ``release_compare``: Method to use to compare between current version + information and release versions on Github. One of ``python`` (version + comparison using ``pkg_resources.parse_version``, newer version detected + if remote > current), ``semantic`` (version comparison using + ``semantic_version`` package, newer version detected if remote > current) + and ``unequal`` (string comparison, newer version detected if + remote != current). + + * ``github_commit``: Checks against commits pushed to Github. Additional + config parameters: + + * ``user``: (mandatory) Github user the repository to check belongs to + * ``repo``: (mandatory) Github repository to check + * ``branch``: Branch of the Github repository to check, defaults to + ``master`` if not set. + + * ``git_commit``: Checks a local git repository for new commits on its + configured remote. Additional config parameters: + + * ``checkout_folder``: (mandatory) The full path to the folder with a valid git + repository to check. + + * ``command_line``: Uses a provided script to determine whether an update + is available. Additional config parameters: + + * ``command``: (mandatory) The full path to the script to execute. The script is + expected to return a ``0`` return code if an update is available and to + return the display name of the available version as the final and + optionally the display name of the current version as the next to final + line on stdout. + + * ``python_checker``: Can only be specified by plugins through the + :ref:`hook `. Additional config + parameters: + + * ``python_checker``: (mandatory) A python callable which returns version + information and whether the current version is up-to-date or not, see + below for details. + +.. sec-bundledplugins-softwareupdate-configuration-updatemethods: + +Update methods +++++++++++++++ + + * ``pip``: An URL to provide to ``pip install`` in order to perform the + update. May contain a placeholder ``{target}`` which will be the most + recent version specifier as retrieved from the update check. + * ``update_script``: A script to execute in order to perform the update. May + contain placeholders ``{target}`` (for the most recent version specified + as retrieved from the update check), ``{folder}`` for the working directory + of the script and ``{python}`` for the python executable OctoPrint is + running under. The working directory must be specified either by an + ``update_folder`` setting or if the ``git_commit`` check is used its + ``checkout_folder`` setting. + * ``python_updater``: Can only be specified by plugins through the + :ref:`hook `. A python callable + which performs the update, see below for details. + +.. sec-bundledplugins-softwareupdate-configuration-patterns: + +Common configuration patterns ++++++++++++++++++++++++++++++ + +Example for a setup that allows "bleeding edge" updates of OctoPrint under +OctoPi (the ``update_script`` gets configured correctly automatically by the +plugin itself): + +.. code-block:: yaml + + plugins: + softwareupdate: + checks: + octoprint: + type: github_commit + user: foosel + repo: OctoPrint + branch: devel + update_folder: /home/pi/OctoPrint + +Plugin installed via pip and hosted on Github under +``https://github.com/someUser/OctoPrint-SomePlugin``, only releases should be +tracked: + +.. code-block:: yaml + + plugins: + softwareupdate: + checks: + some_plugin: + type: github_release + user: someUser + repo: OctoPrint-SomePlugin + pip: 'https://github.com/someUser/OctoPrint-SomePlugin/archive/{target}.zip' + +The same, but tracking all commits pushed to branch ``devel`` (thus allowing +"bleeding edge" updates): + +.. code-block:: yaml + + plugins: + softwareupdate: + checks: + some_plugin: + type: github_commit + user: someUser + repo: OctoPrint-SomePlugin + branch: devel + pip: 'https://github.com/someUser/OctoPrint-SomePlugin/archive/{target}.zip' + +.. sec-bundledplugins-softwareupdate-hooks: + +Hooks +----- + +.. sec-bundledplugins-softwareupdate-hooks-check_config: + +octoprint.plugin.softwareupdate.check_config +++++++++++++++++++++++++++++++++++++++++++++ + +.. py:function:: update_config_hook(*args, **kwargs) + + Returns additional check configurations for the Software Update plugin. + + Handlers should return a Python dict containing one entry per check. Usually + this will probably only be the check configuration for the plugin providing + the handler itself, using the plugin's identifier as key. + + The check configuration must match the format expected in the configuration + (see description above). Handlers may also utilize the ``python_checker`` + and ``python_updater`` properties to return Python callables that take care + of performing the version check or the update. + + ``python_checker`` is expected to be a callable matching signature and return + value of the ``get_latest`` methods found in the provided version checkers in + ``src/octoprint/plugins/softwareupdate/version_checks``. ``python_updater`` + is expected to be a callable matching signature and return value of the + ``perform_update`` methods found in the provided updaters in + ``src/octoprint/plugins/softwareupdate/updaters``. + + **Example** + + The example single-file-plugin updates itself from Github releases published + at the (fictional) repository ``https://github.com/someUser/OctoPrint-UpdatePluginDemo``. + + .. code-block:: python + + # coding=utf-8 + from __future__ import absolute_import + + def get_update_information(*args, **kwargs): + return dict( + updateplugindemo=dict( + displayName=self._plugin_name, + displayVersion=self._plugin_version, + + type="github_release", + current=self._plugin_version, + user="someUser", + repo="OctoPrint-UpdatePluginDemo", + + pip="https://github.com/someUser/OctoPrint-UpdatePluginDemo/archive/{target}.zip" + ) + ) + + __plugin_hooks__ = { + "octoprint.plugin.softwareupdate.check_config": get_update_information + } + + :return: A dictionary of check configurations as described above + :rtype: dict + +.. sec-bundledplugins-softwareupdate-helpers: + +Helpers +------- + +.. sec-bundledplugins-softwareupdate-helpers-version_checks: + +version_checks +++++++++++++++ + +``version_checks`` module of the Software Update plugin, allows reusing the +bundled version check variants from plugins (e.g. wrapped in a ``python_checker``). + +.. sec-bundledplugins-softwareupdate-helpers-updaters: + +updaters +++++++++ + +``updaters`` module of the Software Update plugin, allows reusing the bundled +updater variants from plugins (e.g. wrapped in a ``python_updater``). + +.. sec-bundledplugins-softwareupdate-helpers-exceptions: + +exceptions +++++++++++ + +``exceptions`` module of the Software Update plugin. + +.. sec-bundledplugins-softwareupdate-helpers-util: + +util +++++ + +``util`` module of the Software Update plugin. + +.. sec-bundledplugins-softwareupdate-source: + +Source Code +----------- + +The source of the Software Update plugin is bundled with OctoPrint and can be +found in its source repository under ``src/octoprint/plugins/softwareupdate``. diff --git a/docs/images/bundledplugins-softwareupdate-yaml_octoprintsetup.png b/docs/images/bundledplugins-softwareupdate-yaml_octoprintsetup.png new file mode 100644 index 0000000000000000000000000000000000000000..d631dad8fc54b8b78d4e055337e1ee9b41b50790 GIT binary patch literal 37654 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⪙8b03A#y!zs;*HCJ&eFJFe`V(l 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 within the system. @@ -42,7 +42,7 @@ octoprint.accesscontrol.appkey octoprint.comm.protocol.action ------------------------------ -.. py:function:: hook(comm_instance, line, action, *args, **kwargs) +.. py:function:: protocol_action_hook(comm_instance, line, action, *args, **kwargs) React to a :ref:`action command ` received from the printer. @@ -77,7 +77,7 @@ This describes actually four hooks: * ``octoprint.comm.protocol.gcode.sending`` * ``octoprint.comm.protocol.gcode.sent`` -.. py:function:: hook(comm_instance, phase, cmd, cmd_type, gcode, *args, **kwargs) +.. py:function:: protocol_gcodephase_hook(comm_instance, phase, cmd, cmd_type, gcode, *args, **kwargs) Pre- and postprocess commands as they progress through the various phases of being sent to the printer. The phases are the following: @@ -164,7 +164,7 @@ This describes actually four hooks: octoprint.comm.protocol.scripts ------------------------------- -.. py:function:: hook(comm_instance, script_type, script_name, *args, **kwargs) +.. py:function:: protocol_scripts_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 @@ -198,7 +198,7 @@ octoprint.comm.protocol.scripts octoprint.comm.transport.serial.factory --------------------------------------- -.. py:function:: hook(comm_instance, port, baudrate, read_timeout, *args, **kwargs) +.. py:function:: serial_factory_hook(comm_instance, port, baudrate, read_timeout, *args, **kwargs) Return a serial object to use as serial connection to the printer. If a handler cannot create a serial object for the specified ``port`` (and ``baudrate``), it should just return ``None``. @@ -274,7 +274,7 @@ octoprint.comm.transport.serial.factory octoprint.filemanager.extension_tree ------------------------------------ -.. py:function:: hook(*args, **kwargs) +.. py:function:: file_extension_hook(*args, **kwargs) Return additional entries for the tree of accepted file extensions for uploading/handling by the file manager. @@ -310,7 +310,7 @@ octoprint.filemanager.extension_tree octoprint.filemanager.preprocessor ---------------------------------- -.. py:function:: hook(path, file_object, links=None, printer_profile=None, allow_overwrite=False, *args, **kwargs) +.. py:function:: file_preprocessor_hook(path, file_object, links=None, printer_profile=None, allow_overwrite=False, *args, **kwargs) Replace the ``file_object`` used for saving added files to storage by calling :func:`~octoprint.filemanager.util.AbstractFileWrapper.save`. @@ -344,7 +344,7 @@ octoprint.filemanager.preprocessor octoprint.server.http.bodysize ------------------------------ -.. py:function:: hook(current_max_body_sizes, *args, **kwargs) +.. py:function:: server_bodysize_hook(current_max_body_sizes, *args, **kwargs) Allows extending the list of custom maximum body sizes on the web server per path and HTTP method with custom entries from plugins. @@ -382,7 +382,7 @@ octoprint.server.http.bodysize octoprint.server.http.routes ---------------------------- -.. py:function:: hook(server_routes, *args, **kwargs) +.. py:function:: server_route_hook(server_routes, *args, **kwargs) Allows extending the list of routes registered on the web server. @@ -437,7 +437,7 @@ octoprint.server.http.routes octoprint.ui.web.templatetypes ------------------------------ -.. py:function:: hook(template_sorting, template_rules, *args, **kwargs) +.. py:function:: templatetype_hook(template_sorting, template_rules, *args, **kwargs) Allows extending the set of supported template types in the web interface. This is interesting for plugins which want to offer other plugins to hook into their own offered UIs. Handlers must return a list of additional template