From 8f6784d5d236901e877c1feb99ad65a1f4502d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 9 Mar 2015 08:51:49 +0100 Subject: [PATCH] WIP: streamlining and documenting custom controls --- docs/configuration/custom_controls.rst | 135 ++++++++++++++ docs/configuration/index.rst | 11 ++ docs/configuration/yaml.rst | 175 ++++++++++++++++++ .../configuration-custom_controls-example.png | Bin 0 -> 22129 bytes docs/index.rst | 1 + src/octoprint/settings.py | 10 +- .../static/js/app/viewmodels/control.js | 34 ++-- 7 files changed, 352 insertions(+), 14 deletions(-) create mode 100644 docs/configuration/custom_controls.rst create mode 100644 docs/configuration/index.rst create mode 100644 docs/configuration/yaml.rst create mode 100644 docs/images/configuration-custom_controls-example.png diff --git a/docs/configuration/custom_controls.rst b/docs/configuration/custom_controls.rst new file mode 100644 index 00000000..eb9af385 --- /dev/null +++ b/docs/configuration/custom_controls.rst @@ -0,0 +1,135 @@ +.. _sec-configuration-custom_controls: + +Custom Controls +=============== + +OctoPrint allows you to add custom controls to the "Control" tab of its interface. Control types reach from simple +buttons which trigger sending of one or more lines of GCODE to the printer over more complex controls allowing +parameterization of these commands with values entered by the user to full blown GCODE script templates backed by +`Jinja2 `_. + +.. note:: + + At the current time, the configuration of custom controls is only possible through manually editing OctoPrint's + ``config.yaml`` file. + + To make sure that your ``config.yaml`` stays valid when adding custom controls, don't hesitate to take a look at the + :ref:`YAML Primer `. + +.. _sec-configuration-custom_controls-configyaml: + +config.yaml +----------- + +Custom controls are configured within ``config.yaml`` in a ``controls`` section which basically represents a hierarchical +structure of all configured custom controls of various types. + +The following example defines a control for enabling the cooling fan with a variable speed defined by the user +(default 255 and selectable through a slider UI element) and a control for disabling the fan, all within a section named +"Fan", two example controls with multiple commands in a section "Example for multiple commands" and a command with printer +feedback evaluation for the result of the M114 "Get Position" gcode inside a section named "Reporting". + +.. sourcecode:: yaml + + controls: + - name: Fan + type: section + children: + - name: Enable Fan + type: parametric_command + command: M106 S%(speed)s + input: + - name: Speed (0-255) + parameter: speed + default: 255 + slider: + min: 0 + max: 255 + - name: Disable Fan + type: command + command: M107 + - name: Example for multiple commands + type: section + children: + - name: Move X (static) + type: commands + commands: + - G91 + - G1 X10 F3000 + - G90 + - name: Move X (parametric) + type: parametric_commands + commands: + - G91 + - G1 X%(distance)s F%(speed)s + - G90 + input: + - default: 10 + name: Distance + parameter: distance + - default: 3000 + name: Speed + parameter: speed + - name: Reporting + type: section + children: + - command: M114 + name: Get Position + type: feedback_command + regex: "X:([0-9.]+) Y:([0-9.]+) Z:([0-9.]+) E:([0-9.]+)" + template: "Position: X={0}, Y={1}, Z={2}, E={3}" + +Adding this to ``config.yaml``, restarting the OctoPrint server and switching to the "Control" tab within its +interface yields the following visual representation: + +.. _fig-configuration-custom_controls-example: +.. figure:: ../images/configuration-custom_controls-example.png + :align: center + :alt: The rendered output created through the example configuration + +As you can see there are quite a number of different custom controls already in this small example, each with their own +attributes: :ref:`sections `, :ref:`commands `, +:ref:`parametric commands ` and +:ref:`feedback commands `. Two attributes are common for all +of the types: ``name`` and ``type``. + +.. _sec-configuration-custom_controls-types: + +Types +----- + +.. _sec-configuration-custom_controls-types: + +Sections +........ + +.. _sec-configuration-custom_controls-types: + +Rows +.... + +.. _sec-configuration-custom_controls-types: + +Section rows +............ + +.. _sec-configuration-custom_controls-types: + +Commands +........ + +.. _sec-configuration-custom_controls-types-parametric_command: + +Parametric commands +................... + +.. _sec-configuration-custom_controls-types-script: + +Scripts +....... + +.. _sec-configuration-custom_controls-types-feedback_command: + +Feedback commands +................. + diff --git a/docs/configuration/index.rst b/docs/configuration/index.rst new file mode 100644 index 00000000..7a078cef --- /dev/null +++ b/docs/configuration/index.rst @@ -0,0 +1,11 @@ +.. _sec-configuration: + +############# +Configuration +############# + +.. toctree:: + :maxdepth: 2 + + custom_controls.rst + yaml.rst \ No newline at end of file diff --git a/docs/configuration/yaml.rst b/docs/configuration/yaml.rst new file mode 100644 index 00000000..4fc37ef7 --- /dev/null +++ b/docs/configuration/yaml.rst @@ -0,0 +1,175 @@ +.. _sec-configuration-yaml: + +A YAML Primer +============= + +Most of OctoPrint's configuration is done under the hood through `YAML `_ files, +which is why it makes sense to shed some light on the basics of this data serialization format. + +YAML is a text based format which excels at representing the most common of data structures in an easy and very human +readable way, which is why it was chosen for OctoPrint's configuration files. A text editor is all you need in order +to write YAML configuration files. + +.. _sec-configuration-yaml-basic: + +Basic Rules +----------- + +First of all some basic things to know about working with YAML files: + + * Never use tabs outside of quoted strings, especially not for indentation. The tab characters is illegal within + YAML files. + * Whitespace and indentation matters and plays an important part in structuring the data, so take special care + to stay consistent here. + * YAML's comments start with a `#` and go until the end of the line. + +.. _sec-configuration-yaml-types: + +Interesting data types +---------------------- + +You will probably only come across the three most basic types of data within OctoPrint's YAML files: scalars +(such as strings, integers, ...), lists and associated arrays (aka key-value-paris, aka maps, aka dictionaries). + +.. _sec-configuration-yaml-types-scalar: + +Scalars +....... + +Scalars are the most basic of all data types and are simple string, integer, float or boolean values. + +For most scalars you don't need any quotes at all, but if you need to define some piece of data which contains characters +that could be mistaken with YAML syntax you need to quote it in either double ``"`` or single ``'`` quotes for the +YAML file to stay valid. As simple rule of thumb, if your data contains any of these characters ``:-{}[]!#|>&%@`` better +quote it. Also quote it if you want a string but it could be mistaken for a valid number (integer or float) or if +it consists only of "Yes", "No", "yes", "no", "true" or "false", which would be converted to a boolean without quotes. + +In double quoted strings if you need to include a literal double quote in your string you can escape it by prefixing +it with a backslash ``\`` (which you can in turn escape by itself). In single quoted strings the single quote character +can be escaped by prefixing it with another single quote, basically doubling it. Backslashes in single quoted strings +do not need to be escaped. + +Quoted strings can also span across multiple lines, just indent the following lines. Note that you'll need to add a +completely empty line in order for force a line break, the data will not be actually wrapped across multiple lines +just because you spread its representation across multiple lines. + +.. list-table:: + + - * **Data type** + * **Examples** + - * int + * .. sourcecode:: yaml + + 23 + + 42 + + - * float + * .. sourcecode:: yaml + + 23.5 + + 100.0 + + - * boolean + * .. sourcecode:: yaml + + true + + false + + Yes + + No + + yes + + no + + - * string + * .. sourcecode:: yaml + + a string + + "some quoted string with a : colon and a { bracket and a quote \" and a backslash \\ - phew" + + 'some single quoted string with a single quote '' and a backslash \ - yay' + + "and a multiline string - just because we can we'll make it span + across not two but four YAML lines! + + Including this paragraph. But in fact it will only be two lines :)" + + "23" + + "42.3" + + "Yes" + + "No" + + "true" + + "false" + + yes and no + + true or false + +.. _sec-configuration-yaml-types-lists: + +Lists +..... + +Lists allow to "collect" a number of similar things into one data structure. They are created by prefixing one or more +consecutive lines with a ``-``: + +.. sourcecode:: yaml + + - item 1 + - 23.42 + - 57 + - true + +Take special care to have all of your list items at the same indentation level! + +.. _sec-configuration-yaml-types-dicts: + +Dictionaries +............ + +Dictionaries (aka associative arrays aka maps) allow organizing the data in key value pairs, with the key and the value +being separated through a colon ``:``: + +.. sourcecode:: yaml + + key: value + anotherkey: another value + +.. _sec-configuration-yaml-examples: + +Examples +-------- + +Based on the three types explained above, quite complex data structures are possible: + +.. sourcecode:: yaml + + general: + some_setting: some_value + a_list: + - item 1 + - 23.42 + - 57 + - true + some_flag: true + quoted_string: "This string is quoted because {we have this here} and also > this and : that" + specific: + setting1: value1 + setting2: value2 + subsetting21: value11 + subsetting22: + - subsubsetting221 + - subsubsetting222 + - subsubsetting223 + the_end: yes diff --git a/docs/images/configuration-custom_controls-example.png b/docs/images/configuration-custom_controls-example.png new file mode 100644 index 0000000000000000000000000000000000000000..eab2a58b2792bb1f99299578d7bb98d7675d36e0 GIT binary patch literal 22129 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 literal 0 HcmV?d00001 diff --git a/docs/index.rst b/docs/index.rst index 7acbf1f5..2803415b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,6 +16,7 @@ Contents .. toctree:: :maxdepth: 2 + configuration/index.rst api/index.rst events/index.rst plugins/index.rst diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 816813a5..786ce971 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -466,7 +466,15 @@ class Settings(object): def _migrate_config(self): dirty = False - for migrate in (self._migrate_event_config, self._migrate_reverse_proxy_config, self._migrate_printer_parameters, self._migrate_gcode_scripts): + + migrators = ( + self._migrate_event_config, + self._migrate_reverse_proxy_config, + self._migrate_printer_parameters, + self._migrate_gcode_scripts + ) + + for migrate in migrators: dirty = migrate() or dirty if dirty: self.save(force=True) diff --git a/src/octoprint/static/js/app/viewmodels/control.js b/src/octoprint/static/js/app/viewmodels/control.js index 45a779fa..4c045b2a 100644 --- a/src/octoprint/static/js/app/viewmodels/control.js +++ b/src/octoprint/static/js/app/viewmodels/control.js @@ -122,18 +122,20 @@ $(function() { }; self._processControl = function (control) { - if (_.startsWith(control.type, "parametric_")) { + if (control.type == "feedback_command" || control.type == "feedback") { + control.output = ko.observable(""); + self.feedbackControlLookup[control.name] = control.output; + } else if (control.type == "section" || control.type == "row" || control.type == "section_row") { + control.children = self._processControls(control.children); + } + + if (control.hasOwnProperty("input")) { for (var i = 0; i < control.input.length; i++) { control.input[i].value = ko.observable(control.input[i].default); if (!control.input[i].hasOwnProperty("slider")) { control.input[i].slider = false; } } - } else if (control.type == "feedback_command" || control.type == "feedback") { - control.output = ko.observable(""); - self.feedbackControlLookup[control.name] = control.output; - } else if (control.type == "section" || control.type == "row" || control.type == "section_row") { - control.children = self._processControls(control.children); } var js; @@ -275,25 +277,31 @@ $(function() { }) }; var data = undefined; - if (command.type == "command" || command.type == "parametric_command" || command.type == "feedback_command") { + if (command.hasOwnProperty("command")) { // single command data = {"command": command.command}; - } else if (command.type == "commands" || command.type == "parametric_commands") { + } else if (command.hasOwnProperty("commands")) { // multi command data = {"commands": command.commands}; - } else if (command.type == "script" || command.type == "parametric_script") { + } else if (command.hasOwnProperty("script")) { data = {"script": command.script}; if (command.hasOwnProperty("context")) { data["context"] = command.context; } + } else { + return; } - if (command.type == "parametric_command" || command.type == "parametric_commands" || command.type == "parametric_script") { + if (command.hasOwnProperty("input")) { // parametric command(s) data["parameters"] = {}; - for (var i = 0; i < command.input.length; i++) { - data["parameters"][command.input[i].parameter] = command.input[i].value(); - } + _.each(command.input, function(input) { + if (!input.hasOwnProperty("parameter") || !input.hasOwnProperty("value")) { + return; + } + + data["parameters"][input.parameter] = input.value(); + }); } if (command.confirm) {