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:
parent
22c73d831a
commit
699f7b5278
23 changed files with 1288 additions and 301 deletions
25
docs/_static/theme_overrides.css
vendored
25
docs/_static/theme_overrides.css
vendored
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
388
docs/configuration/config_yaml.rst
Normal file
388
docs/configuration/config_yaml.rst
Normal 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
|
||||
|
||||
|
|
@ -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
|
||||
.................
|
||||
|
||||
|
|
@ -7,5 +7,6 @@ Configuration
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
custom_controls.rst
|
||||
yaml.rst
|
||||
yaml.rst
|
||||
config_yaml.rst
|
||||
logging_yaml.rst
|
||||
|
|
|
|||
100
docs/configuration/logging_yaml.rst
Normal file
100
docs/configuration/logging_yaml.rst
Normal 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>`_.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
277
docs/features/custom_controls.rst
Normal file
277
docs/features/custom_controls.rst
Normal 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
11
docs/features/index.rst
Normal 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 |
BIN
docs/images/features-custom_controls-confirm.png
Normal file
BIN
docs/images/features-custom_controls-confirm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
docs/images/features-custom_controls-example.png
Normal file
BIN
docs/images/features-custom_controls-example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
|
|
@ -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
|
||||
|
|
|
|||
258
docs/sphinxext/codeblockext.py
Normal file
258
docs/sphinxext/codeblockext.py
Normal 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")
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
.
|
||||
|
|
|
|||
89
setup.py
89
setup.py
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue