schema-filters (#1052)
* pin schema and other fixes * schema filters and registries
This commit is contained in:
parent
979e0a2d57
commit
f6c277c4f9
|
@ -85,23 +85,40 @@ of these entries matters!)
|
|||
return {};
|
||||
}
|
||||
|
||||
Supported filters:
|
||||
``invert``
|
||||
**********
|
||||
|
||||
- **invert**: Simple filter that just inverts every value from the binary sensor.
|
||||
- **delayed_on**: When a signal ON is received, wait for the specified time period until publishing
|
||||
an ON state. If an OFF value is received while waiting, the ON action is discarded. Or in other words:
|
||||
Only send an ON value if the binary sensor has stayed ON for at least the specified time period.
|
||||
**Useful for debouncing push buttons**.
|
||||
- **delayed_off**: When a signal OFF is received, wait for the specified time period until publishing
|
||||
an OFF state. If an ON value is received while waiting, the OFF action is discarded. Or in other words:
|
||||
Only send an OFF value if the binary sensor has stayed OFF for at least the specified time period.
|
||||
**Useful for debouncing push buttons**.
|
||||
- **delayed_on_off**: Only send an ON or OFF value if the binary sensor has stayed in the same state
|
||||
for at least the specified time period.
|
||||
**Useful for debouncing binary switches**.
|
||||
- **lambda**: Specify any :ref:`lambda <config-lambda>` for more complex filters. The input value from
|
||||
the binary sensor is ``x`` and you can return ``true`` for ON, ``false`` for OFF, and ``{}`` to stop
|
||||
the filter chain.
|
||||
Simple filter that just inverts every value from the binary sensor.
|
||||
|
||||
``delayed_on``
|
||||
**************
|
||||
|
||||
(**Required**, :ref:`config-time`): When a signal ON is received, wait for the specified time period until publishing
|
||||
an ON state. If an OFF value is received while waiting, the ON action is discarded. Or in other words:
|
||||
Only send an ON value if the binary sensor has stayed ON for at least the specified time period.
|
||||
**Useful for debouncing push buttons**.
|
||||
|
||||
``delayed_off``
|
||||
***************
|
||||
|
||||
(**Required**, :ref:`config-time`): When a signal OFF is received, wait for the specified time period until publishing
|
||||
an OFF state. If an ON value is received while waiting, the OFF action is discarded. Or in other words:
|
||||
Only send an OFF value if the binary sensor has stayed OFF for at least the specified time period.
|
||||
**Useful for debouncing push buttons**.
|
||||
|
||||
``delayed_on_off``
|
||||
******************
|
||||
|
||||
(**Required**, :ref:`config-time`): Only send an ON or OFF value if the binary sensor has stayed in the same state
|
||||
for at least the specified time period.
|
||||
**Useful for debouncing binary switches**.
|
||||
|
||||
``lambda``
|
||||
**********
|
||||
|
||||
Specify any :ref:`lambda <config-lambda>` for more complex filters. The input value from
|
||||
the binary sensor is ``x`` and you can return ``true`` for ON, ``false`` for OFF, and ``{}`` to stop
|
||||
the filter chain.
|
||||
|
||||
Binary Sensor Automation
|
||||
------------------------
|
||||
|
|
|
@ -42,7 +42,7 @@ There are numerous board types out there. Some initialize differently as well. T
|
|||
update_interval: 5s
|
||||
|
||||
Configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
************************
|
||||
|
||||
- **model** (**Required**, "See Models Below"): This the model to use. INITR_BLACKTAB is the default
|
||||
- **cs_pin** (**Required**, :ref:`Pin Schema <config-pin_schema>`): The CS pin.
|
||||
|
@ -55,7 +55,7 @@ Configuration variables:
|
|||
- **reset_pin** (*Optional*, :ref:`Pin Schema <config-pin_schema>`): The RESET pin.
|
||||
|
||||
Memory notes:
|
||||
~~~~~~~~~~~~~
|
||||
*************
|
||||
|
||||
- 8Bit color saves 50% of the buffer required.
|
||||
- eightbitcolor: True 160x128 = 20480 *Important for memory constrained devices*
|
||||
|
@ -63,7 +63,7 @@ Memory notes:
|
|||
|
||||
|
||||
Models:
|
||||
~~~~~~~
|
||||
*******
|
||||
|
||||
- INITR_GREENTAB
|
||||
- INITR_REDTAB
|
||||
|
|
|
@ -52,7 +52,7 @@ The MCP23008 component (`datasheet <http://ww1.microchip.com/downloads/en/device
|
|||
inverted: False
|
||||
|
||||
Configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
************************
|
||||
|
||||
- **id** (**Required**, :ref:`config-id`): The id to use for this MCP23008 component.
|
||||
- **address** (*Optional*, int): The I²C address of the driver.
|
||||
|
@ -62,7 +62,7 @@ Configuration variables:
|
|||
will require a pull-up resistor (to 3.3 volts) when this mode is enabled.
|
||||
|
||||
Pin configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****************************
|
||||
|
||||
- **mcp23xxx** (**Required**, :ref:`config-id`): The id of the MCP23008 component.
|
||||
- **interrupt** (*Optional*): Set this pin to trigger the INT pin on the component. Can be one of ``CHANGE``, ``RISING``, ``FALLING``.
|
||||
|
@ -114,14 +114,14 @@ has 16 GPIOs and can be configured the same way than the other variants.
|
|||
|
||||
|
||||
Configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
************************
|
||||
|
||||
- **id** (**Required**, :ref:`config-id`): The id to use for this MCP23016 component.
|
||||
- **address** (*Optional*, int): The I²C address of the driver.
|
||||
Defaults to ``0x20``.
|
||||
|
||||
Pin configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****************************
|
||||
|
||||
- **mcp23xxx** (**Required**, :ref:`config-id`): The id of the MCP23016 component.
|
||||
- All other options from :ref:`Pin Schema <config-pin_schema>`
|
||||
|
@ -173,7 +173,7 @@ binary sensor or GPIO switch.
|
|||
inverted: False
|
||||
|
||||
Configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
************************
|
||||
|
||||
- **id** (**Required**, :ref:`config-id`): The id to use for this MCP23017 component.
|
||||
- **address** (*Optional*, int): The I²C address of the driver.
|
||||
|
@ -183,7 +183,7 @@ Configuration variables:
|
|||
will require pull-up resistors (to 3.3 volts) when this mode is enabled.
|
||||
|
||||
Pin configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****************************
|
||||
|
||||
- **mcp23xxx** (**Required**, :ref:`config-id`): The id of the MCP23017 component.
|
||||
- **interrupt** (*Optional*): Set this pin to trigger the port INT pin on the component. Can be one of ``CHANGE``, ``RISING``, ``FALLING``.
|
||||
|
|
|
@ -54,7 +54,7 @@ The MCP23S08 component (`datasheet <http://ww1.microchip.com/downloads/en/Device
|
|||
inverted: False
|
||||
|
||||
Configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
************************
|
||||
|
||||
- **id** (**Required**, :ref:`config-id`): The id to use for this MCP23S08 component.
|
||||
- **cs_pin** (**Required**, int): The SPI chip select pin to use
|
||||
|
@ -65,7 +65,7 @@ Configuration variables:
|
|||
will require pull-up resistors (to 3.3 volts) when this mode is enabled.
|
||||
|
||||
Pin Configuration Variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****************************
|
||||
|
||||
- **mcp23xxx** (**Required**, :ref:`config-id`): The id of the MCP23S08 component.
|
||||
- **interrupt** (*Optional*): Set this pin to trigger the INT pin on the component. Can be one of ``CHANGE``, ``RISING``, ``FALLING``.
|
||||
|
@ -119,7 +119,7 @@ binary sensor or GPIO switch.
|
|||
inverted: False
|
||||
|
||||
Configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
************************
|
||||
|
||||
- **id** (**Required**, :ref:`config-id`): The id to use for this MCP23S17 component.
|
||||
- **cs_pin** (**Required**, int): The SPI chip select pin to use.
|
||||
|
@ -130,7 +130,7 @@ Configuration variables:
|
|||
will require pull-up resistors (to 3.3 volts) when this mode is enabled.
|
||||
|
||||
Pin Configuration Variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****************************
|
||||
|
||||
- **mcp23xxx** (**Required**, :ref:`config-id`): The id of the MCP23S17 component.
|
||||
- **interrupt** (*Optional*): Set this pin to trigger the port INT pin on the component. Can be one of ``CHANGE``, ``RISING``, ``FALLING``.
|
||||
|
|
|
@ -132,8 +132,10 @@ for platforms with multiple sensors)
|
|||
- delta: 5.0
|
||||
- lambda: return x * (9.0/5.0) + 32.0;
|
||||
|
||||
``offset`` / ``multiply``
|
||||
*************************
|
||||
``offset``
|
||||
**********
|
||||
|
||||
Adds a constant value to each sensor value.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -144,8 +146,10 @@ for platforms with multiple sensors)
|
|||
- offset: 2.0
|
||||
- multiply: 1.2
|
||||
|
||||
Offset adds a constant value to each sensor value. Multiply multiplies each value
|
||||
by a constant value.
|
||||
``multiply``
|
||||
************
|
||||
|
||||
Multiplies each value by a constant value.
|
||||
|
||||
.. _sensor-filter-calibrate_linear:
|
||||
|
||||
|
@ -205,7 +209,7 @@ degree with a least squares solver.
|
|||
``filter_out``
|
||||
**************
|
||||
|
||||
Filter out specific values to be displayed. For example to filter out the value ``85.0``
|
||||
(**Required**, number): Filter out specific values to be displayed. For example to filter out the value ``85.0``
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -218,8 +222,9 @@ Filter out specific values to be displayed. For example to filter out the value
|
|||
``median``
|
||||
**********
|
||||
|
||||
Calculate moving median over the data. This can be used to filter outliers from the received
|
||||
sensor data. A large window size will make the filter slow to react to input changes.
|
||||
A `simple moving median <https://en.wikipedia.org/wiki/Median_filter#Worked_1D_example>`__
|
||||
over the last few values. This can be used to filter outliers from the received sensor data. A large
|
||||
window size will make the filter slow to react to input changes.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -232,27 +237,25 @@ sensor data. A large window size will make the filter slow to react to input cha
|
|||
send_every: 4
|
||||
send_first_at: 3
|
||||
|
||||
- **median**: A `simple moving median
|
||||
<https://en.wikipedia.org/wiki/Median_filter#Worked_1D_example>`__
|
||||
over the last few values.
|
||||
Configuration variables:
|
||||
|
||||
- **window_size**: The number of values over which to calculate the median
|
||||
when pushing out a value. This number should
|
||||
be odd if you want an actual received value pushed out.
|
||||
Defaults to ``5``.
|
||||
- **send_every**: How often a sensor value should be pushed out. For
|
||||
example, in above configuration the median is calculated after every 4th
|
||||
received sensor value, over the last 7 received values.
|
||||
Defaults to ``5``.
|
||||
- **send_first_at**: By default, the very first raw value on boot is immediately
|
||||
published. With this parameter you can specify when the very first value is to be sent.
|
||||
Must be smaller than or equal to ``send_every``
|
||||
Defaults to ``1``.
|
||||
- **window_size** (*Optional*, integer): The number of values over which to calculate the median
|
||||
when pushing out a value. This number should
|
||||
be odd if you want an actual received value pushed out.
|
||||
Defaults to ``5``.
|
||||
- **send_every** (*Optional*, integer): How often a sensor value should be pushed out. For
|
||||
example, in above configuration the median is calculated after every 4th
|
||||
received sensor value, over the last 7 received values.
|
||||
Defaults to ``5``.
|
||||
- **send_first_at** (*Optional*, integer): By default, the very first raw value on boot is immediately
|
||||
published. With this parameter you can specify when the very first value is to be sent.
|
||||
Must be smaller than or equal to ``send_every``
|
||||
Defaults to ``1``.
|
||||
|
||||
``min`` / ``max``
|
||||
*****************
|
||||
``min``
|
||||
*******
|
||||
|
||||
Calculate min/max over the data. A large window size will make the filter slow to
|
||||
A moving minimum over the last few values. A large window size will make the filter slow to
|
||||
react to input changes.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
@ -266,29 +269,46 @@ react to input changes.
|
|||
send_every: 4
|
||||
send_first_at: 3
|
||||
|
||||
- **min**: A moving minimum over the last few values.
|
||||
Configuration variables:
|
||||
|
||||
- **max**: A moving maximum over the last few values.
|
||||
- **window_size** (*Optional*, integer): The number of values over which to calculate the min/max when pushing out a
|
||||
value. Defaults to ``5``.
|
||||
- **send_every** (*Optional*, integer): How often a sensor value should be pushed out. For
|
||||
example, in above configuration the min is calculated after every 4th
|
||||
received sensor value, over the last 7 received values.
|
||||
Defaults to ``5``.
|
||||
- **send_first_at** (*Optional*, integer): By default, the very first raw value on boot is immediately
|
||||
published. With this parameter you can specify when the very first value is to be sent.
|
||||
Must be smaller than or equal to ``send_every``
|
||||
Defaults to ``1``.
|
||||
|
||||
- Both accept the following parameters:
|
||||
``max``
|
||||
*******
|
||||
|
||||
- **window_size**: The number of values over which to calculate the min/max
|
||||
when pushing out a value.
|
||||
Defaults to ``5``.
|
||||
- **send_every**: How often a sensor value should be pushed out. For
|
||||
example, in above configuration the min is calculated after every 4th
|
||||
received sensor value, over the last 7 received values.
|
||||
Defaults to ``5``.
|
||||
- **send_first_at**: By default, the very first raw value on boot is immediately
|
||||
published. With this parameter you can specify when the very first value is to be sent.
|
||||
Must be smaller than or equal to ``send_every``
|
||||
Defaults to ``1``.
|
||||
A moving maximum over the last few values. A large window size will make the filter slow to
|
||||
react to input changes.
|
||||
|
||||
``sliding_window_moving_average`` / ``exponential_moving_average``
|
||||
******************************************************************
|
||||
Configuration variables:
|
||||
|
||||
Two simple moving averages over the data. These can be used to have a short update interval
|
||||
on the sensor but only push out an average on a specific interval (thus increasing resolution).
|
||||
- **window_size** (*Optional*, integer): The number of values over which to calculate the min/max
|
||||
when pushing out a value.
|
||||
Defaults to ``5``.
|
||||
- **send_every** (*Optional*, integer): How often a sensor value should be pushed out. For
|
||||
example, in above configuration the min is calculated after every 4th
|
||||
received sensor value, over the last 7 received values.
|
||||
Defaults to ``5``.
|
||||
- **send_first_at** (*Optional*, integer): By default, the very first raw value on boot is immediately
|
||||
published. With this parameter you can specify when the very first value is to be sent.
|
||||
Must be smaller than or equal to ``send_every``
|
||||
Defaults to ``1``.
|
||||
|
||||
|
||||
``sliding_window_moving_average``
|
||||
*********************************
|
||||
|
||||
A `simple moving average <https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average>`__
|
||||
over the last few values. It can be used to have a short update interval on the sensor but only push
|
||||
out an average on a specific interval (thus increasing resolution).
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -300,28 +320,36 @@ on the sensor but only push out an average on a specific interval (thus increasi
|
|||
window_size: 15
|
||||
send_every: 15
|
||||
|
||||
- **sliding_window_moving_average**: A `simple moving
|
||||
average <https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average>`__
|
||||
over the last few values.
|
||||
Configuration variables:
|
||||
|
||||
- **window_size**: The number of values over which to perform an
|
||||
average when pushing out a value.
|
||||
- **send_every**: How often a sensor value should be pushed out. For
|
||||
example, in above configuration the weighted average is only
|
||||
pushed out on every 15th received sensor value.
|
||||
- **send_first_at**: By default, the very first raw value on boot is immediately
|
||||
published. With this parameter you can specify when the very first value is to be sent.
|
||||
Defaults to ``1``.
|
||||
- **window_size** (*Optional*, integer): The number of values over which to perform an
|
||||
average when pushing out a value.
|
||||
- **send_every** (*Optional*, integer): How often a sensor value should be pushed out. For
|
||||
example, in above configuration the weighted average is only
|
||||
pushed out on every 15th received sensor value.
|
||||
- **send_first_at** (*Optional*, integer): By default, the very first raw value on boot is immediately
|
||||
published. With this parameter you can specify when the very first value is to be sent.
|
||||
Defaults to ``1``.
|
||||
|
||||
- **exponential_moving_average**: A simple `exponential moving
|
||||
average <https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average>`__
|
||||
over the last few values.
|
||||
``exponential_moving_average``
|
||||
******************************
|
||||
|
||||
- **alpha**: The forget factor/alpha value of the filter.
|
||||
- **send_every**: How often a sensor value should be pushed out.
|
||||
A simple `exponential moving average
|
||||
<https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average>`__ over the last few
|
||||
values. It can be used to have a short update interval on the sensor but only push
|
||||
out an average on a specific interval (thus increasing resolution).
|
||||
|
||||
``throttle`` / ``heartbeat`` / ``debounce`` / ``delta``
|
||||
*******************************************************
|
||||
Configuration variables:
|
||||
|
||||
- **alpha** (*Optional*, float): The forget factor/alpha value of the filter. Defaults to ``0.1``.
|
||||
- **send_every** (*Optional*, integer): How often a sensor value should be pushed out. Defaults to ``15``.
|
||||
|
||||
``throttle``
|
||||
************
|
||||
|
||||
Throttle the incoming values. When this filter gets an incoming value,
|
||||
it checks if the last incoming value is at least ``specified time period`` old.
|
||||
If it is not older than the configured value, the value is not passed forward.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -333,28 +361,38 @@ on the sensor but only push out an average on a specific interval (thus increasi
|
|||
- delta: 5.0
|
||||
- lambda: return x * (9.0/5.0) + 32.0;
|
||||
|
||||
- **throttle**: Throttle the incoming values. When this filter gets an incoming value,
|
||||
it checks if the last incoming value is at least ``specified time period`` old.
|
||||
If it is not older than the configured value, the value is not passed forward.
|
||||
|
||||
- **heartbeat**: Send the last value that this sensor in the specified time interval.
|
||||
So a value of ``10s`` will cause the filter to output values every 10s regardless
|
||||
of the input values.
|
||||
|
||||
- **debounce**: Only send values if the last incoming value is at least ``specified time period``
|
||||
old. For example if two values come in at almost the same time, this filter will only output
|
||||
the last value and only after the specified time period has passed without any new incoming
|
||||
values.
|
||||
|
||||
- **delta**: This filter stores the last value passed through this filter and only
|
||||
passes incoming values through if the absolute difference is greater than the configured
|
||||
value. For example if a value of 1.0 first comes in, it's passed on. If the delta filter
|
||||
is configured with a value of 5, it will now not pass on an incoming value of 2.0, only values
|
||||
that are at least 6.0 big or -4.0.
|
||||
|
||||
``or`` Filter
|
||||
``heartbeat``
|
||||
*************
|
||||
|
||||
Send the last value that this sensor in the specified time interval.
|
||||
So a value of ``10s`` will cause the filter to output values every 10s regardless
|
||||
of the input values.
|
||||
|
||||
``debounce``
|
||||
************
|
||||
|
||||
Only send values if the last incoming value is at least ``specified time period``
|
||||
old. For example if two values come in at almost the same time, this filter will only output
|
||||
the last value and only after the specified time period has passed without any new incoming
|
||||
values.
|
||||
|
||||
``delta``
|
||||
*********
|
||||
|
||||
This filter stores the last value passed through this filter and only
|
||||
passes incoming values through if the absolute difference is greater than the configured
|
||||
value. For example if a value of 1.0 first comes in, it's passed on. If the delta filter
|
||||
is configured with a value of 5, it will now not pass on an incoming value of 2.0, only values
|
||||
that are at least 6.0 big or -4.0.
|
||||
|
||||
``or``
|
||||
******
|
||||
|
||||
Pass forward a value with the first child filter that returns. Above example
|
||||
will only pass forward values that are *either* at least 1s old or are if the absolute
|
||||
difference is at least 5.0.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Example filters:
|
||||
|
@ -363,22 +401,18 @@ on the sensor but only push out an average on a specific interval (thus increasi
|
|||
- throttle: 1s
|
||||
- delta: 5.0
|
||||
|
||||
- **or**: Pass forward a value with the first child filter that returns. Above example
|
||||
will only pass forward values that are *either* at least 1s old or are if the absolute
|
||||
difference is at least 5.0.
|
||||
|
||||
``lambda``
|
||||
**********
|
||||
|
||||
``lambda`` Filter
|
||||
*****************
|
||||
Perform a simple mathematical operation over the sensor values. The input value is ``x`` and
|
||||
the result of the lambda is used as the output (use ``return``).
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
filters:
|
||||
- lambda: return x * (9.0/5.0) + 32.0;
|
||||
|
||||
**lambda**: Perform a simple mathematical operation over the sensor
|
||||
values. The input value is ``x`` and the result of the lambda is used
|
||||
as the output (use ``return``).
|
||||
|
||||
Make sure to add ``.0`` to all values in the lambda, otherwise divisions of integers will
|
||||
result in integers (not floating point values).
|
||||
|
|
|
@ -43,7 +43,7 @@ Use of the OE pin is optional. If used, the pin should be pulled up externally.
|
|||
inverted: False
|
||||
|
||||
Configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
************************
|
||||
|
||||
- **id** (**Required**, :ref:`config-id`): The id to use for this SN74HC595 component.
|
||||
- **data_pin** (**Required**, :ref:`Pin Schema <config-pin_schema>`): Pin connected to SN74HC595 SER input.
|
||||
|
@ -54,7 +54,7 @@ Configuration variables:
|
|||
|
||||
|
||||
Pin configuration variables:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****************************
|
||||
|
||||
- **sn74hc595** (**Required**, :ref:`config-id`): The id of the SN74HC595 component of the pin.
|
||||
- **number** (**Required**, integer): The pin number.
|
||||
|
|
|
@ -31,9 +31,10 @@ The ESPHome documentation is built using `sphinx <http://www.sphinx-doc.org/>`__
|
|||
Syntax
|
||||
******
|
||||
|
||||
In my opinion, Markdown would have been the much better choice in hindsight, but at the time
|
||||
I was setting up the documentation good Doxygen integration was key to me. Anyway, here's a quick
|
||||
RST primer:
|
||||
Here's a quick RST primer:
|
||||
|
||||
Title hierarchy is based on order of occurence, not on type of character used to underline it. This
|
||||
documents establish the following character order for better consistency.
|
||||
|
||||
- **Headers**: You can write titles like this:
|
||||
|
||||
|
@ -547,8 +548,8 @@ loader. These are:
|
|||
has one of them in the config, a validation error will be generated.
|
||||
|
||||
- ``ESP_PLATFORMS``: Provide a list of allowed ESP types this integration works with.
|
||||
- ``CODEOWNERS``: GitHub usernames or team names of people that are responsible for this integration.
|
||||
You should add at least your GitHub username here, as well as anyone who helped you to write code
|
||||
- ``CODEOWNERS``: GitHub usernames or team names of people that are responsible for this integration.
|
||||
You should add at least your GitHub username here, as well as anyone who helped you to write code
|
||||
that is being included.
|
||||
|
||||
Codebase Standards
|
||||
|
|
189
schema_doc.py
189
schema_doc.py
|
@ -6,7 +6,7 @@ from typing import MutableMapping
|
|||
from sphinx.util import logging
|
||||
from docutils import nodes
|
||||
|
||||
SCHEMA_PATH = "../esphome_devices/schema.json"
|
||||
SCHEMA_PATH = "schema.json"
|
||||
CONFIGURATION_VARIABLES = "Configuration variables:"
|
||||
PIN_CONFIGURATION_VARIABLES = "Pin configuration variables:"
|
||||
COMPONENT_HUB = "Component/Hub"
|
||||
|
@ -75,7 +75,9 @@ PLATFORMS_TITLES = {
|
|||
}
|
||||
|
||||
CUSTOM_DOCS = {
|
||||
"guides/automations": {"Global Variables": "properties/globals"},
|
||||
"guides/automations": {
|
||||
"Global Variables": "properties/globals",
|
||||
},
|
||||
"guides/configuration-types": {
|
||||
"Color": "properties/color",
|
||||
"Pin Schema": [
|
||||
|
@ -83,6 +85,9 @@ CUSTOM_DOCS = {
|
|||
"definitions/PIN.OUTPUT_INTERNAL",
|
||||
],
|
||||
},
|
||||
"components/binary_sensor/index": {
|
||||
"Binary Sensor Filters": "binary_sensor.FILTER_REGISTRY",
|
||||
},
|
||||
"components/climate/ir_climate": {
|
||||
"IR Remote Climate": [
|
||||
"properties/climate/coolix",
|
||||
|
@ -109,7 +114,8 @@ CUSTOM_DOCS = {
|
|||
"definitions/light.BINARY_LIGHT_SCHEMA",
|
||||
"definitions/light.BRIGHTNESS_ONLY_LIGHT_SCHEMA",
|
||||
"definitions/light.LIGHT_SCHEMA",
|
||||
]
|
||||
],
|
||||
"Light Effects": "light.EFFECTS_REGISTRY",
|
||||
},
|
||||
"components/light/fastled": {
|
||||
"Clockless": "properties/light/fastled_clockless",
|
||||
|
@ -125,10 +131,13 @@ CUSTOM_DOCS = {
|
|||
"MQTT Component Base Configuration": "definitions/CONFIG.MQTT_COMMAND_COMPONENT_SCHEMA",
|
||||
},
|
||||
"components/output/index": {
|
||||
"Base Output Configuration": "definitions/output.FLOAT_OUTPUT_SCHEMA"
|
||||
"Base Output Configuration": "definitions/output.FLOAT_OUTPUT_SCHEMA",
|
||||
},
|
||||
"components/remote_transmitter": {
|
||||
"Remote Transmitter Actions": "definitions/REMOTE_BASE.BASE_REMOTE_TRANSMITTER_SCHEMA"
|
||||
"Remote Transmitter Actions": "definitions/REMOTE_BASE.BASE_REMOTE_TRANSMITTER_SCHEMA",
|
||||
},
|
||||
"components/sensor/index": {
|
||||
"Sensor Filters": "sensor.FILTER_REGISTRY",
|
||||
},
|
||||
"components/time": {
|
||||
"Home Assistant Time Source": "properties/time/homeassistant",
|
||||
|
@ -146,6 +155,10 @@ CUSTOM_DOCS = {
|
|||
}
|
||||
|
||||
|
||||
def get_node_title(node):
|
||||
return list(node.traverse(nodes.title))[0].astext()
|
||||
|
||||
|
||||
class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
||||
def __init__(self, app, doctree, docname):
|
||||
nodes.NodeVisitor.__init__(self, doctree)
|
||||
|
@ -160,6 +173,8 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
self.json_base_config = None
|
||||
self.title_id = None
|
||||
self.props_section_title = None
|
||||
self.find_registry = None
|
||||
self.section_level = 0
|
||||
if self.path[0] == "components":
|
||||
if len(self.path) == 2: # root component, e.g. dfplayer, logger
|
||||
component = docname[11:]
|
||||
|
@ -230,7 +245,7 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
# this is empty, not much to do
|
||||
raise nodes.SkipChildren
|
||||
|
||||
self.props_section_title = list(node.traverse(nodes.title))[0].astext()
|
||||
self.props_section_title = get_node_title(node)
|
||||
|
||||
# Document first paragraph is description of this thing
|
||||
description = self.getMarkdownParagraph(node)
|
||||
|
@ -266,23 +281,23 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
def depart_document(self, node):
|
||||
pass
|
||||
|
||||
def visit_SEONode(self, node):
|
||||
pass
|
||||
|
||||
def depart_SEONode(self, node):
|
||||
pass
|
||||
|
||||
def visit_literal_block(self, node):
|
||||
pass
|
||||
|
||||
def depart_literal_block(self, node):
|
||||
pass
|
||||
|
||||
def visit_section(self, node):
|
||||
pass
|
||||
self.section_level += 1
|
||||
section_title = get_node_title(node)
|
||||
if self.custom_doc and section_title in self.custom_doc:
|
||||
r = self.custom_doc[section_title]
|
||||
if (
|
||||
isinstance(r, list)
|
||||
or r.startswith("properties")
|
||||
or r.startswith("definitions")
|
||||
):
|
||||
return
|
||||
self.find_registry = r
|
||||
|
||||
def depart_section(self, node):
|
||||
pass
|
||||
self.section_level -= 1
|
||||
if self.section_level == 1:
|
||||
self.find_registry = None
|
||||
|
||||
def unknown_visit(self, node):
|
||||
pass
|
||||
|
@ -303,7 +318,11 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
# TODO: add same markdown description to each?
|
||||
|
||||
return
|
||||
|
||||
json_component = self.find_component(self.custom_doc[title_text])
|
||||
if not json_component:
|
||||
return
|
||||
|
||||
json_component["markdownDescription"] = self.getMarkdownParagraph(
|
||||
node.parent
|
||||
)
|
||||
|
@ -450,22 +469,6 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
)
|
||||
return
|
||||
|
||||
if title_text.endswith("Action") or title_text.endswith("Condition"):
|
||||
# Document first paragraph is description of this thing
|
||||
description = self.getMarkdownParagraph(node.parent)
|
||||
split_text = title_text.split(" ")
|
||||
if len(split_text) != 2:
|
||||
return
|
||||
key = split_text[0]
|
||||
registry_name = f"automation.{split_text[1].upper()}_REGISTRY"
|
||||
registry = self.app.jschema["definitions"][registry_name]["anyOf"]
|
||||
for action in registry:
|
||||
if key in action["properties"]:
|
||||
action["properties"][key]["markdownDescription"] = description
|
||||
self.props = self.find_props(action["properties"][key])
|
||||
break
|
||||
self.props_section_title = title_text
|
||||
|
||||
if title_text.endswith("Trigger"):
|
||||
# Document first paragraph is description of this thing
|
||||
description = self.getMarkdownParagraph(node.parent)
|
||||
|
@ -481,28 +484,50 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
self.props = self.find_props(trigger_schema)
|
||||
self.props_section_title = title_text
|
||||
|
||||
if self.docname == "components/light/index" and title_text.endswith("Effect"):
|
||||
# Document first paragraph is description of this thing
|
||||
if title_text == PIN_CONFIGURATION_VARIABLES:
|
||||
self.multi_component = []
|
||||
if self.app.jschema["definitions"].get(f"PIN.INPUT_{self.path[-1]}"):
|
||||
self.multi_component.append(f"definitions/PIN.INPUT_{self.path[-1]}")
|
||||
if self.app.jschema["definitions"].get(f"PIN.OUTPUT_{self.path[-1]}"):
|
||||
self.multi_component.append(f"definitions/PIN.OUTPUT_{self.path[-1]}")
|
||||
self.accept_props = True
|
||||
self.filled_props = False
|
||||
self.props = None
|
||||
if len(self.multi_component) == 0:
|
||||
raise ValueError(
|
||||
f'Found a "{PIN_CONFIGURATION_VARIABLES}" entry but could not find pin schema'
|
||||
)
|
||||
|
||||
if title_text.endswith("Action") or title_text.endswith("Condition"):
|
||||
# Document first paragraph is description of this thing
|
||||
description = self.getMarkdownParagraph(node.parent)
|
||||
name = title_text[: -len(" Effect")]
|
||||
# accept Light Effect as ending (Automation Light Effect)
|
||||
split_text = title_text.split(" ")
|
||||
if len(split_text) != 2:
|
||||
return
|
||||
key = split_text[0]
|
||||
|
||||
if self.props:
|
||||
ref = self.props.get(key)
|
||||
if ref:
|
||||
ref = self.get_ref(ref)
|
||||
if ref:
|
||||
self.props = self.find_props(ref)
|
||||
return
|
||||
|
||||
registry_name = f"automation.{split_text[1].upper()}_REGISTRY"
|
||||
self.find_registry_prop(registry_name, key, description)
|
||||
|
||||
if self.section_level == 3 and self.find_registry:
|
||||
name = title_text
|
||||
if name.endswith(" Effect"):
|
||||
name = title_text[: -len(" Effect")]
|
||||
if name.endswith(" Light"):
|
||||
name = name[: -len(" Light")]
|
||||
|
||||
key = name.replace(" ", "_").replace(".", "").lower()
|
||||
registry = self.app.jschema["definitions"]["light.EFFECTS_REGISTRY"][
|
||||
"anyOf"
|
||||
]
|
||||
description = self.getMarkdownParagraph(node.parent)
|
||||
self.find_registry_prop(self.find_registry, key, description)
|
||||
self.props_section_title = title_text
|
||||
|
||||
for effect in registry:
|
||||
if key in effect["properties"]:
|
||||
effect["properties"][key]["markdownDescription"] = description
|
||||
self.props = self.find_props(effect["properties"][key])
|
||||
return
|
||||
raise ValueError("Cannot find Effect " + title_text)
|
||||
|
||||
if title_text == PIN_CONFIGURATION_VARIABLES:
|
||||
self.multi_component = []
|
||||
if self.app.jschema["definitions"].get(f"PIN.INPUT_{self.path[-1]}"):
|
||||
|
@ -517,6 +542,16 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
f'Found a "{PIN_CONFIGURATION_VARIABLES}" entry but could not find pin schema'
|
||||
)
|
||||
|
||||
def find_registry_prop(self, registry_name, key, description):
|
||||
registry = self.app.jschema["definitions"][registry_name]["anyOf"]
|
||||
for item in registry:
|
||||
if key in item["properties"]:
|
||||
item["properties"][key]["markdownDescription"] = description
|
||||
self.props = self.find_props(item["properties"][key])
|
||||
|
||||
return
|
||||
raise ValueError(f"Cannot find {registry_name} {key}")
|
||||
|
||||
def depart_title(self, node):
|
||||
if self.filled_props:
|
||||
self.filled_props = False
|
||||
|
@ -663,6 +698,25 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
paragraph = list(node.traverse(nodes.paragraph))[0]
|
||||
markdown = self.getMarkdown(paragraph)
|
||||
|
||||
param_type = None
|
||||
# Check if there is type information for this item
|
||||
try:
|
||||
name_type = markdown[: markdown.index(": ") + 2]
|
||||
ntr = re.search(
|
||||
r"(\(((\*\*Required\*\*)|(\*Optional\*))(,\s(.*))*)\):\s",
|
||||
name_type,
|
||||
re.IGNORECASE,
|
||||
)
|
||||
if ntr:
|
||||
param_type = ntr.group(6)
|
||||
if param_type:
|
||||
markdown = (
|
||||
f"**{param_type}**: {markdown[markdown.index(': ') + 2 :]}"
|
||||
)
|
||||
except ValueError:
|
||||
# ': ' not found
|
||||
pass
|
||||
|
||||
title = list(node.traverse(nodes.title))[0]
|
||||
if len(title) > 0:
|
||||
url = urllib.parse.urljoin(
|
||||
|
@ -696,9 +750,6 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
# **name** (*Optional*, string): Long Description... Defaults to ``value``.
|
||||
# **name** (*Optional*): Long Description... Defaults to ``value``.
|
||||
|
||||
if "ads111" in self.docname:
|
||||
self.docname = self.docname
|
||||
|
||||
ntr = re.search(
|
||||
r"\* \*\*(\w*)\*\*\s(\(((\*\*Required\*\*)|(\*Optional\*))(,\s(.*))*)\):\s",
|
||||
name_type,
|
||||
|
@ -765,7 +816,7 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
|
||||
desc = markdown[markdown.index(": ") + 2 :].strip()
|
||||
if param_type:
|
||||
desc = param_type + ": " + desc
|
||||
desc = "**" + param_type + "**: " + desc
|
||||
|
||||
jprop["markdownDescription"] = desc
|
||||
global props_documented
|
||||
|
@ -780,6 +831,8 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
|
||||
def find_component(self, component_path):
|
||||
path = component_path.split("/")
|
||||
if path[0] not in ("properties", "definitions"):
|
||||
return None
|
||||
json_component = self.app.jschema[path[0]][path[1]]
|
||||
|
||||
if len(path) > 2:
|
||||
|
@ -897,32 +950,6 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor):
|
|||
self.current_prop = None
|
||||
|
||||
return props
|
||||
return
|
||||
# find properties
|
||||
if "then" in component:
|
||||
component = component["then"]
|
||||
props = component.get("properties")
|
||||
ref = None
|
||||
if not props:
|
||||
arr = component.get("anyOf", component.get("allOf"))
|
||||
if not arr:
|
||||
if "$ref" in component:
|
||||
return self.find_props(self.get_ref(component))
|
||||
return None
|
||||
for x in arr:
|
||||
props = x.get("properties")
|
||||
if not ref:
|
||||
ref = self.get_ref(x)
|
||||
if props:
|
||||
break
|
||||
if not props and ref:
|
||||
props = self.find_props(ref)
|
||||
|
||||
if props:
|
||||
self.filled_props = False
|
||||
self.accept_props = False
|
||||
self.current_prop = None
|
||||
return props
|
||||
|
||||
|
||||
def handle_component(app, doctree, docname):
|
||||
|
|
Loading…
Reference in New Issue