More work on custom controls

Added a lot of documentation, more stream lining, should now work completely without having to define types but offer the same/more functionality than before. Backwards compatible too.
This commit is contained in:
Gina Häußge 2015-03-12 17:23:55 +01:00
parent 22c73d831a
commit 699f7b5278
23 changed files with 1288 additions and 301 deletions

View file

@ -7,4 +7,27 @@
.wy-table-responsive {
overflow: visible !important;
}
}
/* style headlink for code block captions like other headlinks */
.code-block-caption .headerlink {
display: none;
visibility: hidden;
font-size: 14px;
font-family: inherit;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
}
.code-block-caption:hover .headerlink {
display: inline-block;
}
.code-block-caption .headerlink:after {
visibility: visible;
content: "\f0c1";
font-family: FontAwesome;
display: inline-block;
}

View file

@ -17,6 +17,7 @@ import sys, os
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('../src/'))
sys.path.append(os.path.abspath('sphinxext'))
import octoprint._version
from datetime import date
@ -27,11 +28,11 @@ year_current = date.today().year
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.3'
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 = ['sphinx.ext.todo', 'sphinx.ext.autodoc', 'sphinxcontrib.httpdomain', 'sphinxcontrib.napoleon']
extensions = ['codeblockext', 'sphinx.ext.todo', 'sphinx.ext.autodoc', 'sphinxcontrib.httpdomain', 'sphinxcontrib.napoleon']
todo_include_todos = True
# Add any paths that contain templates here, relative to this directory.

View file

@ -0,0 +1,388 @@
.. _sec-configuration-config_yaml:
config.yaml
===========
If not specified via the command line, the main configuration file ``config.yaml`` for OctoPrint is expected in its
settings folder, which unless defined differently via the command line is located at ``~/.octoprint`` on Linux, at
``%APPDATA%/OctoPrint`` on Windows and at ``~/Library/Application Support/OctoPrint`` on MacOS. If the file is not there,
you can just create it - it will only get created by OctoPrint once you save settings that deviate from the default
settings.
Note that many of these settings are available from the "Settings" menu in OctoPrint itself.
Serial
------
Use the following settings to configure the serial connection to the printer:
.. code-block:: yaml
serial:
# Use the following option to define the default serial port, defaults to unset (= AUTO)
port: /dev/ttyACM0
# Use the following option to define the default baudrate, defaults to unset (= AUTO)
baudrate: 115200
# Whether to automatically connect to the printer on server startup (if available)
autoconnect: false
# Whether to log whole communication to serial.log (warning: might decrease performance)
log: false
# Timeouts used for the serial connection to the printer, you might want to adjust these if you are
# experiencing connection problems
timeout:
# Timeout for waiting for a response from the currently tested port during autodetect, in seconds.
# Defaults to 0.5 sec
detection: 0.5
# Timeout for waiting to establish a connection with the selected port, in seconds.
# Defaults to 2 sec
connection: 2
# Timeout during serial communication, in seconds.
# Defaults to 5 sec
communication: 5
# Use this to define additional patterns to consider for serial port listing. Must be a valid
# "glob" pattern (see http://docs.python.org/2/library/glob.html). Defaults to not set.
additionalPorts:
- /dev/myPrinterSymlink
Server
------
Use the following settings to configure the server:
.. code-block:: yaml
server:
# Use this option to define the host to which to bind the server, defaults to "0.0.0.0" (= all interfaces)
host: 0.0.0.0
# Use this option to define the port to which to bind the server, defaults to 5000
port: 5000
# Use this option to define an optional baseUrl (with a leading /, so absolute to your
# server's root) under which to run OctoPrint. This should only be needed if you want to run
# OctoPrint behind a reverse proxy under a different root endpoint than `/` and can't configure
# said reverse proxy to send `X-Script-Name` and `X-Scheme` HTTP headers with
# forwarded requests (see below). Defaults to an empty string and therefore the server root.
baseUrl: /octoprint
# Use this option to define an optional URL scheme under which to run OctoPrint.
# Should only be needed for use with reverse proxies, see above.
scheme: http
# will be automatically set to false once the first-run-wizard has been completed
firstRun: true
.. note::
If you want to run OctoPrint behind a reverse proxy such as HAProxy or Nginx and use a different base URL than the
server root ``/`` you have two options to achieve this. One approach is using the configuration settings ``baseUrl`` and
``scheme`` mentioned above in which OctoPrint will only work under the configured base URL.
The second and better approach is to make your proxy send a couple of custom headers with each forwarded requests:
* ``X-Script-Name``: should contain your custom baseUrl (absolute server path), e.g. ``/octoprint``
* ``X-Scheme``: should contain your custom URL scheme to use (if different from ``http``), e.g. ``https``
If you use these headers OctoPrint will work both via the reverse proxy as well as when called directly. Take a look
`into OctoPrint's wiki <https://github.com/foosel/OctoPrint/wiki/Reverse-proxy-configuration-examples>`_ for a couple
of examples on how to configure this.
Webcam
------
Use the following settings to configure webcam support:
.. code-block:: yaml
webcam:
# Use this option to enable display of a webcam stream in the UI, e.g. via MJPG-Streamer.
# Webcam support will be disabled if not set
stream: http://<stream host>:<stream port>/?action=stream
# Use this option to enable timelapse support via snapshot, e.g. via MJPG-Streamer.
# Timelapse support will be disabled if not set
snapshot: http://<stream host>:<stream port>/?action=snapshot
# Path to ffmpeg binary to use for creating timelapse recordings.
# Timelapse support will be disabled if not set
ffmpeg: /path/to/ffmpeg
# The bitrate to use for rendering the timelapse video. This gets directly passed to ffmpeg.
bitrate: 5000k
# Whether to include a "created with OctoPrint" watermark in the generated timelapse movies
watermark: true
# The default timelapse settings.
timelapse:
# The timelapse type. Can be either "off", "zchange" or "timed". Defaults to "off"
type: timed
# Additional options depending on the timelapse type. Currently only the "timed" timelapse takes
# the interval which to leave between images as option "interval", given in seconds. This example
# therefore configures a "Timed" timelapse with an interval of 2s. Defaults to empty.
options:
interval: 2
Feature
-------
Use the following settings to enable or disable OctoPrint features:
.. code-block:: yaml
feature:
# Whether to enable the gcode viewer in the UI or not
gCodeVisualizer: true
# Whether to enable the temperature graph in the UI or not
temperatureGraph: true
# Specifies whether OctoPrint should wait for the start response from the printer before trying to send commands
# during connect.
waitForStartOnConnect: false
# Specifies whether OctoPrint should send linenumber + checksum with every command. Needed for
# successful communication with Repetier firmware
alwaysSendChecksum: false
# Whether to ignore the first ok after a resend response. Needed for successful communication with
# Repetier firmware
swallowOkAfterResend: false
# Specifies whether support for SD printing and file management should be enabled
sdSupport: true
Folder
------
Use the following settings to set custom paths for folders used by OctoPrint:
.. code-block:: yaml
folder:
# Absolute path where to store gcode uploads. Defaults to the uploads folder in the OctoPrint settings folder
uploads: /path/to/upload/folder
# Absolute path where to store finished timelapse recordings. Defaults to the timelapse folder in the OctoPrint
# settings dir
timelapse: /path/to/timelapse/folder
# Absolute path where to store temporary timelapse files. Defaults to the timelapse/tmp folder in the OctoPrint
# settings dir
timelapse_tmp: /path/to/timelapse/tmp/folder
# Absolute path where to store log files. Defaults to the logs folder in the OctoPrint settings dir
logs: /path/to/logs/folder
# Absolute path to the virtual printer's simulated SD card. Only useful for development, just ignore
# it otherwise
virtualSd: /path/to/virtualSd/folder
# Absolute path to a folder being watched for new files which then get automatically
# added to OctoPrint (and deleted from that folder). Can e.g. be used to define a folder which
# can then be mounted from remote machines and used as local folder for quickly adding downloaded
# and/or sliced objects to print in the future.
watched: /path/to/watched/folder
Temperature
-----------
Use the following settings to configure temperature profiles which will be displayed in the temperature tab:
.. code-block:: yaml
temperature:
profiles:
- name: ABS
extruder: 210
bed: 100
- name: PLA
extruder: 180
bed: 60
Appearance
----------
Use the following settings to tweak OctoPrint's appearance a bit to better distinguish multiple instances/printers
appearance:
.. code-block:: yaml
appearance:
# Use this to give your printer a name. It will be displayed in the title bar (as "<Name> [OctoPrint]") and in the
# navigation bar (as "OctoPrint: <Name>")
name: My Printer Model
# Use this to color the navigation bar. Supported colors are red, orange, yellow, green, blue, violet and default.
color: blue
Controls
--------
Use the ``controls`` section to add :ref:`custom controls <sec-features-custom_controls>` to the "Controls" tab within
OctoPrint.
.. code-block:: yaml
controls:
- name: Fan
layout: horizontal
children:
- name: Enable Fan
type: parametric_command
command: M106 S%(speed)s
input:
- name: Speed (0-255)
parameter: speed
default: 255
- name: Disable Fan
type: command
command: M107
System
------
Use the following settings to add custom system commands to the "System" dropdown within OctoPrint's top bar.
Commands consist of a name, an action identifier, the commandline to execute and an optional confirmation message to
display before actually executing the command (should be set to False if a confirmation dialog is not desired).
The following example defines a command for shutting down the system under Linux. It assumes that the user under which
OctoPrint is running is allowed to do this without password entry:
.. code-block:: yaml
system:
actions:
- name: Shutdown
action: shutdown
command: sudo shutdown -h now
confirm: You are about to shutdown the system.
Access Control
--------------
Use the following settings to enable access control:
.. code-block:: yaml
accessControl:
# whether to enable access control or not. Defaults to true
enabled: true
# The user manager implementation to use for accessing user information. Currently only a filebased
# user manager is implemented which stores configured accounts in a YAML file (Default: users.yaml
# in the default configuration folder, see below)
userManager: octoprint.users.FilebasedUserManager
# The YAML user file to use. If left out defaults to users.yaml in the default configuration folder.
userFile: /path/to/users.yaml
# If set to true, will automatically log on clients originating from any of the networks defined in
# "localNetworks" as the user defined in "autologinAs". Defaults to false.
autologinLocal: true
# The name of the user to automatically log on clients originating from "localNetworks" as. Must
# be the name of one of your configured users.
autologinAs: someUser
# A list of networks or IPs for which an automatic logon as the user defined in "autologinAs" will
# take place. If available OctoPrint will evaluate the "X-Forwarded-For" HTTP header for determining
# the client's IP address (see https://code.google.com/p/haproxy-docs/wiki/forwardfor on how to
# configure the sending of this header in HAProxy). Defaults to 127.0.0.0/8 (so basically anything
# originating from localhost).
localNetworks:
- 127.0.0.0/8
- 192.168.1.0/24
Events
------
Use the following settings to add shell/gcode commands to be executed on certain :ref:`events <sec-events>`:
.. code-block:: yaml
events:
subscriptions:
# example event consumer that prints a message to the system log if the printer is disconnected
- event: Disconnected
command: "logger 'Printer got disconnected'"
type: system
# example event consumer that queries printer information from the firmware, prints a "Connected"
# message to the LCD and homes the print head upon established printer connection, disabled though
- event: Connected
command: M115,M117 printer connected!,G28
type: gcode
enabled: False
Terminal Filters
----------------
Use the following settings to define a set of terminal filters to display in the terminal tab for filtering certain
lines from the display terminal log.
Use `Javascript regular expressions <https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions>`_:
.. code-block:: yaml
# A list of filters to display in the terminal tab. Defaults to the filters shown below
terminalFilters:
- name: Suppress M105 requests/responses
regex: '(Send: M105)|(Recv: ok T:)'
- name: Suppress M27 requests/responses
regex: '(Send: M27)|(Recv: SD printing byte)'
API
---
Settings for the REST API:
.. code-block:: yaml
api:
# whether to enable the API
enabled: True
# current API key needed for accessing the API
apikey: ...
Development settings
--------------------
The following settings are only relevant to you if you want to do OctoPrint development:
.. code-block:: yaml
# Settings only relevant for development
devel:
# Settings for the virtual printer
virtualPrinter:
# Whether to enable the virtual printer and include it in the list of available serial connections.
# Defaults to false.
enabled: true
# Whether to send an additional "ok" after a resend request (like Repetier)
okAfterResend: false
# Whether to force checksums and line number in the communication (like Repetier), if set to true
# printer will only accept commands that come with linenumber and checksum and throw an error for
# lines that don't. Defaults to false
forceChecksum: false
# Whether to send "ok" responses with the line number that gets acknowledged by the "ok". Defaults
# to false.
okWithLinenumber: false

View file

@ -1,135 +0,0 @@
.. _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 <http://jinja.pocoo.org/>`_.
.. 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-yaml>`.
.. _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 <sec-configuration-custom_controls-types-section>`, :ref:`commands <sec-configuration-custom_controls-commands>`,
:ref:`parametric commands <sec-configuration-custom_controls-types-parametric_command>` and
:ref:`feedback commands <sec-configuration-custom_controls-types-feedback_command>`. Two attributes are common for all
of the types: ``name`` and ``type``.
.. _sec-configuration-custom_controls-types:
Types
-----
.. _sec-configuration-custom_controls-types-sections:
Sections
........
.. _sec-configuration-custom_controls-types-rows:
Rows
....
.. _sec-configuration-custom_controls-types-section_rows:
Section rows
............
.. _sec-configuration-custom_controls-types-commands:
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
.................

View file

@ -7,5 +7,6 @@ Configuration
.. toctree::
:maxdepth: 2
custom_controls.rst
yaml.rst
yaml.rst
config_yaml.rst
logging_yaml.rst

View file

@ -0,0 +1,100 @@
.. _sec-configuration-logging_yaml:
logging.yaml
============
The logging configuration file ``logging.yaml`` for OctoPrint is expected in its settings folder, which unless defined
differently on the command line is located at ``~/.octoprint`` on Linux, at ``%APPDATA%/OctoPrint`` on Windows and at
``~/Library/Application Support/OctoPrint`` on MacOS.
You can use it to change the log levels of the individual components within OctoPrint, which might be necessary to help
in debugging issues you are experiencing, or to change the configuration of the logging handlers themselves, e.g. in
order to change size after which to rollover the ``serial.log``.
Changing log levels
-------------------
If you need to change the default logging level within OctoPrint, create the file with a text editor of your choice
(it's usually not there). The general format is this::
logger:
<component>:
level: <loglevel>
with ``<component>`` being the internal OctoPrint component for which to change the loglevel, and ``<loglevel>`` being the
new log level to set. An example for increasing the log level of the events and the file management components to
``DEBUG`` (the highest amount of logging) would be this ``logging.yaml``:
.. code-block:: yaml
logger:
octoprint.events:
level: DEBUG
octoprint.filemanager:
level: DEBUG
A list of important components for which an increase in logging might be interesting follows:
* ``octoprint.events``: the event sub system
* ``octoprint.filemanager``: the file management layer
* ``octoprint.plugin``: the plugin sub system
* ``octoprint.plugins.<plugin>``: the plugin ``<plugin>``, e.g. ``octoprint.plugins.discovery`` to change the log level of
the `Discovery plugin <https://github.com/foosel/OctoPrint/wiki/Plugin:-Discovery>`_ or ``octoprint.plugins.cura``
to change the log level of the `Cura plugin <https://github.com/foosel/OctoPrint/wiki/Plugin:-Cura>`_.
* ``octoprint.slicing``: the slicing sub system
This list will be expanded when deemed necessary.
Changing logging handlers
-------------------------
You can also change the configuration of the logging handlers themselves, e.g. in order to make the ``serial.log`` larger
for debugging long running communications or to change the behaviour of the ``octoprint.log``.
You can find the default configurations of the ``file`` handler used for the ``octoprint.log``, the ``serialFile`` handler
used for the ``serial.log`` and the ``console`` handler used for the output to stdout in YAML format below:
.. code-block:: yaml
handlers:
# stdout
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
# octoprint.log
file:
class: logging.handlers.TimedRotatingFileHandler
level: DEBUG
formatter: simple
when: D
backupCount: 1
filename: /path/to/octoprints/logs/octoprint.log
# serial.log
serialFile:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: simple
maxBytes: 2097152 # 2 * 1024 * 1024 = 2 MB in bytes
filename: /path/to/octoprints/logs/serial.log
You can find more information on the used logging handlers in the
`Python documentation on logging handlers <https://docs.python.org/2/library/logging.handlers.html>`_.
Changing logging formatters
---------------------------
The logging formatters can be defined via ``logging.yaml`` as well. The ``simple`` formatter as referenced above is
expressed in YAML as follows:
.. code-block:: yaml
formatters:
simple:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
The possible keys for the logging format can be found in the
`Python documentation on LogRecord attributes <https://docs.python.org/2/library/logging.html#logrecord-attributes>`_.

View file

@ -17,11 +17,11 @@ 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
* Never use tabs outside of quoted strings, especially not for indentation. The tab character 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.
* YAML's comments start with a ``#`` and go until the end of the line.
.. _sec-configuration-yaml-types:
@ -29,7 +29,7 @@ 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).
(such as strings, integers, ...), lists and associated arrays (aka key-value-pairs, aka maps, aka dictionaries).
.. _sec-configuration-yaml-types-scalar:
@ -53,68 +53,80 @@ Quoted strings can also span across multiple lines, just indent the following li
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::
.. _sec-configuration-yaml-types-scalar-int:
- * **Data type**
* **Examples**
- * int
* .. sourcecode:: yaml
int
'''
23
.. code-block:: yaml
42
23
- * float
* .. sourcecode:: yaml
42
23.5
.. _sec-configuration-yaml-types-scalar-float:
100.0
float
'''''
- * boolean
* .. sourcecode:: yaml
.. code-block:: yaml
true
23.5
false
100.0
Yes
.. _sec-configuration-yaml-types-scalar-boolean:
No
boolean
'''''''
yes
.. code-block:: yaml
no
true
- * string
* .. sourcecode:: yaml
false
a string
Yes
"some quoted string with a : colon and a { bracket and a quote \" and a backslash \\ - phew"
No
'some single quoted string with a single quote '' and a backslash \ - yay'
yes
"and a multiline string - just because we can we'll make it span
across not two but four YAML lines!
no
Including this paragraph. But in fact it will only be two lines :)"
.. _sec-configuration-yaml-types-scalar-string:
"23"
string
''''''
"42.3"
.. code-block:: yaml
"Yes"
a string
"No"
"some quoted string with a : colon and a { bracket and a quote \" and a backslash \\ - phew"
"true"
'some single quoted string with a single quote '' and a backslash \ - yay'
"false"
"and a multiline string - just because we can we'll make it span
across not two but four YAML lines!
yes and no
Including this paragraph. But in fact it will only be two lines :)"
true or false
"23"
"42.3"
"Yes"
"No"
"true"
"false"
yes and no
true or false
.. _sec-configuration-yaml-types-lists:
@ -124,7 +136,7 @@ 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
.. code-block:: yaml
- item 1
- 23.42
@ -151,9 +163,50 @@ being separated through a colon ``:``:
Examples
--------
Based on the three types explained above, quite complex data structures are possible:
Based on the three types explained above, quite complex data structures are possible (whitespace made visible to
help track indentation):
.. sourcecode:: yaml
.. code-block-ext:: yaml
:whitespace:
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:
subsetting21: value11
subsetting22:
- subsubsetting221
- subsubsetting222
- subsubsetting223
the_end: yes
In this example we have a dictionary on the top most "layer" which has three keys, ``general``, ``specific`` and
``the_end``.
``general`` in turn is a dictionary with the keys ``some_setting`` (a string), ``a_list`` (a list with four items,
a string, a float, an int and a boolean), ``some_flag`` (a boolean) and ``quoted_string`` (a -- you guessed it -- string).
``specific`` is also a dictionary, with keys ``setting1`` (a string) and ``setting2``, a dictionary with two keys, one
a string and the other again a list.
Finally, ``the_end`` is just a boolean, since an unquoted ``yes`` evaluates as a boolean value as we saw in the
:ref:`section about boolean scalars above <sec-configuration-yaml-types-scalar-boolean>`.
Don't get confused by the list "dividing" one part of the dictionary under ``general`` from the other -- your mind is
just playing a trick on you due to the list's dashes ``-`` being on the same levels as the dictionary keys. You could
also just add two more spaces to your identation and write that part like this, which makes the structure a bit
clearer (whitespace again made visible to help track indentation):
.. code-block-ext:: yaml
:whitespace:
general:
some_setting: some_value
@ -163,13 +216,9 @@ Based on the three types explained above, quite complex data structures are poss
- 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
# ...
Just make sure you follow a consistent way of indenting your files -- YAML is not as strict as Python when it comes to
differing identation variants within the same file (as long as it's still valid), but consistency will help you as
a lot as a human. Ideally you'll use a text editor which highlights white space characters for you (most editors can
be configured this way), this will help tremendously when editing whitespace sensitive syntax such as YAML.

View file

@ -6,11 +6,14 @@ Events
.. contents::
With release of OctoPrint 1.1.0, the payload data has been harmonized, it is now a key-value-map for all events.
Additionally, the format of the placeholders in both system command and gcode command triggers has been changed to
accommodate for this new format. Last but not least, the way of specifying event hooks has changed, OctoPrint no longer
separates hooks into two sections (gcodeCommandTrigger and systemCommandTrigger) but instead event hooks are now typed
to indicate what to do with the command contained.
.. note::
With release of OctoPrint 1.1.0, the payload data has been harmonized, it is now a key-value-map for all events.
Additionally, the format of the placeholders in both system command and gcode command triggers has been changed to
accommodate for this new format. Last but not least, the way of specifying event hooks has changed, OctoPrint no longer
separates hooks into two sections (gcodeCommandTrigger and systemCommandTrigger) but instead event hooks are now typed
to indicate what to do with the command contained.
.. _sec-events-configuration:

View file

@ -0,0 +1,277 @@
.. _sec-features-custom_controls:
Custom Controls
===============
.. contents::
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 <http://jinja.pocoo.org/>`_.
Custom controls are configured within :ref:`config.yaml <sec-configuration-config_yaml>` in a ``controls`` section which
basically represents a hierarchical structure of all configured custom controls of various types.
.. note::
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-yaml>`.
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", a command with printer
feedback evaluation for the result of the M114 "Get Position" gcode inside a section named "Reporting" and finally
a GCODE script including user input.
.. code-block-ext:: yaml
controls:
- name: Fan
layout: horizontal
children:
- name: Enable Fan
command: M106 S%(speed)s
input:
- name: Speed (0-255)
parameter: speed
default: 255
slider:
min: 0
max: 255
- name: Disable Fan
command: M107
- name: Example for multiple commands
children:
- name: Move X (static)
confirm: You are about to move the X axis right by 10mm with 3000mm/s.
commands:
- G91
- G1 X10 F3000
- G90
- name: Move X (parametric)
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
children:
- name: Get Position
command: M114
regex: "X:([0-9.]+) Y:([0-9.]+) Z:([0-9.]+) E:([0-9.]+)"
template: "Position: X={0}, Y={1}, Z={2}, E={3}"
- name: Fun stuff
children:
- name: Dance
script: custom/dance.gco
input:
- name: Go arounds
parameter: repetitions
slider:
max: 10
min: 1
step: 1
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/features-custom_controls-example.png
:align: center
:alt: The rendered output created through the example configuration
As you can see you have two basic types of control definitions here: controls that actually do something (providing a
button that sends one or more commands to the printer when clicked, displaying output received from the printer) and
controls that just serve as *container* for other controls, the latter being identified by having a ``children``
attribute wrapping more controls.
.. _sec-features-custom_controls-types:
Types
-----
Let's take a closer look at the possible attributes that are available for both basic types.
.. _sec-features-custom_controls-types-containers:
Containers
..........
.. list-table::
:widths: 25 75
* - **Attribute**
- **Description**
* - ``children``
- A list of children controls or containers contained within this container
* - ``name``
- (Optional) A name to display above the container, basically a section header
* - ``layout``
- (Optional) The layout to use for laying out the contained children, either from top to bottom (``vertical``) or
from left to right (``horizontal``). Defaults to a ``vertical`` layout.
.. _sec-features-custom_controls-types-controls:
Controls
........
.. list-table::
:widths: 25 75
* - **Attribute**
- **Description**
* - ``name``
- The name of the control, will be displayed either on the button if it's a control sending a command or as a label
for controls which only display output.
* - ``command``
- (Optional) A single GCODE command to send to the printer. Will be rendered as a button which sends the command to
the printer upon click. The button text will be the value of the ``name`` attribute. Mutually exclusive with
``commands`` and ``script``. The rendered button be disabled if the printer is currently offline or printing or
alternatively if the requirements defined via the ``enabled`` attribute are not met.
* - ``commands``
- (Optional) A list of GCODE commands to send to the printer. Will be rendered as a button which sends the commands
to the printer upon click. The button text will be the value of the ``name`` attribute. Mutually exclusive with
``command`` and ``script``. The rendered button will be disabled if the printer is currently offline or printing
or alternatively if the requirements defined via the ``enabled`` attribute are not met.
* - ``script``
- (Optional) The name of a full blown :ref:`GCODE script <sec-features-gcode_scripts>` to send to the printer.
Will be rendered as a button which sends the script to the printer upon click. The button text will be the value
of the ``name`` attribute. Mutually exclusive with ``command`` and ``commands``. The rendered button will be
disabled if the printer is currently offline or printing or alternatively if the requirements defined via the
``enabled`` attribute are not met.
Values of input parameters will be available in the template context under the ``parameter`` variable (e.g.
an input parameter ``speed`` will be available in the script template as ``parameter.speed``). On top of that all
other variables defined in the :ref:`GCODE template context <sec-features-gcode_scripts-context>` will be available.
:ref:`See below for an example <sec-features-custom_controls-examples-gcode_script>`.
* - ``javascript``
- (Optional) A JavaScript snippet to be executed when the button rendered for ``command`` or ``commands`` is
clicked. This allows to override the direct sending of the command or commands to the printer with more
sophisticated behaviour. The JavaScript snippet is ``eval``'d and processed in a context where the control
it is part of is provided as local variable ``data`` and the ``ControlViewModel`` is available as ``self``.
* - ``enabled``
- (Optional) A JavaScript snippet returning either ``true`` or ``false`` determining whether the control
should be enabled or not. This allow to override the default logic for this (disabled if printer is offline
or currently printing). The JavaScript snippet is ``eval``'d and processed in a context where the control
it is part of is provided as local variable ``data`` and the ``ControlViewModel`` is available as ``self``.
* - ``input``
- (Optional) A list of definitions of input parameters for a ``command`` or ``commands``, to be rendered as
additional input fields. ``command``/``commands`` may contain placeholders to be replaced by the values obtained
from the user for the defined input fields:
.. code-block-ext:: yaml
name: Enable Fan
command: M106 S%(speed)s
input:
- name: Speed (0-255)
parameter: speed
default: 255
slider:
min: 0
max: 255
In OctoPrint's default UI input fields are always rendered left to right (inline).
* - ``input.name``
- Name to display for the input field.
* - ``input.parameter``
- Internal parameter name for the input field, used as a placeholder in ``command``/``commands``.
* - ``input.default``
- Default value for the input field.
* - ``input.slider``
- (Optional) If this attribute is included, instead of an input field a slider control will
be rendered. If you don't want to define any of ``min``, ``max`` or ``step``, write ``slider: {}`` to render
a slider based on default values.
* - ``input.slider.min``
- (Optional) Minimum value of the slider, defaults to 0.
* - ``input.slider.max``
- (Optional) Maximum value of the slider, defaults to 255.
* - ``input.slider.step``
- (Optional) Step size per slider "tick", defaults to 1.
* - ``regex``
- (Optional) A `regular expression <https://docs.python.org/2/library/re.html#regular-expression-syntax>`_ to
match against lines received from the printer to retrieve information from it (e.g. specific output). Together
with ``template`` this allows rendition of received data from the printer within the UI.
* - ``template``
- (Optional) A template to use for rendering the match of ``regex``. May contain placeholders in
`Python Format String Syntax <https://docs.python.org/2/library/string.html#format-string-syntax>`_ for either named
groups within the regex (e.g. ``Temperature: {temperature}`` for a regex ``T:\s*(?P<temperature>\d+(\.\d*)``)
or positional groups within the regex (e.g. ``Position: X={0}, Y={1}, Z={2}, E={3}`` for a regex
``X:([0-9.]+) Y:([0-9.]+) Z:([0-9.]+) E:([0-9.]+)``).
* - ``confirm``
- (Optional) A text to display to the user to confirm his button press. Can be used with sensitive custom controls
like changing EEPROM values in order to prevent accidental clicks. The text will be displayed in a confirmation
dialog like the following:
.. _fig-configuration-custom_controls-confirm:
.. figure:: ../images/features-custom_controls-confirm.png
:align: center
:alt: An example confirmation dialog
.. _sec-features-custom_controls-examples:
Examples
--------
.. _sec-features-custom_controls-examples-gcode_script:
Parameterized GCODE Script
..........................
.. code-block-ext:: yaml
:caption: Control definition in ~/.octoprint/config.yaml
:name: code-features-custom_controls-example-gcode_script-config_yaml
name: Dance
script: custom/dance.gco
input:
- default: 5
name: Go arounds
parameter: repetitions
slider:
max: 10
min: 1
step: 1
.. code-block-ext:: jinja
:caption: ~/.octoprint/scripts/gcode/custom/dance.gco
:name: code-features-custom_controls-example-gcode_script-dance_gco
{% set center_x = printer_profile.volume.width / 2 %}
{% set center_y = printer_profile.volume.depth / 2 %}
{% set speed_x = printer_profile.axes.x.speed %}
{% set speed_y = printer_profile.axes.y.speed %}
{% set speed_z = printer_profile.axes.z.speed %}
M117 run {{ script.name }}
G4 P500
G1 Z10
G1 X{{ center_x }} Y{{ center_y }} F{{ speed_x }}
M117 let's dance!
G91
G1 X-1 Y-1 F{{ speed_x }}
{% for n in range(parameters.repetitions) %}
M117 and {{ n + 1 }}
{% if n % 2 == 0 %}
G1 Z1 F{{ speed_z }}
G1 Z-2 F{{ speed_z }}
G1 Z1 F{{ speed_z }}
{% endif %}
G1 X2 F{{ speed_x }}
G1 Y2 F{{ speed_y }}
G1 X-2 F{{ speed_x }}
G1 Y-2 F{{ speed_y }}
{% endfor %}
G90
G1 X{{ center_x }} Y{{ center_y }} F{{ speed_x }}
G28 X0 Y0
Note the usage of the ``parameters.repetitions`` template variable in the GCODE script template, which will contain
the value selected by the user for the "Go arounds" slider.

11
docs/features/index.rst Normal file
View file

@ -0,0 +1,11 @@
.. _section-features:
********
Features
********
.. toctree::
:maxdepth: 2
custom_controls.rst
gcode_scripts.rst

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -6,16 +6,13 @@ Welcome to OctoPrint's documentation!
:alt: The OctoPrint Logo
:align: right
This is a work in progress. The goal is to document OctoPrint's REST API, event system, configuration etc in a way that
allows different documentation per development branch in Git, which so far did not scale well with the Github-Wiki-based
approach.
Contents
========
.. toctree::
:maxdepth: 2
features/index.rst
configuration/index.rst
api/index.rst
events/index.rst

View file

@ -0,0 +1,258 @@
# 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"
from sphinx.directives.code import CodeBlock
import sphinx.highlighting
from sphinx.highlighting import PygmentsBridge
from sphinx.ext import doctest
from sphinx.util.texescape import tex_hl_escape_map_new
from docutils.nodes import General, FixedTextElement, literal_block, container
from docutils.parsers.rst import directives
from six import text_type
from pygments import highlight
from pygments.filters import VisibleWhitespaceFilter, ErrorToken
from pygments.lexers.python import PythonConsoleLexer
from pygments.util import ClassNotFound
def _merge_dict(a, b):
"""
Little helper to merge two dicts a and b on the fly.
"""
result = dict(a)
result.update(b)
return result
class literal_block_ext(General, FixedTextElement):
"""
Custom node which is basically the same as a :class:`literal_block`, just with whitespace support and introduced
in order to be able to have a custom visitor.
"""
@classmethod
def from_literal_block(cls, block):
"""
Factory method constructing an instance exactly copying all attributes over from ``block`` and settings a
custom ``tagname``.
"""
new = literal_block_ext()
for a in ("attributes", "basic_attributes", "child_text_separator", "children", "document", "known_attributes",
"line", "list_attributes", "local_attributes", "parent", "rawsource", "source"):
setattr(new, a, getattr(block, a))
new.tagname = "literal_block_ext"
return new
class CodeBlockExt(CodeBlock):
"""
This is basically an extension of a regular :class:`CodeBlock` directive which just supports an additional option
``whitespace`` which if present will enable (together with everything else in here) to render whitespace in
code blocks.
"""
option_spec = _merge_dict(CodeBlock.option_spec, dict(whitespace=directives.flag))
def run(self):
# get result from parent implementation
code_block = CodeBlock.run(self)
def find_and_wrap_literal_block(node):
"""
Recursive method to turn all literal blocks located within a node into :class:`literal_block_ext`.
"""
if isinstance(node, container):
# container node => handle all children
children = []
for child in node.children:
children.append(find_and_wrap_literal_block(child))
node.children = children
return node
elif isinstance(node, literal_block):
# literal block => replace it
return self._wrap_literal_block(node)
else:
# no idea what that is => leave it alone
return node
# replace all created literal_blocks with literal_block_ext instances
return map(find_and_wrap_literal_block, code_block)
def _wrap_literal_block(self, node):
literal = literal_block_ext.from_literal_block(node)
literal["whitespace"] = "whitespace" in self.options
return literal
class PygmentsBridgeExt(object):
"""
Wrapper for :class:`PygmentsBridge`, delegates everything to the wrapped ``bridge`` but :method:`highlight_block`,
which calls the parent implementation for lexer selection, then
"""
def __init__(self, bridge, whitespace):
self._bridge = bridge
self._whitespace = whitespace
def __getattr__(self, item):
return getattr(self._bridge, item)
def highlight_block(self, source, lang, opts=None, warn=None, force=False, **kwargs):
if not self._whitespace:
return self._bridge.highlight_block(source, lang, opts=opts, warn=warn, force=force, **kwargs)
# We are still here => we need to basically do everything the parent implementation does (and does so in a very
# unextensible way...), but inject the whitespace filter into the used lexer just before the highlighting run
# and remove it afterwards so the lexer can be safely reused.
#
# For this we define a context manager that will allow us to wrap a lexer and modify its filters on the fly to
# include the whitespace filter.
class whitespace(object):
def __init__(self, lexer):
self._lexer = lexer
self._orig_filters = lexer.filters
self._orig_tabsize = lexer.tabsize
def __enter__(self):
new_filters = list(self._orig_filters)
new_filters.append(VisibleWhitespaceFilter(spaces=True, tabs=True, tabsize=self._lexer.tabsize))
self._lexer.filters = new_filters
self._lexer.tabsize = 0
return self._lexer
def __exit__(self, type, value, traceback):
self._lexer.filters = self._orig_filters
self._lexer.tabsize = self._orig_tabsize
# Then a ton of copy-pasted code follows. Sadly, we need to do this since we have no way to inject ourselves
# into the highlighting call otherwise - lexer selection and actual call are tightly coupled in the original
# "highlight_block" method, with no means for external code to inject different functionality.
#
# Unless otherwise marked ("MODIFIED"), any code in this method after this line is copied verbatim from the
# implementation of sphinx.highlighting.PygmentsBridge, released under the Simplified BSD License, the copyright
# lies with the respective authors.
if not isinstance(source, text_type):
source = source.decode()
# find out which lexer to use
if lang in ('py', 'python'):
if source.startswith('>>>'):
# interactive session
lexer = sphinx.highlighting.lexers['pycon']
elif not force:
# maybe Python -- try parsing it
if self.try_parse(source):
lexer = sphinx.highlighting.lexers['python']
else:
lexer = sphinx.highlighting.lexers['none']
else:
lexer = sphinx.highlighting.lexers['python']
elif lang in ('python3', 'py3') and source.startswith('>>>'):
# for py3, recognize interactive sessions, but do not try parsing...
lexer = sphinx.highlighting.lexers['pycon3']
elif lang == 'guess':
try:
lexer = sphinx.highlighting.guess_lexer(source)
except Exception:
lexer = sphinx.highlighting.lexers['none']
else:
if lang in sphinx.highlighting.lexers:
lexer = sphinx.highlighting.lexers[lang]
else:
try:
lexer = sphinx.highlighting.lexers[lang] = sphinx.highlighting.get_lexer_by_name(lang, **opts or {})
except ClassNotFound:
if warn:
warn('Pygments lexer name %r is not known' % lang)
lexer = sphinx.highlighting.lexers['none']
else:
raise
else:
lexer.add_filter('raiseonerror')
if not isinstance(source, text_type):
source = source.decode()
# trim doctest options if wanted
if isinstance(lexer, PythonConsoleLexer) and self._bridge.trim_doctest_flags:
source = doctest.blankline_re.sub('', source)
source = doctest.doctestopt_re.sub('', source)
# highlight via Pygments
formatter = self._bridge.get_formatter(**kwargs)
try:
# MODIFIED: replaced by whitespace wrapped call
with whitespace(lexer) as l:
hlsource = highlight(source, l, formatter)
# /MODIFIED
except ErrorToken:
# this is most probably not the selected language,
# so let it pass unhighlighted
# MODIFIED: replaced by whitespace wrapped call
with whitespace(sphinx.highlighting.lexers["none"]) as l:
hlsource = highlight(source, l, formatter)
# /MODIFIED
if self._bridge.dest == 'html':
return hlsource
else:
if not isinstance(hlsource, text_type): # Py2 / Pygments < 1.6
hlsource = hlsource.decode()
return hlsource.translate(tex_hl_escape_map_new)
class whitespace_highlighter(object):
"""
Context manager for adapting the used highlighter on a translator for a given node's whitespace properties.
"""
def __init__(self, translator, node):
self.translator = translator
self.node = node
self._orig_highlighter = self.translator.highlighter
def __enter__(self):
whitespace = self.node["whitespace"] if "whitespace" in self.node else False
if whitespace:
self.translator.highlighter = PygmentsBridgeExt(self._orig_highlighter, whitespace)
return self.translator
def __exit__(self, exc_type, exc_val, exc_tb):
self.translator.highlighter = self._orig_highlighter
def visit_literal_block_ext(translator, node):
"""
When our custom code block is visited, we temporarily exchange the highlighter used in the translator, call the
visitor for regular literal blocks, then switch back again.
"""
with whitespace_highlighter(translator, node):
translator.visit_literal_block(node)
def depart_literal_block_ext(translator, node):
"""
Just call the depart function for regular literal blocks.
"""
with whitespace_highlighter(translator, node):
translator.depart_literal_block(node)
def setup(app):
# custom directive
app.add_directive("code-block-ext", CodeBlockExt)
# custom node type
handler = (visit_literal_block_ext, depart_literal_block_ext)
app.add_node(literal_block_ext, html=handler, latex=handler, text=handler)
return dict(version="0.1")

View file

@ -1,15 +0,0 @@
flask==0.9
werkzeug==0.8.3
tornado==3.0.2
sockjs-tornado>=1.0.0
PyYAML==3.10
Flask-Login==0.2.2
Flask-Principal==0.3.5
netaddr>=0.7.10
mock>=1.0.1
nose>=1.3.0
watchdog
sarge
sphinxcontrib-httpdomain
sphinx_rtd_theme

View file

@ -1,12 +0,0 @@
# Testing dependencies
mock>=1.0.1
nose>=1.3.0
ddt
# Documentation dependencies
sphinxcontrib-httpdomain
sphinxcontrib-napoleon
sphinx_rtd_theme
# Translation dependencies
po2json

View file

@ -1,16 +1,11 @@
flask==0.9
werkzeug==0.8.3
tornado==4.0.1
sockjs-tornado>=1.0.0
PyYAML==3.10
Flask-Login==0.2.2
Flask-Principal==0.3.5
Flask-Babel==0.9
pyserial
netaddr
watchdog
sarge>=0.1.4
netifaces
pylru
rsa
pkginfo
###
# This file is only here to make sure that something like
#
# pip install -e .[develop]
#
# works as expected. Requirements can be found in setup.py in the
# variables INSTALL_REQUIRES and EXTRA_REQUIRES.
###
--process-dependency-links
.

View file

@ -1,7 +1,64 @@
# coding=utf-8
#!/usr/bin/env python
# coding=utf-8
from setuptools import setup, find_packages, Command
import os
import shutil
import glob
import versioneer
#-----------------------------------------------------------------------------------------------------------------------
# Requirements for out application
INSTALL_REQUIRES = [
"flask==0.9",
"werkzeug==0.8.3",
"tornado==4.0.1",
"sockjs-tornado>=1.0.0",
"PyYAML==3.10",
"Flask-Login==0.2.2",
"Flask-Principal==0.3.5",
"Flask-Babel==0.9",
"pyserial",
"netaddr",
"watchdog",
"sarge>=0.1.4",
"netifaces",
"pylru",
"rsa",
"pkginfo"
]
# Requirements for developing etc
EXTRA_REQUIRES = dict(
develop=[
# Testing dependencies
"mock>=1.0.1",
"nose>=1.3.0",
"ddt",
# Documentation dependencies
"sphinx>=1.3",
"sphinxcontrib-httpdomain",
"sphinx_rtd_theme",
# Translation dependencies
"po2json"
]
)
# Dependency links for any of the aforementioned dependencies
DEPENDENCY_LINKS = []
# I18N setup
I18N_MAPPING_FILE = "babel.cfg"
I18N_DOMAIN = "messages"
I18N_INPUT_DIRS = "."
I18N_OUTPUT_DIR_PY = os.path.join("src", "octoprint", "translations")
I18N_OUTPUT_DIR_JS = os.path.join("src", "octoprint", "static", "js", "i18n")
I18N_POT_FILE = os.path.join(I18N_OUTPUT_DIR_PY, "messages.pot")
# Versioneer configuration
versioneer.VCS = 'git'
versioneer.versionfile_source = 'src/octoprint/_version.py'
versioneer.versionfile_build = 'octoprint/_version.py'
@ -9,17 +66,8 @@ versioneer.tag_prefix = ''
versioneer.parentdir_prefix = ''
versioneer.lookupfile = '.versioneer-lookup'
from setuptools import setup, find_packages, Command
import os
import shutil
import glob
I18N_MAPPING_FILE = "babel.cfg"
I18N_DOMAIN = "messages"
I18N_INPUT_DIRS = "."
I18N_OUTPUT_DIR_PY = os.path.join("src", "octoprint", "translations")
I18N_OUTPUT_DIR_JS = os.path.join("src", "octoprint", "static", "js", "i18n")
I18N_POT_FILE = os.path.join(I18N_OUTPUT_DIR_PY, "messages.pot")
#-----------------------------------------------------------------------------------------------------------------------
# Anything below here is just command setup and general setup configuration
def package_data_dirs(source, sub_folders):
dirs = []
@ -250,10 +298,6 @@ def get_cmdclass():
return cmdclass
def requirements(filename):
return filter(lambda line: line and not line.startswith("#"), map(lambda line: line.strip(), open(filename).read().split("\n")))
def params():
name = "OctoPrint"
version = versioneer.get_version()
@ -291,14 +335,13 @@ def params():
include_package_data = True
zip_safe = False
install_requires = requirements("requirements.txt")
extras_require = dict(
develop=requirements("requirements-dev.txt")
)
install_requires = INSTALL_REQUIRES
extras_require = EXTRA_REQUIRES
dependency_links = DEPENDENCY_LINKS
if os.environ.get('READTHEDOCS', None) == 'True':
# we can't tell read the docs to please perform a pip install -e .[develop], so we help
# it a bit here by explicitely adding the development dependencies, which include our
# it a bit here by explicitly adding the development dependencies, which include our
# documentation dependencies
install_requires = install_requires + extras_require['develop']
@ -308,10 +351,6 @@ def params():
]
}
#scripts = {
# "scripts/octoprint.init": "/etc/init.d/octoprint"
#}
return locals()
setup(**params())

File diff suppressed because one or more lines are too long

View file

@ -191,10 +191,27 @@ $(function() {
};
self.clickCustom = function (data) {
var callback;
if (data.hasOwnProperty("javascript")) {
data.javascript(data);
callback = data.javascript;
} else {
self.sendCustomCommand(data);
callback = self.sendCustomCommand;
}
if (data.confirm) {
var confirmationDialog = $("#confirmation_dialog");
var confirmationDialogAck = $(".confirmation_dialog_acknowledge", confirmationDialog);
$(".confirmation_dialog_message", confirmationDialog).text(data.confirm);
confirmationDialogAck.unbind("click");
confirmationDialogAck.bind("click", function (e) {
e.preventDefault();
$("#confirmation_dialog").modal("hide");
callback(data);
});
confirmationDialog.modal("show");
} else {
callback(data);
}
};
@ -285,15 +302,6 @@ $(function() {
if (!command)
return;
var callback = function () {
$.ajax({
url: API_BASEURL + "printer/command",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify(data)
})
};
var data = undefined;
if (command.hasOwnProperty("command")) {
// single command
@ -322,22 +330,13 @@ $(function() {
});
}
if (command.confirm) {
var confirmationDialog = $("#confirmation_dialog");
var confirmationDialogAck = $(".confirmation_dialog_acknowledge", confirmationDialog);
$(".confirmation_dialog_message", confirmationDialog).text(command.confirm);
confirmationDialogAck.unbind("click");
confirmationDialogAck.bind("click", function (e) {
e.preventDefault();
$("#confirmation_dialog").modal("hide");
callback();
});
confirmationDialog.modal("show");
} else {
callback();
}
$.ajax({
url: API_BASEURL + "printer/command",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify(data)
})
};
self.displayMode = function (customControl) {

View file

@ -595,7 +595,11 @@ ul.dropdown-menu li a {
margin-top: -3px;
}
.custom_parametric_command {
.custom_section_horizontal .custom_control {
display: inline-block;
}
.custom_control {
.slider {
margin-left: 10px;
margin-right: 10px;

View file

@ -111,11 +111,15 @@
<!-- /ko -->
<!-- ko if: layout == 'vertical' -->
<div class="custom_section" data-bind="template: { name: $root.displayMode, foreach: children }"></div>
<div class="custom_section custom_section_vertical" data-bind="template: { name: $root.displayMode, foreach: children }"></div>
<!-- /ko -->
<!-- ko if: layout == 'horizontal' -->
<div class="row-fluid custom_row">
<div class="custom_section custom_section_horizontal" data-bind="template: { name: $root.displayMode, foreach: children }"></div>
<!-- /ko -->
<!-- ko if: layout == 'horizontal_grid' -->
<div class="row-fluid custom_section custom_section_horizontal_grid">
<!-- ko foreach: children -->
<div data-bind="template: { name: $root.displayMode }, css: $root.rowCss($data)"></div>
<!-- /ko -->
@ -123,9 +127,9 @@
<!-- /ko -->
</script>
<script type="text/html" id="customControls_controlTemplate">
<form class="form-inline">
<form class="form-inline custom_control">
<!-- ko template: { name: 'customControls_controlTemplate_input', data: $data, if: $data.hasOwnProperty('input') } --><!-- /ko -->
<!-- ko template: { name: 'customControls_controlTemplate_command', data: $data, if: $data.hasOwnProperty('command') || $data.hasOwnProperty('commands') } --><!-- /ko -->
<!-- ko template: { name: 'customControls_controlTemplate_command', data: $data, if: $data.hasOwnProperty('command') || $data.hasOwnProperty('commands') || $data.hasOwnProperty('script') } --><!-- /ko -->
<!-- ko template: { name: 'customControls_controlTemplate_output', data: $data, if: $data.hasOwnProperty('output') } --><!-- /ko -->
</form>
</script>