docs: remove references to plugins and create components.md

Replace various notes with admonitions.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Arksine 2021-03-18 17:16:36 -04:00
parent 1dc920019c
commit 8acd0f2728
7 changed files with 397 additions and 70 deletions

304
docs/components.md Normal file
View File

@ -0,0 +1,304 @@
## Components
Components in Moonraker are used to extend Moonraker's functionality,
similar to "extras" in Klipper. Moonraker divides components into
two categories, "core" components and "optional" components. A core
component gets its configuration from the `[server]` section and is
loaded when Moonraker starts. For example, the `file_manager` is a
core component. If a core component fails to load Moonraker will
exit with an error.
Optional components must be configured in `moonraker.conf`. If they
have no specific configuration, a bare section, such as `[octoprint_compat]`
must be present in `moonraker.conf`. Unlike with core components,
Moonraker will still start if an optional component fails to load.
Its failed status will be available for clients to query and present
to the user.
### Basic Example
Components exist in the `components` directory. The below example
shows how an `example.py` component might look:
```python
# Example Component
#
# Copyright (C) 2021 Eric Callahan <arksine.code@gmail.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
class Example:
def __init__(self, config):
self.server = config.get_server()
self.name = config.get_name()
# Raises an error if "example_int_option" is not configured in
# the [example] section
self.example_int_opt = config.getint("example_int_option")
# Returns a NoneType if "example_float_option is not configured
# in the config
self.example_float_opt = config.getfloat("example_float_option", None)
self.server.register_endpoint("/server/example", ['GET'],
self._handle_example request)
async def request_some_klippy_state(self):
klippy_apis = self.server.lookup_component('klippy_apis')
return await klippy_apis.query_objects({'print_stats': None})
async def _handle_example_request(self, web_request):
web_request.get_int("required_reqest_param")
web_request.get_float("optional_request_param", None)
state = await self.request_some_klippy_state()
return {"example_return_value": state}
def load_component(config):
return Example(config)
```
If you have created a "Klippy extras" module then the above should look
look familiar. Moonraker attempts to use similar method for adding
extensions, making easier Klipper contributors to add new functionality
to Moonraker. Be aware that there is no "Reactor" object in Moonraker,
it uses `asyncio` for coroutines. Like Klippy, you should not write
code that blocks the main thread.
### The ConfigWrapper Object
As shown above, each component is passed a config object. This object
will be a `ConfigWrapper` type, which is an object that wraps a
configuration section to simply access to the native `ConfigParser`.
A `ConfigWrapper` should never be directly instantiated.
#### *ConfigWrapper.get_server()*
Returns the primary [server](#the-server-object) instance.
#### *ConfigWrapper.get_name()*
Returns the configuration section name associated with this `ConfigWrapper`.
#### *ConfigWrapper.get(option_name, default=Sentinel)*
Returns the value of the option`option_name` as a string. If
the option does not exist, returns `default`. If `default` is
not provided raises a `ConfigError`.
#### *ConfigWrapper.getint(option_name, default=Sentinel)*
Returns the value of the option`option_name` as an integer. If
the option does not exist, returns `default`. If `default` is
not provided raises a `ConfigError`.
#### *ConfigWrapper.getfloat(option_name, default=Sentinel)*
Returns the value of the option`option_name` as a float. If
the option does not exist, returns `default`. If `default` is
not provided raises a `ConfigError`.
#### *ConfigWrapper.getboolean(option_name, default=Sentinel)*
Returns the value of the option`option_name` as a boolean. If
the option does not exist, returns `default`. If `default` is
not provided raises a `ConfigError`.
#### *ConfigWrapper.has_section(section_name)*
Returns True if a section matching `section_name` is in the configuration,
otherwise False.
Note that a ConfigWrapper object also implements `__contains__`,
which is an alias for `has_section`, ie: `section_name in config_instance`
#### *ConfigWrapper.getsection(section_name)*
Returns a Config object for the section matching `section_name`. If the
section does not exist in the configuration raises a `ConfigError`.
Note that a ConfigWrapper object also implements `__getitem__`,
which is an alias for `get_section`, ie: `config_instance[section_name]`
#### *ConfigWrapper.get_options()*
Returns a dict mapping options to values for all options in the Config
object.
#### *ConfigWrapper.get_prefix_sections(prefix)*
Returns a list section names in the configuration that start with `prefix`.
These strings can be used to retreve ConfigWrappers via
[get_section()](#configwrappergetsectionsection_name).
### The Server Object
The server instance represents the central management object in Moonraker.
It can be used to register endpoints, register notifications, look up other
components, send events, and more.
#### *Server.lookup_component(component_name, default=Sentinel)*
Attempts to look up a loaded component, returning the result. If
the component has not been loaded, `default` will be returned.
If `default` is not provided a `ServerError` will be raised.
#### *Server.load_component(config, component_name, default=Sentinel)*
Attempts to load an uninitialized component and returns the result. It is
only valid to call this within a a component's `__init__()` method, and
should only be necessary if one optional component relies on another. Core components will always be loaded before optional components, thus an optional
component may always call
[lookup_component()](#serverlookup_componentcomponent_name-defaultsentinel)
when it needs a reference to core component.
If the component fails to load `default` will be returned. If `default`
is not provided a `ServerError` will be raised.
#### *Server.register_endpoint(uri, request_methods, callback, protocol=["http", "websocket"], wrap_result=True)*
Registers the supplied `uri` with the server.
The `request_methods` argument should be a list of strings containing any
combination of `GET`, `POST`, and `DELETE`.
The `callback` is executed when a request matching the `uri` and a
`request_method` is received. The callback function will be passed a
`WebRequest` object with details about the request. This function
should be able of handling each registered `request_method`. The
provided callback must be a coroutine.
The `protocol` is a list containing any combination of `http` and `websocket`.
If `websocket` is selected associated JSON-RPC methods will be generated based
on what is supplied by the `uri` and `request_methods` argument. A unique
JSON_RPC method is generated for each request method. For example:
```python
self.server.register_endpoint("/server/example", ["POST"], self._handle_request)
```
would register a JSON-RPC method like:
```
server.example
```
However, if multiple requests methods are supplied, the generated JSON-RPC
methods will differ:
```python
self.server.register_endpoint("/server/example", ["GET", "POST", "DELETE"],
self._handle_request)
```
would register:
```
server.get_example
server.post_example
server.delete_example
```
The `wrap_result` argument applies only to the `http` protocol. In Moonraker
all http requests return a result with a JSON body. By default, the value returned
by a `callback` is wrapped in a dict:
```python
{"result": return_value}
```
It is only necessary to set this to false if you need to return a body that
does not match this result. For example, the `[octoprint_compat]` component
uses this functionality to return results in a format that match what
Octoprint itself would return.
#### *Server.register_event_handler(event, callback)*
Registers the provided `callback` method to be executed when the
provided `event` is sent. The callback may be a coroutine, however it
is not required.
#### *Server.send_event(event, \*args)*
Emits the event named `event`, calling all callbacks registered to the
event. All positional arguments in `*args` will be passed to each
callback. Event names should be in the form of
`"module_name:event_description"`.
#### *Server.register_notification(event_name, notify_name=None)*
Registers a websocket notification to be pushed when `event_name`
is emitted. By default JSON-RPC notifcation sent will be in the form of
`notify_{event_description}`. For example, when the server sends the
`server:klippy_connected` event, the JSON_RPC notification will be
`notify_klippy_connected`.
If a `notify_name` is provided it will override the `{event_description}`
extracted from the `event_name`. For example, if the `notify_name="kconnect`
were specfied when registering the `server:klippy_connected` event, the
websocket would emit a `notify_kconnect` notification.
#### *Server.get_host_info()*
Returns a tuple of the current host name of the PC and the port Moonraker
is serving on.
#### *Server.get_klippy_info()*
Returns a dict containing the values from the most recent `info` request to
Klippy. If Klippy has never connected this will be an empty dict.
### The WebRequest Object
All callbacks registered with the
[register_endpoint()](#serverregister_endpointuri-request_methods-callback-protocolhttp-websocket-wrap_resulttrue)
method are passed a WebRequest object when they are executed. This object
contains information about the request including its endpoint name and arguments
parsed from the request.
#### *WebRequest.get_endpoint()*
Returns the URI registered with this request, ie: `/server/example`.
#### *WebRequest.get_action()*
Returns the request action, which is synonomous with its HTTP request
method. Will be either `GET`, `POST`, or `DELETE`. This is useful
if your endpoint was registered with multiple request methods and
needs to handle each differently.
#### *WebRequest.get_connection()*
Returns the associated Websocket connection ID. This will be `None`
for HTTP requests when no associated websocket is connected to
the client.
#### *WebRequest.get_args()*
Returns a reference to the entire argument dictionary. Useful if
one request handler needs to preprocess the arguments before
passing the WebRequest on to another request handler.
#### *WebRequest.get(key, default=Sentinel)*
Returns the request argument at the provided `key`. If the key is not
present `default` will be returned. If `default` is not provided a
`SeverError` will be raised.
#### *WebRequest.get_str(key, default=Sentinel)*
Retrieves the request argument at the provided `key` and converts it
to a string, returning the result. If the key is not present the `default`
value will be returned. If `default` is not provided or if the attempt at
type conversion fails a `SeverError` will be raised.
#### *WebRequest.get_int(key, default=Sentinel)*
Retrieves the request argument at the provided `key` and converts it
to an integer, returning the result. If the key is not present the `default`
value will be returned. If `default` is not provided or if the attempt at
type conversion fails a `SeverError` will be raised.
#### *WebRequest.get_float(key, default=Sentinel)*
Retrieves the request argument at the provided `key` and converts it
to a float, returning the result. If the key is not present the `default`
value will be returned. If `default` is not provided or if the attempt at
type conversion fails a `SeverError` will be raised.
#### *WebRequest.get_boolean(key, default=Sentinel)*
Retrieves the request argument at the provided `key` and converts it
to a boolean, returning the result. If the key is not present the `default`
value will be returned. If `default` is not provided or if the attempt at
type conversion fails a `SeverError` will be raised.

View File

@ -7,7 +7,9 @@ to install and configure Moonraker.
Client developers may refer to the [Client API](web_api.md) Client developers may refer to the [Client API](web_api.md)
documentation. documentation.
Internal API documentation for back-end contributors is forthcoming. Backend developers should refer to the
In the meantime developers should refer to the
[contibuting](contributing.md) section for basic contribution [contibuting](contributing.md) section for basic contribution
guidelines prior to creating a pull request. guidelines prior to creating a pull request. The
[components](components.md) document provides a brief overview
of how to create a component and interact with Moonraker's
primary internal APIs.

View File

@ -64,9 +64,10 @@ KLIPPY_EXEC=/home/pi/klippy-env/bin/python
KLIPPY_ARGS="/home/pi/klipper/klippy/klippy.py /home/pi/printer.cfg -l /tmp/klippy.log -a /tmp/klippy_uds" KLIPPY_ARGS="/home/pi/klipper/klippy/klippy.py /home/pi/printer.cfg -l /tmp/klippy.log -a /tmp/klippy_uds"
``` ```
**Note: Your installation of Klipper may use systemd instead of !!! note
Your installation of Klipper may use systemd instead of
the default LSB script. In this case, you need to modify the the default LSB script. In this case, you need to modify the
klipper.service file.** klipper.service file.
You may also want to take this opportunity to change the location of You may also want to take this opportunity to change the location of
printer.cfg to match Moonraker's `config_path` option (see the printer.cfg to match Moonraker's `config_path` option (see the

View File

@ -1,3 +0,0 @@
## Plugins
Documentation Forthcoming

View File

@ -61,7 +61,8 @@ The `gcode_move` object reports the current gcode state:
the most recent "G1" or "G0" processed assuming the machine is the most recent "G1" or "G0" processed assuming the machine is
using absolute coordinates. using absolute coordinates.
Note: The printer's actual movement will lag behind the reported positional !!! Note
The printer's actual movement will lag behind the reported positional
coordinates due to lookahead. coordinates due to lookahead.
## toolhead ## toolhead
@ -98,7 +99,8 @@ The `toolhead` object reports state of the current tool:
- `square_corner_velocity`: The currently set square corner velocity. This - `square_corner_velocity`: The currently set square corner velocity. This
is the maximum velocity at which the tool may travel a 90 degree corner. is the maximum velocity at which the tool may travel a 90 degree corner.
Note: `max_velocity`, `max_accel`, `max_accel_to_decel`, and !!! tip
`max_velocity`, `max_accel`, `max_accel_to_decel`, and
`square_corner_velocity` can be changed by the `SET_VELOCITY_LIMIT` gcode. `square_corner_velocity` can be changed by the `SET_VELOCITY_LIMIT` gcode.
`M204` can also change `max_accel`. `M204` can also change `max_accel`.
@ -128,7 +130,8 @@ The `configfile` object reports printer configuration state:
## extruder ## extruder
*Enabled when `[extruder]` is included in printer.cfg* *Enabled when `[extruder]` is included in printer.cfg*
Note: If multiple extruders are configured, extruder 0 is available as !!! note
If multiple extruders are configured, extruder 0 is available as
`extruder`, extruder 1 as `extruder1` and so on. `extruder`, extruder 1 as `extruder1` and so on.
```json ```json
{ {
@ -219,9 +222,10 @@ The `virtual_sdcard` object reports the state of the virtual sdcard:
- `file_position`: The current file position in bytes. This will always - `file_position`: The current file position in bytes. This will always
be an integer value be an integer value
**Note: `progress` and `file_position` will persist after a print has !!! Note
`progress` and `file_position` will persist after a print has
paused, completed, or errored. They are cleared when the user issues paused, completed, or errored. They are cleared when the user issues
a SDCARD_RESET_FILE gcode or when a new print has started.** a SDCARD_RESET_FILE gcode or when a new print has started.
## print_stats ## print_stats
*Enabled when `[virtual_sdcard]` is included in printer.cfg* *Enabled when `[virtual_sdcard]` is included in printer.cfg*
@ -252,8 +256,9 @@ The `print_stats` object reports `virtual_sdcard` print state:
- `message`: If an error is detected, this field contains the error - `message`: If an error is detected, this field contains the error
message generated. Otherwise it will be a null string. message generated. Otherwise it will be a null string.
**Note: After a print has started all of the values above will persist until !!! Note
the user issues a SDCARD_RESET_FILE gcode or when a new print has started.** After a print has started all of the values above will persist until
the user issues a SDCARD_RESET_FILE gcode or when a new print has started.
## display_status ## display_status
*Enabled when `[display]` or `[display_status]` is included in printer.cfg* *Enabled when `[display]` or `[display_status]` is included in printer.cfg*
@ -360,8 +365,9 @@ The `bed_mesh` printer object reports the following state:
- `mesh_matrix`: A 2 dimension array representing the interpolated mesh. If - `mesh_matrix`: A 2 dimension array representing the interpolated mesh. If
no matrix has been generated the result is `[[]]`. no matrix has been generated the result is `[[]]`.
**Note: See [web_api.md](web_api.md##bed-mesh-coordinates) for an example !!! tip
of how to use this information to generate (X,Y,Z) coordinates.** See [web_api.md](web_api.md##bed-mesh-coordinates) for an example
of how to use this information to generate (X,Y,Z) coordinates.
## gcode_macro macro_name ## gcode_macro macro_name
*Enabled when `[gcode_macro macro_name]` is included in printer.cfg. *Enabled when `[gcode_macro macro_name]` is included in printer.cfg.

View File

@ -253,7 +253,8 @@ JSON-RPC request:
"id": 4654 "id": 4654
} }
``` ```
**Note: A `null` value will fetch all available attributes for its key. !!! note
A `null` value will fetch all available attributes for its key.
Returns: Returns:
@ -289,11 +290,12 @@ HTTP request:
```http ```http
POST /printer/objects/subscribe?connection_id=123456789&gcode_move&extruder` POST /printer/objects/subscribe?connection_id=123456789&gcode_move&extruder`
``` ```
**Note: The HTTP API requires that a `connection_id` is passed via the query !!! note
The HTTP API requires that a `connection_id` is passed via the query
string or as part of the form. This should be the string or as part of the form. This should be the
[ID reported](#get-websocket-id) from a currently connected websocket. A [ID reported](#get-websocket-id) from a currently connected websocket. A
request that includes only the `connection_id` argument will cancel the request that includes only the `connection_id` argument will cancel the
subscription on the specified websocket.** subscription on the specified websocket.
JSON-RPC request: JSON-RPC request:
```json ```json
@ -309,8 +311,9 @@ JSON-RPC request:
"id": 5434 "id": 5434
} }
``` ```
**Note: If `objects` is set to an empty object then the subscription will !!! note
be cancelled.** If `objects` is set to an empty object then the subscription will
be cancelled.
Returns: Returns:
@ -392,7 +395,7 @@ An object containing various fields that report server state.
{ {
"klippy_connected": true, "klippy_connected": true,
"klippy_state": "ready", "klippy_state": "ready",
"plugins": [ "components": [
"database", "database",
"file_manager", "file_manager",
"klippy_apis", "klippy_apis",
@ -405,17 +408,22 @@ An object containing various fields that report server state.
"update_manager", "update_manager",
"power" "power"
], ],
"failed_plugins": [], "failed_components": [],
"registered_directories": ["config", "gcodes", "config_examples", "docs"] "registered_directories": ["config", "gcodes", "config_examples", "docs"]
} }
``` ```
!!! warning
This object also includes `plugins` and `failed_plugins` fields that
are now deprecated. They duplicate the information in
`components` and `failed_components`, and will be removed in the future.
Note that `klippy_state` will match the `state` value received from Note that `klippy_state` will match the `state` value received from
`/printer/info`. The `klippy_connected` item tracks the state of the `/printer/info`. The `klippy_connected` item tracks the state of the
unix domain socket connect to Klippy. The `plugins` key will return a list of unix domain socket connect to Klippy. The `components` key will return a list
enabled plugins. This can be used by clients to check if an optional of enabled components. This can be used by clients to check if an optional
plugin is available. Optional plugins that do not load correctly will not component is available. Optional components that do not load correctly will
prevent the server from starting, thus any plugins that failed to load will be not prevent the server from starting, thus any components that failed to load
reported in the `failed_plugins` field. will be reported in the `failed_components` field.
#### Get Server Configuration #### Get Server Configuration
HTTP request: HTTP request:
@ -987,12 +995,13 @@ JSON-RPC request:
"id": 4644 "id": 4644
} }
``` ```
!!! tip
If the `root` argument is omitted the request will default to
the `gcodes` root.
**Note: If the `root` argument is omitted the request will default to !!! note
the `gcodes` root.** The `gcodes` root will only return files with valid gcode
extensions.
**Note: The `gcodes` root will only return files with valid gcode
extensions.**
Returns: Returns:
A list of objects, where each object contains file data. A list of objects, where each object contains file data.
@ -1093,13 +1102,15 @@ modified time, and size.
"filename": "3DBenchy_0.15mm_PLA_MK3S_2h6m.gcode" "filename": "3DBenchy_0.15mm_PLA_MK3S_2h6m.gcode"
} }
``` ```
**Note: The `print_start_time` and `job_id` fields are initialized to !!! note
The `print_start_time` and `job_id` fields are initialized to
`null`. They will be updated for each print job if the user has the `null`. They will be updated for each print job if the user has the
`[history]` plugin configured** `[history]` component configured
**Note: The `data` field for each thumbnail is deprecated and will be removed !!! warning
The `data` field for each thumbnail is deprecated and will be removed
in a future release. Clients should retrieve the png directly using the in a future release. Clients should retrieve the png directly using the
`relative_path` field.** `relative_path` field.
#### Get directory information #### Get directory information
Returns a list of files and subdirectories given a supplied path. Returns a list of files and subdirectories given a supplied path.
@ -1124,9 +1135,9 @@ JSON-RPC request:
"id": 5644 "id": 5644
} }
``` ```
!!! tip
**Note: If the `path` argument is omitted then the command will return If the `path` argument is omitted then the command will return
directory information from the `gcodes` root.** directory information from the `gcodes` root.
The `extended` argument is optional and defaults to false. If The `extended` argument is optional and defaults to false. If
supplied and set to true then data returned for gcode files supplied and set to true then data returned for gcode files
@ -1223,8 +1234,9 @@ JSON-RPC request:
"id": 6545 "id": 6545
} }
``` ```
**Note: If the specified directory contains files then the delete request !!! warning
will fail unless the `force` argument is set to `true`.** If the specified directory contains files then the delete request
will fail unless the `force` argument is set to `true`.
Returns: Returns:
@ -1467,9 +1479,10 @@ as an array of strings, where each string references a nested field.
This is useful for scenarios where your namespace contains keys that include This is useful for scenarios where your namespace contains keys that include
a "." character. a "." character.
**Note: Moonraker reserves the `moonraker`, `gcode_metadata`, and `history` !!! note
namespaces. Clients may read from these namespaces but they may not modify Moonraker reserves the `moonraker`, `gcode_metadata`, and `history`
them.** namespaces. Clients may read from these namespaces but they may not
modify them.
For example, assume the following object is stored in the "superclient" For example, assume the following object is stored in the "superclient"
namespace: namespace:
@ -1568,10 +1581,11 @@ HTTP request:
```http ```http
POST /server/database/item?namespace={namespace}&key={key}value={value}` POST /server/database/item?namespace={namespace}&key={key}value={value}`
``` ```
**Note: If the `value` is not a string type, the `value` argument must !!! note
If the `value` is not a string type, the `value` argument must
provide a [type hint](#query-string-type-hints). Alternatively, provide a [type hint](#query-string-type-hints). Alternatively,
arguments may be passed via the request body in JSON format. For arguments may be passed via the request body in JSON format. For
example:** example:
```http ```http
POST /server/database/item POST /server/database/item
Content-Type: application/json Content-Type: application/json
@ -1639,7 +1653,7 @@ deleted item.
``` ```
### Update Manager APIs ### Update Manager APIs
The following endpoints are available when the `[update_manager]` plugin has The following endpoints are available when the `[update_manager]` component has
been configured: been configured:
#### Get update status #### Get update status
@ -1887,7 +1901,7 @@ Returns:
`ok` when complete `ok` when complete
### Power APIs ### Power APIs
The APIs below are available when the `[power]` plugin has been configured. The APIs below are available when the `[power]` component has been configured.
#### Get Device List #### Get Device List
HTTP request: HTTP request:
@ -2240,7 +2254,7 @@ An object containing simulates Octoprint Printer profile
``` ```
### History APIs ### History APIs
The APIs below are avilable when the `[history]` plugin has been configured. The APIs below are avilable when the `[history]` component has been configured.
#### Get job list #### Get job list
HTTP request: HTTP request:
@ -2346,9 +2360,9 @@ JSON-RPC request:
"id": 5534 "id": 5534
} }
``` ```
!!! tip
**Note: it is possible to replace the `uid` argument with `all=true` It is possible to replace the `uid` argument with `all=true`
to delete all jobs in the history database.** to delete all jobs in the history database.
Returns: Returns:
@ -2571,9 +2585,10 @@ The websocket is located at `ws://host:port/websocket`, for example:
var s = new WebSocket("ws://" + location.host + "/websocket"); var s = new WebSocket("ws://" + location.host + "/websocket");
``` ```
**Note: A client using API Key authorization may request a !!! tip
A client using API Key authorization may request a
[oneshot token](#generate-a-oneshot-token), applying the result to the [oneshot token](#generate-a-oneshot-token), applying the result to the
websocket request's query string:** websocket request's query string:
```http ```http
ws://host:port/websocket?token={32 character base32 string} ws://host:port/websocket?token={32 character base32 string}

View File

@ -11,9 +11,11 @@ nav:
- API Changes: api_changes.md - API Changes: api_changes.md
- 'Backend Developers': - 'Backend Developers':
- Contributing: contributing.md - Contributing: contributing.md
- Components: components.md
theme: theme:
name: readthedocs name: readthedocs
plugins: plugins:
- search - search
markdown_extensions: markdown_extensions:
- codehilite - codehilite
- admonition