diff --git a/changelog/2021.12.0.rst b/changelog/2021.12.0.rst index b65c24b03..80b87e8be 100644 --- a/changelog/2021.12.0.rst +++ b/changelog/2021.12.0.rst @@ -71,7 +71,7 @@ NEC remote protocol ------------------- In this version, the order of transferring bits was corrected from MSB to LSB in accordance with the NEC standard. -Therefore, if the the configuration file has come from an earlier version of ESPhome, it is necessary to reverse +Therefore, if the configuration file has come from an earlier version of ESPhome, it is necessary to reverse the order of the address and command bits when moving to 2021.12 or above. For example, address: ``0x84ED``, command: ``0x13EC`` becomes ``0xB721`` and ``0x37C8`` respectively. diff --git a/changelog/v1.14.0.rst b/changelog/v1.14.0.rst index 603a627d7..6fe862a40 100644 --- a/changelog/v1.14.0.rst +++ b/changelog/v1.14.0.rst @@ -306,7 +306,7 @@ Notable Changes & New Features - Add configurable ignore bits to rc_switch_raw codes (:esphomepr:`650` by :ghuser:`mtl010957`, :doc:`docs `). - New ``restore`` option has been added to :doc:`servos ` (:esphomepr:`829`). -- Add IR receiver support for coolix climate devices (:esphomepr:`645` by :ghuser:`glmnet`, :doc:`docs `). +- Add IR receiver support for coolix climate devices (:esphomepr:`645` by :ghuser:`glmnet`, :doc:`docs `). - Add :ref:`calibrate_polynomial ` sensor filter (:esphomepr:`642`). - Allow setting the initial mode of HLW8012 sensors (:esphomepr:`611` by :ghuser:`brandond`, :doc:`docs `). - Add tilt actions to :doc:`template cover ` (:esphomepr:`577` by :ghuser:`mtl010957`). diff --git a/components/binary_sensor/analog_threshold.rst b/components/binary_sensor/analog_threshold.rst index 8a665eae0..8dac5db1a 100644 --- a/components/binary_sensor/analog_threshold.rst +++ b/components/binary_sensor/analog_threshold.rst @@ -5,19 +5,19 @@ Analog Threshold Binary Sensor :description: Instructions for setting up an analog threshold binary sensors. :image: analog_threshold.svg -The ``analog_threshold`` binary sensor platform allows you to convert analog values -(i.e. :doc:`sensor ` readings) -into boolean values, using a threshold as a reference. -When the signal is above or equal to the threshold the binary sensor is `true` -(this behavior can be changed adding and `invert` filter). +The ``analog_threshold`` binary sensor platform allows you to convert analog values +(i.e. :doc:`sensor ` readings) +into boolean values, using a threshold as a reference. +When the signal is above or equal to the threshold the binary sensor is ``true`` +(this behavior can be changed adding and ``invert`` filter). It provides an *hysteresis* option to reduce instability when the source signal is noisy -using different limits depending on the current state. -Additionally a :ref:`delay filter ` could be used to only change +using different limits depending on the current state. +Additionally a :ref:`delay filter ` could be used to only change after a new state has been kept a minimum time. If the source sensor is uninitialized at the moment of component creation, the initial -state of the binary sensor wil be `false`, if later it has some reading errors, those +state of the binary sensor wil be ``false``, if later it has some reading errors, those invalid source updates will be ignored, and the binary sensor will keep it´s last state. For example, below configuration would turn the readings of current sensor into @@ -39,8 +39,8 @@ Configuration variables - **name** (**Required**, string): The name of the binary sensor. - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **sensor_id** (**Required**, :ref:`config-id`): The ID of the source sensor. -- **threshold** (**Required**, float or mapping): Configures the reference for comparison. Accepts either a shorthand - float number that will be used as both upper/lower threshold, or a mapping to define different values for each (to +- **threshold** (**Required**, float or mapping): Configures the reference for comparison. Accepts either a shorthand + float number that will be used as both upper/lower threshold, or a mapping to define different values for each (to use hysteresis). - **upper** (**Required**, float): Upper threshold, that needs to be crossed to transition from ``low`` to ``high`` states. diff --git a/components/binary_sensor/cap1188.rst b/components/binary_sensor/cap1188.rst index 479eb6bf0..0cc7a5113 100644 --- a/components/binary_sensor/cap1188.rst +++ b/components/binary_sensor/cap1188.rst @@ -49,10 +49,12 @@ The configuration is made up of two parts: The central component, and individual - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor. - **reset_pin** (*Optional*, :ref:`config-pin`): Set the pin that is used to reset the CAP1188 board on boot. - **touch_threshold** (*Optional*, int): The touch threshold for all channels. This defines the sensitivity for touch detection. + - ``0x01``: Maximum sensitivity - Most sensitive to touch - ``0x20``: Default sensitivity - ``0x40``: Medium sensitivity (I used this sensitivity when being used through a 3mm sheet of plastic) - ``0x80``: Minimum sensitivity - Least sensitive to touch + - **allow_multiple_touches** (*Optional*, boolean): Whether to allow multitouch. Defaults to off. Binary Sensor diff --git a/components/binary_sensor/modbus_controller.rst b/components/binary_sensor/modbus_controller.rst index 455ee0048..1c0b83197 100644 --- a/components/binary_sensor/modbus_controller.rst +++ b/components/binary_sensor/modbus_controller.rst @@ -1,5 +1,5 @@ -Modbus Binary Sensor -==================== +Modbus Controller Binary Sensor +=============================== .. seo:: :description: Instructions for setting up a modbus_controller device binary sensor. @@ -14,31 +14,39 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. -- **modbus_functioncode** (**Required**): type of the modbus register. - - "read_coils": Function 01 (01hex) Read Coils - Reads the ON/OFF status of discrete coils in the device. - - "read_discrete_inputs": Function 02(02hex) - Reads the ON/OFF status of discrete inputs in the device. - - "read_holding_registers": Function 03 (03hex) Read Holding Registers - Read the binary contents of holding registers in the device. - - "read_input_registers": Function 04 (04hex) Read Input Registers - Read the binary contents of input registers in the device. +- **register_type** (**Required**): type of the modbus register. -- **address**: (**Required**, int): start address of the first register in a range -- **bitmask** : some values are packed in a response. The bitmask is used to determined if the result is true or false -- **skip_updates**: (*Optional*, int): By default all sensors of of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle -- **register_count**: (*Optional*, int): only required for uncommon response encodings or to :ref:`optimize modbus communications` - The number of registers this data point spans. Overrides the defaults determined by ``value_type``. - If no value for ``register_count`` is provided, it is calculated based on the register type. + - ``coil``: Function 01 (01hex) Read Coils - Reads the ON/OFF status of discrete coils in the device. + - ``discrete_input``: Function 02(02hex) - Reads the ON/OFF status of discrete inputs in the device. + - ``holding``: Function 03 (03hex) Read Holding Registers - Read the binary contents of holding registers in the device. + - ``read``: Function 04 (04hex) Read Input Registers - Read the binary contents of input registers in the device. - The default size for 1 register is 16 bits (1 Word). Some devices are not adhering to this convention and have registers larger than 16 bits. In this case ``register_count`` and ``response_size`` must be set. For example, if your modbus device uses 1 registers for a FP32 value instead the default of two set ``register_count: 1`` and ``response_size: 4``. -- **response_size**: (*Optional*, int): Size of the response for the register in bytes. Defaults to register_count*2. -- **force_new_range**: (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting ``force_new_range: true`` enforces the start of a new range at that address. -- **custom_data** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_data`` is used ``address`` and ``register_type`` can't be used. +- **address** (**Required**, int): start address of the first register in a range +- **bitmask** (*Optional*, int): Some values are packed in a response. The bitmask is used to determined if the result is true or false +- **skip_updates** (*Optional*, int): By default all sensors of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle +- **response_size** (*Optional*, int): Size of the response for the register in bytes. Defaults to register_count*2. +- **force_new_range** (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting ``force_new_range: true`` enforces the start of a new range at that address. +- **custom_command** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_command`` is used ``address`` and ``register_type`` can't be used. custom data must contain all required bytes including the modbus device address. The crc is automatically calculated and appended to the command. - See :ref:`modbus_custom_data` how to use ``custom_command`` + See :ref:`modbus_custom_command` how to use ``custom_command`` - **lambda** (*Optional*, :ref:`lambda `): Lambda to be evaluated every update interval to get the new value of the sensor -- **offset**: (*Optional*, int): not required for most cases + + Parameters + + - **x** (bool): The parsed float value of the modbus data + - **data** (std::vector`. diff --git a/components/climate/ir_climate.rst b/components/climate/climate_ir.rst similarity index 100% rename from components/climate/ir_climate.rst rename to components/climate/climate_ir.rst diff --git a/components/cover/time_based.rst b/components/cover/time_based.rst index a2da02d76..e9ca8e493 100644 --- a/components/cover/time_based.rst +++ b/components/cover/time_based.rst @@ -1,4 +1,4 @@ -Time-Based Cover +Time Based Cover ================ .. seo:: diff --git a/components/deep_sleep.rst b/components/deep_sleep.rst index a45822e27..9516524ab 100644 --- a/components/deep_sleep.rst +++ b/components/deep_sleep.rst @@ -127,7 +127,7 @@ Useful for keeping the ESP active during data transfer or OTA updating (See note it will no longer enter deep sleep mode and you can upload your OTA update. Remember to turn "OTA mode" off again after the OTA update by sending a MQTT message with the payload - ``OFF``. To enter the the deep sleep again after the OTA update send a message on the topic ``livingroom/sleep_mode`` + ``OFF``. To enter the deep sleep again after the OTA update send a message on the topic ``livingroom/sleep_mode`` with payload ``ON``. Deep sleep will start immediately. Don't forget to delete the payload before the node wakes up again. diff --git a/components/display/index.rst b/components/display/index.rst index 435ccdc80..59bfdb77f 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -374,8 +374,8 @@ RGB displays use red, green, and blue, while grayscale displays may use white. .. _display-graphs: -Graphs -****** +Graph Component +*************** You can display a graph of a sensor value(s) using this component. Examples: @@ -482,8 +482,8 @@ And then later in code: - Axis labels are currently not possible without manually placing them. - The grid and border color is set with it.graph(), while the traces are defined separately. -QR Codes -******** +QR Code Component +***************** Use this component to generate a QR-code containing a string on the device, which can then be drawn on compatible displays. @@ -500,10 +500,10 @@ Configuration variables: - **value** (**Required**, string): The string which you want to encode in the QR-code. - **ecc** (*Optional*, string): The error correction code level you want to use. Defaults to ``LOW``. You can use one of the following values: - - ``LOW`` - The QR Code can tolerate about 7% erroneous codewords - - ``MEDIUM`` - The QR Code can tolerate about 15% erroneous codewords - - ``QUARTILE`` - The QR Code can tolerate about 25% erroneous codewords - - ``HIGH`` - The QR Code can tolerate about 30% erroneous codewords + - ``LOW``: The QR Code can tolerate about 7% erroneous codewords + - ``MEDIUM``: The QR Code can tolerate about 15% erroneous codewords + - ``QUARTILE``: The QR Code can tolerate about 25% erroneous codewords + - ``HIGH``: The QR Code can tolerate about 30% erroneous codewords To draw the QR-code, call the ``it.qr_code`` function from your render lambda: @@ -641,14 +641,6 @@ Configuration variables: - ``GRAYSCALE``: Full scale grey. Uses 8 bits per pixel, 1 pixel per byte. - ``RGB24``: Full RGB color stored. Uses 3 bytes per pixel. -- **dither** (*Optional*): Specifies which dither method used to process each frame, only used in GRAYSCALE and BINARY type image. - Defaults to ``NONE``. You can read more about it `here `__ - and `here `__. - - - ``NONE``: Every pixel convert to its nearest color. - - ``FLOYDSTEINBERG``: Uses Floyd-Steinberg dither to approximate the original image luminosity levels. - - .. _display-pages: Display Pages diff --git a/components/display/ssd1306.rst b/components/display/ssd1306.rst index 235373238..74342a4c2 100644 --- a/components/display/ssd1306.rst +++ b/components/display/ssd1306.rst @@ -12,7 +12,7 @@ Over I²C The ``ssd1306_i2c`` display platform allows you to use SSD1306 (`datasheet `__, -`Adafruit `__), SSD1305 (`datasheet `__) +`Adafruit `__), SSD1305 (`datasheet `__) and SH1106 (`datasheet `__, `electrodragon `__) displays with ESPHome. Note that this component is for displays that are connected via the :ref:`I²C Bus `. @@ -48,7 +48,7 @@ Configuration variables: - **model** (**Required**): The model of the display. Options are: - - ``SSD1306 128x32`` (SSD1306 with 128 columns and 32 rows) + - ``SSD1306 128x32`` - SSD1306 with 128 columns and 32 rows - ``SSD1306 128x64`` - ``SSD1306 96x16`` - ``SSD1306 64x48`` diff --git a/components/display/ssd1325.rst b/components/display/ssd1325.rst index 8af7569c4..74324e065 100644 --- a/components/display/ssd1325.rst +++ b/components/display/ssd1325.rst @@ -49,7 +49,7 @@ Configuration variables: - **model** (**Required**): The model of the display. Options are: - - ``SSD1325 128x32`` (SSD1325 with 128 columns and 32 rows) + - ``SSD1325 128x32`` - SSD1325 with 128 columns and 32 rows - ``SSD1325 128x64`` - ``SSD1325 96x16`` - ``SSD1325 64x48`` diff --git a/components/display/ssd1351.rst b/components/display/ssd1351.rst index 0686ca264..526a65fb5 100644 --- a/components/display/ssd1351.rst +++ b/components/display/ssd1351.rst @@ -48,8 +48,8 @@ Configuration variables: - **model** (**Required**): The model of the display. Options are: - - ``SSD1351 128x128`` (SSD1351 with 128 columns and 128 rows) - - ``SSD1351 128x96`` (SSD1351 with 128 columns and 96 rows) + - ``SSD1351 128x128`` - SSD1351 with 128 columns and 128 rows + - ``SSD1351 128x96`` - SSD1351 with 128 columns and 96 rows - **dc_pin** (**Required**, :ref:`Pin Schema `): The DC pin. - **cs_pin** (**Required**, :ref:`Pin Schema `): The pin on the ESP that that the CS line is connected to. diff --git a/components/display/tm1637.rst b/components/display/tm1637.rst index dcb2d6da1..79b0b4d24 100644 --- a/components/display/tm1637.rst +++ b/components/display/tm1637.rst @@ -39,7 +39,7 @@ Configuration variables: - **intensity** (*Optional*, int): The intensity with which the TM1637 should drive the outputs. Range is from 0 (least intense) to 7 (the default). - **inverted** (*Optional*, bool): Invert character rendering to the TM1637 so you can physically flip the display around. -- **length** (*Optional*, int): The amount of digits your TM1637 is driving. Only required when `inverted: true` +- **length** (*Optional*, int): The amount of digits your TM1637 is driving. Only used when ``inverted: true`` Range is from 1 to 6 (the default). - **lambda** (*Optional*, :ref:`lambda `): The lambda to use for rendering the content on the TM1637. See :ref:`display-tm1637_lambda` for more information. diff --git a/components/display/waveshare_epaper.rst b/components/display/waveshare_epaper.rst index b681b861e..914805358 100644 --- a/components/display/waveshare_epaper.rst +++ b/components/display/waveshare_epaper.rst @@ -78,24 +78,24 @@ Configuration variables: - ``1.54in`` - ``1.54inv2`` - - ``2.13in`` (not tested) - - ``2.13in-ttgo`` (T5_V2.3 tested. Also works for Wemos D1 Mini ePaper Shield 2.13 1.0.0 "LOLIN") - - ``2.13in-ttgo-b73`` (T5_V2.3 with B73 display tested) - - ``2.13in-ttgo-b74`` (T5_V2.3.1 with B74 display tested) - - ``2.13in-ttgo-b1`` (T5_V2.3 with B1 display tested) - - ``2.13in-ttgo-dke`` (T5_V2.3 with DKE group display (DEPG0213BN) tested) - - ``2.70in`` (currently not working with the HAT Rev 2.1 version) + - ``2.13in`` - not tested + - ``2.13in-ttgo`` - T5_V2.3 tested. Also works for Wemos D1 Mini ePaper Shield 2.13 1.0.0 "LOLIN" + - ``2.13in-ttgo-b73`` - T5_V2.3 with B73 display tested + - ``2.13in-ttgo-b74`` - T5_V2.3.1 with B74 display tested + - ``2.13in-ttgo-b1`` - T5_V2.3 with B1 display tested + - ``2.13in-ttgo-dke`` - T5_V2.3 with DKE group display (DEPG0213BN) tested + - ``2.70in`` - currently not working with the HAT Rev 2.1 version - ``2.90in`` - ``2.90inv2`` - - ``2.90in-b`` (B/W rendering only) + - ``2.90in-b`` - B/W rendering only - ``4.20in`` - - ``4.20in-bV2`` (B/W rendering only) + - ``4.20in-bV2`` - B/W rendering only - ``5.83in`` - ``7.50in`` - - ``7.50in-bV2`` (also supports v3, B/W rendering only) - - ``7.50in-bc`` (display with version sticker '(C)' on the back, B/W rendering only) - - ``7.50inV2`` (Can't use with an ESP8266 as it runs out of RAM) - - ``7.50in-hd-b`` (Can't use with an ESP8266 as it runs out of RAM) + - ``7.50in-bV2`` - also supports v3, B/W rendering only + - ``7.50in-bc`` - display with version sticker '(C)' on the back, B/W rendering only + - ``7.50inV2`` - Can't use with an ESP8266 as it runs out of RAM + - ``7.50in-hd-b`` - Can't use with an ESP8266 as it runs out of RAM - **busy_pin** (*Optional*, :ref:`Pin Schema `): The BUSY pin. Defaults to not connected. - **reset_pin** (*Optional*, :ref:`Pin Schema `): The RESET pin. Defaults to not connected. diff --git a/components/esp32.rst b/components/esp32.rst index 755e907cb..32692f96f 100644 --- a/components/esp32.rst +++ b/components/esp32.rst @@ -23,7 +23,7 @@ Configuration variables: choose a generic board from Espressif such as ``esp32dev``. - **framework** (*Optional*): Options for the underlying framework used by ESPHome. See :ref:`esp32-arduino_framework` and :ref:`esp32-espidf_framework`. -- **variant** (*Optional*, boolean): The variant of the ESP32 that is used on this board. One of ``esp32``, +- **variant** (*Optional*, boolean): The variant of the ESP32 that is used on this board. One of ``esp32``, ``esp32s2``, ``esp32s3``, ``esp32c3`` and ``esp32h2``. Defaults to the variant that is detected from the board, if a board that's unknown to ESPHome is used, this option is mandatory. @@ -43,6 +43,9 @@ This is the default framework for ESP32 chips at the moment. type: arduino version: 2.0.0 +Configuration variables: +------------------------ + - **version** (*Optional*, string): The base framework version number to use, from `ESP32 arduino releases `__. Defaults to ``recommended``. Additional values are: @@ -76,6 +79,9 @@ of the ESP32 like ESP32S2, ESP32S3, ESP32C3 and single-core ESP32 chips. advanced: ignore_efuse_mac_crc: false +Configuration variables: +------------------------ + - **version** (*Optional*, string): The base framework version number to use, from `ESP32 ESP-IDF releases `__. Defaults to ``recommended``. Additional values are: diff --git a/components/ethernet.rst b/components/ethernet.rst index 7ff2b3f34..3c2ad0e45 100644 --- a/components/ethernet.rst +++ b/components/ethernet.rst @@ -54,7 +54,6 @@ Configuration variables: - **dns1** (*Optional*, IPv4 address): The main DNS server to use. - **dns2** (*Optional*, IPv4 address): The backup DNS server to use. -- **enable_mdns** (*Optional*, boolean): Controls if your node should advertise its presence and services using mDNS. When set to ``false`` you won't be able to access your node using its hostname which can break certain functionalities. Please see :ref:`notes on disabling mDNS `. Defaults to ``true``. - **use_address** (*Optional*, string): Manually override what address to use to connect to the ESP. Defaults to auto-generated value. For example, if you have changed your static IP and want to flash OTA to the previously configured IP address. @@ -69,7 +68,7 @@ Configuration variables: If your ethernet board is not designed with an ESP32 built in, chances are that you are going to use flying leads, dupont wires, etc. to connect the ethernet to the ESP32. This is probably to fail as the ethernet interface uses a high frequency clock signal. For more - information and wiring details refer to the the link in the *See also* section. + information and wiring details refer to the link in the *See also* section. Configuration for wESP32 board ------------------------------ diff --git a/components/fan/hbridge.rst b/components/fan/hbridge.rst index dc145aee9..19501f5c0 100644 --- a/components/fan/hbridge.rst +++ b/components/fan/hbridge.rst @@ -5,7 +5,7 @@ H-bridge Fan :description: Instructions for setting up hbridge controlled fans (or motors). :image: fan.svg -The ``hbridge`` fan platform allows you to use a compatible `h-bridge` (L298N, DRV8871, MX1508, BTS7960, L9110S, DRV8833, TB6612, etc.) to control a fan (or motor/solenoid). +The ``hbridge`` fan platform allows you to use a compatible *h-bridge* (L298N, DRV8871, MX1508, BTS7960, L9110S, DRV8833, TB6612, etc.) to control a fan (or motor/solenoid). .. figure:: images/L298N_module.jpg :align: center @@ -30,7 +30,7 @@ The ``hbridge`` fan platform allows you to use a compatible `h-bridge` (L298N, D - platform: ... id: motor_reverse_pin pin: GPIO4 - + fan: - platform: hbridge id: my_fan diff --git a/components/light/cwww.rst b/components/light/cwww.rst index 66fb02edb..43127cbc4 100644 --- a/components/light/cwww.rst +++ b/components/light/cwww.rst @@ -29,7 +29,7 @@ Mixing The two channels of this light can be controlled individually by using the ``cold_white`` and ``warm_white`` options of the :ref:`light control actions `. -If the color temperature of both lights is supplied, it is also possible to control the the two channels together by +If the color temperature of both lights is supplied, it is also possible to control the two channels together by setting a color temperature, using the ``white`` (interpreted as brightness) and ``color_temperature`` options. This calculation assumes that both lights have the same illuminance, which might not always be accurate. diff --git a/components/light/tuya.rst b/components/light/tuya.rst index 2c2ee3df5..9a2fa52b1 100644 --- a/components/light/tuya.rst +++ b/components/light/tuya.rst @@ -63,7 +63,7 @@ Configuration variables: maximum of 255, but dimmers with a maximum of 1000 can also be found. Try what works best. Defaults to 255. - **color_temperature_max_value** (*Optional*, int): The highest color temperature - value allowed. Some ceiling fans have a value of 100 (also for `max_value`). Defaults to 255. + value allowed. Some ceiling fans have a value of 100 (also for ``max_value``). Defaults to 255. - **color_temperature_invert** (*Optional*, boolean): Control how color temperature values are sent to the MCU. If this is set to true ESPHome will treat 0 as warm white and **color_temperature_max_value** as cool white when setting **color_temperature_datapoint**. @@ -79,7 +79,7 @@ Configuration variables: .. note:: The MCU on the Tuya dimmer handles transitions and gamma correction on its own. - Therefore the ``gamma_correct`` setting default is ``1.0`` and the the + Therefore the ``gamma_correct`` setting default is ``1.0`` and the ``default_transition_length`` parameter is ``0s`` by default. See Also diff --git a/components/lock/template.rst b/components/lock/template.rst index da81965c1..bd88d7f5a 100644 --- a/components/lock/template.rst +++ b/components/lock/template.rst @@ -37,7 +37,7 @@ Possible return values for the optional lambda: - ``return LOCK_STATE_LOCKING;`` if the lock should be reported as LOCKING. - ``return LOCK_STATE_UNLOCKING;`` if the lock should be reported as UNLOCKING. - ``return {};`` if the last state should be repeated. - + .. note:: Only ``LOCK_STATE_LOCKED`` and ``LOCK_STATE_UNLOCKED`` are supported by the MQTT component in Home Assistant @@ -52,8 +52,6 @@ Configuration variables: be performed when the remote (like Home Assistant's frontend) requests the lock to be locked. - **unlock_action** (*Optional*, :ref:`Action `): The action that should be performed when the remote (like Home Assistant's frontend) requests the lock to be unlocked. -- **restore_state** (*Optional*, boolean): Sets whether ESPHome should attempt to restore the - state on boot-up and call the lock/unlock actions with the recovered values. Defaults to ``no``. - **optimistic** (*Optional*, boolean): Whether to operate in optimistic mode - when in this mode, any command sent to the template lock will immediately update the reported state. Defaults to ``false``. diff --git a/components/modbus.rst b/components/modbus.rst index 5d06f7e6d..3b1b07695 100644 --- a/components/modbus.rst +++ b/components/modbus.rst @@ -24,13 +24,13 @@ Configuration variables: ------------------------ - **flow_control_pin** (*Optional*, :ref:`config-pin`): The pin used to switch flow control. - This is useful for RS485 transeivers that do not have automatic flow control switching, - like the common MAX485. + This is useful for RS485 transceivers that do not have automatic flow control switching, + like the common MAX485. - **send_wait_time** (*Optional*, :ref:`config-time`): Time in milliseconds before a new modbus command is sent if an answer from a previous command is pending. Defaults to 250 ms. - If multiple modbus devices are attached increasing this value can help avoiding to to overlapping reads. - When 2 devices are sending a command at the same the the response read from uart can't be assigend to the proper design. - This value defines the maximumm queuing time for a command before it is send anyways. + If multiple modbus devices are attached increasing this value can help avoiding to to overlapping reads. + When 2 devices are sending a command at the same the response read from uart can't be assigned to the proper design. + This value defines the maximum queuing time for a command before it is send anyways. See Also diff --git a/components/mqtt.rst b/components/mqtt.rst index 387c8cd25..3d9a75344 100644 --- a/components/mqtt.rst +++ b/components/mqtt.rst @@ -58,6 +58,12 @@ Configuration variables: ````. - **log_topic** (*Optional*, :ref:`mqtt-message`): The topic to send MQTT log messages to. + + The ``log_topic`` has an additional configuration option: + + - **level** (*Optional*, string): The log level to use for MQTT logs. See + :ref:`logger-log_levels` for options. + - **birth_message** (*Optional*, :ref:`mqtt-message`): The message to send when a connection to the broker is established. See :ref:`mqtt-last_will_birth` for more information. - **will_message** (*Optional*, :ref:`mqtt-message`): The message to send when @@ -113,12 +119,6 @@ Configuration options: - **retain** (*Optional*, boolean): If the published message should have a retain flag on or not. Defaults to ``true``. - -The ``log_topic`` has an additional configuration option: - -- **level** (*Optional*, string): The log level to use for MQTT logs. See - :ref:`logger-log_levels` for options. - .. _mqtt-using_with_home_assistant: Using with Home Assistant diff --git a/components/number/modbus_controller.rst b/components/number/modbus_controller.rst index 1219fa834..9c5291c3b 100644 --- a/components/number/modbus_controller.rst +++ b/components/number/modbus_controller.rst @@ -12,77 +12,71 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. -- **address**: (**Required**, int): start address of the first register in a range -- **value_type**: (**Required**): datatype of the mod_bus register data. The default data type for modbus is a 16 bit integer in big endian format (MSB first) - - U_WORD (unsigned 16 bit integer from 1 register = 16bit) - - S_WORD (signed 16 bit integer from 1 register = 16bit) - - U_DWORD (unsigned 32 bit integer from 2 registers = 32bit) - - S_DWORD (signed 32 bit integer from 2 registers = 32bit) - - U_DWORD_R (unsigned 32 bit integer from 2 registers low word first) - - S_DWORD_R (signed 32 bit integer from 2 registers low word first) - - U_QWORD (unsigned 64 bit integer from 4 registers = 64bit) - - S_QWORD (unsigned 64 bit integer from 4 registers = 64bit) - - U_QWORD_R (unsigned 64 bit integer from 4 registers low word first) - - U_QWORD_R signed 64 bit integer from 4 registers low word first) - - FP32 (32 bit IEEE 754 floating point from 2 registers) - - FP32_R (32 bit IEEE 754 floating point - same as FP32 but low word first) +- **address** (**Required**, int): start address of the first register in a range +- **value_type** (**Required**): datatype of the mod_bus register data. The default data type for modbus is a 16 bit integer in big endian format (MSB first) -- **skip_updates**: (*Optional*, int): By default all sensors of of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle - Note: The modbus_controller groups component by address ranges to reduce number of transactions. All compoents with the same address will be updated in one request. skip_updates applies for all components in the same range. -- **register_count**: (*Optional*): only required for uncommon response encodings or to :ref:`optimize modbus communications` - The number of registers this data point spans. Overrides the defaults determined by ``value_type``. - If no value for ``register_count`` is provided, it is calculated based on the register type. + - ``U_WORD`` (unsigned 16 bit integer from 1 register = 16bit) + - ``S_WORD`` (signed 16 bit integer from 1 register = 16bit) + - ``U_DWORD`` (unsigned 32 bit integer from 2 registers = 32bit) + - ``S_DWORD`` (signed 32 bit integer from 2 registers = 32bit) + - ``U_DWORD_R`` (unsigned 32 bit integer from 2 registers low word first) + - ``S_DWORD_R`` (signed 32 bit integer from 2 registers low word first) + - ``U_QWORD`` (unsigned 64 bit integer from 4 registers = 64bit) + - ``S_QWORD`` (unsigned 64 bit integer from 4 registers = 64bit) + - ``U_QWORD_R`` (unsigned 64 bit integer from 4 registers low word first) + - ``U_QWORD_R`` signed 64 bit integer from 4 registers low word first) + - ``FP32`` (32 bit IEEE 754 floating point from 2 registers) + - ``FP32_R`` (32 bit IEEE 754 floating point - same as FP32 but low word first) - The default size for 1 register is 16 bits (1 Word). Some devices are not adhering to this convention and have registers larger than 16 bits. In this case ``register_count`` and ``response_size`` must be set. For example, if your modbus device uses 1 registers for a FP32 value instead the default of two set ``register_count: 1`` and ``response_size: 4``. -- **response_size**: (*Optional*): Size of the response for the register in bytes. Defaults to register_count*2. -- **force_new_range**: (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting ``force_new_range: true`` enforces the start of a new range at that address. -- **offset**: (*Optional*, int): only required for uncommon response encodings - offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type +- **skip_updates** (*Optional*, int): By default all sensors of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle + Note: The modbus_controller groups component by address ranges to reduce number of transactions. All components with the same address will be updated in one request. skip_updates applies for all components in the same range. +- **response_size** (*Optional*): Size of the response for the register in bytes. Defaults to register_count*2. +- **force_new_range** (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting ``force_new_range: true`` enforces the start of a new range at that address. +- **offset** (*Optional*, int): only required for uncommon response encodings offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type - **min_value** (*Optional*, float): The minimum value this number can be. - **max_value** (*Optional*, float): The maximum value this number can be. - **step** (*Optional*, float): The granularity with which the number can be set. Defaults to 1 -- **custom_data** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_data`` is used ``address`` and ``register_type`` can't be used. +- **custom_command** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_command`` is used ``address`` and ``register_type`` can't be used. custom data must contain all required bytes including the modbus device address. The crc is automatically calculated and appended to the command. - See :ref:`modbus_custom_data` how to use ``custom_command`` + See :ref:`modbus_custom_command` how to use ``custom_command`` - **lambda** (*Optional*, :ref:`lambda `): Lambda to be evaluated every update interval to get the new value of the sensor. + + Parameters passed into the lambda + + - **x** (float): The parsed float value of the modbus data + - **data** (std::vectoroffset]`` to get the first response byte for your sensor. + - **item** (const pointer to a SensorItem derived object): The sensor object itself. + + Possible return values for the lambda: + + - ``return ;`` the new value for the sensor. + - ``return NAN;`` if the state should be considered invalid to indicate an error (advanced). + + - **write_lambda** (*Optional*, :ref:`lambda `): Lambda called before send. Lambda is evaluated before the modbus write command is created. + + Parameters passed into the lambda + + - **x** (float): The float value to be sent to the modbus device + - **payload** (``std::vector&payload``): empty vector for the payload. The lambda can add 16 bit raw modbus register words. + *note:* because the response contains data for all registers in the same range you have to use ``data[item->offset]`` to get the first response byte for your sensor. + - **item** (const pointer to a SensorItem derived object): The sensor object itself. + + Possible return values for the lambda: + + - ``return ;`` the new value for the sensor. + - ``return ; and fill payload with data`` if the payload is added from the lambda then these 16 bit words will be sent + - ``return {};`` if you don't want write the command to the device (or do it from the lambda). + - **multiply** (*Optional*, float): multiply the new value with this factor before sending the requests. Ignored if lambda is defined. -- **use_write_multiple**: (*Optional*, boolean): By default the modbus command ``Preset Single Registers`` (function code 6) is used for setting the holding register if only 1 register is set. If your device only supports ``Preset Multiple Registers`` (function code 16) set this option to true. +- **use_write_multiple** (*Optional*, boolean): By default the modbus command ``Preset Single Registers`` (function code 6) is used for setting the holding register if only 1 register is set. If your device only supports ``Preset Multiple Registers`` (function code 16) set this option to true. All other options from :ref:`Number `. -Parameters passed into the lambda - -- **x** (float): The parsed float value of the modbus data - -- **data** (std::vectoroffset]`` to get the first response byte for your sensor. -- **item** (const pointer to a SensorItem derived object): The sensor object itself. - -Possible return values for the lambda: - - - ``return ;`` the new value for the sensor. - - ``return NAN;`` if the state should be considered invalid to indicate an error (advanced). - - - -**Parameters passed into write_lambda** - -- **x** (float): The float value to be sent to the modbus device - -- **payload** (`std::vector&payload`): empty vector for the payload. The lamdba can add 16 bit raw modbus register words. - note: because the response contains data for all registers in the same range you have to use ``data[item->offset]`` to get the first response byte for your sensor. -- **item** (const pointer to a SensorItem derived object): The sensor object itself. - -Possible return values for the lambda: - - - ``return ;`` the new value for the sensor. - - ``return ; and fill payload with data`` if the payload is added from the lambda then these 16 bit words will be sent - - ``return {};`` if you don't want write the command to the device (or do it from the lambda). - **Example** .. code-block:: yaml diff --git a/components/output/ac_dimmer.rst b/components/output/ac_dimmer.rst index e17580e32..b70474852 100644 --- a/components/output/ac_dimmer.rst +++ b/components/output/ac_dimmer.rst @@ -56,7 +56,7 @@ Configuration variables: detector, in such case duplicate the ``zero_cross_pin`` config on each output. - **method** (*Optional*): Set the method for dimming, can be: - - ``leading pulse`` (default): a short pulse to trigger a triac. + - ``leading pulse``: (default) a short pulse to trigger a triac. - ``leading``: gate pin driven high until the zero cross is detected - ``trailing``: gate pin driven high from zero cross until dim period, this method is suitable for mosfet dimmers only. diff --git a/components/output/mcp4725.rst b/components/output/mcp4725.rst index c337bc892..384dde37a 100644 --- a/components/output/mcp4725.rst +++ b/components/output/mcp4725.rst @@ -46,7 +46,7 @@ Usage with voltages higher than 3.3v In order to drive analog modules with voltages higher than 3.3v, use a `TTL bi-directionnal level converter `__ -Be careful about what converter you use, some of of them have channels labeled with `RX` and `TX`, +Be careful about what converter you use, some of them have channels labeled with `RX` and `TX`, in this case only `TX` channels are bi-directional (so you must use 2 `TX` channels for I2C to work). See Also diff --git a/components/output/mcp4728.rst b/components/output/mcp4728.rst index 567a6a1da..538746849 100644 --- a/components/output/mcp4728.rst +++ b/components/output/mcp4728.rst @@ -1,5 +1,5 @@ -MCP4728 Output -============== +MCP4728 Component +================= .. seo:: :description: Instructions for setting up MCP4728 outputs on the ESP. @@ -34,8 +34,8 @@ Configuration variables: the DAC. Defaults to ``0x60``. - **store_in_eeprom** (*Optional*, boolean): Use SEQ_WRITE mode to also write to EEPROM sequentially. Defaults to ``false``. -Output -****** +MCP4728 Output +************** The MCP4728 output component exposes 4 MCP4728 channels of a global :ref:`MCP4728 ` as float outputs. @@ -84,9 +84,9 @@ Configuration variables: Use this if you have multiple MCP4728 chains you want to use at the same time. - **channel** (**Required**, string): Chose the channel of the MCP4728 chain of this output component. One of ``A``, ``B``, ``C`` or ``D``. -- **vref** (**Optional**, string): Chose the VREF source. One of ``vdd`` or ``internal``. Defaults to ``vdd``. -- **gain** (**Optional**, string): Chose the GAIN multiplier for internal VREF. One of ``X1`` or ``X2``. Only useful when ``vdd=internal``. Defaults to ``X1``. -- **power_down** (**Optional**, string): Chose the power down mode. In power down mode (value different from ``normal``) the output pin will be connected to GND using a resistor (1kOhm, 100kOhm or 500kOhm). One of ``normal``, ``gnd_1k``, ``gnd_100k`` or ``gnd_500k``. Defaults to ``normal``. +- **vref** (*Optional*, string): Chose the VREF source. One of ``vdd`` or ``internal``. Defaults to ``vdd``. +- **gain** (*Optional*, string): Chose the GAIN multiplier for internal VREF. One of ``X1`` or ``X2``. Only useful when ``vdd=internal``. Defaults to ``X1``. +- **power_down** (*Optional*, string): Chose the power down mode. In power down mode (value different from ``normal``) the output pin will be connected to GND using a resistor (1kOhm, 100kOhm or 500kOhm). One of ``normal``, ``gnd_1k``, ``gnd_100k`` or ``gnd_500k``. Defaults to ``normal``. - All other options from :ref:`Output `. Output voltage range will be different depending on the ``vref`` source and ``gain``. diff --git a/components/output/modbus_controller.rst b/components/output/modbus_controller.rst index c923edd3e..3318fa50c 100644 --- a/components/output/modbus_controller.rst +++ b/components/output/modbus_controller.rst @@ -11,54 +11,53 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. -- **address**: (**Required**, int): start address of the first register in a range -- **value_type**: (**Required**): datatype of the mod_bus register data. The default data type for modbus is a 16 bit integer in big endian format (MSB first) - - U_WORD (unsigned 16 bit integer from 1 register = 16bit) - - S_WORD (signed 16 bit integer from 1 register = 16bit) - - U_DWORD (unsigned 32 bit integer from 2 registers = 32bit) - - S_DWORD (signed 32 bit integer from 2 registers = 32bit) - - U_DWORD_R (unsigned 32 bit integer from 2 registers low word first) - - S_DWORD_R (signed 32 bit integer from 2 registers low word first) - - U_QWORD (unsigned 64 bit integer from 4 registers = 64bit) - - S_QWORD (unsigned 64 bit integer from 4 registers = 64bit) - - U_QWORD_R (unsigned 64 bit integer from 4 registers low word first) - - U_QWORD_R signed 64 bit integer from 4 registers low word first) - - FP32 (32 bit IEEE 754 floating point from 2 registers) - - FP32_R (32 bit IEEE 754 floating point - same as FP32 but low word first) -- **register_count**: (*Optional*): only required for uncommon response encodings - The number of registers this data point spans. Default is 1 +- **address** (**Required**, int): start address of the first register in a range +- **value_type** (**Required**): datatype of the modbus register data. The default data type for modbus is a 16 bit integer in big endian format (MSB first) + + - ``U_WORD`` (unsigned 16 bit integer from 1 register = 16bit) + - ``S_WORD`` (signed 16 bit integer from 1 register = 16bit) + - ``U_DWORD`` (unsigned 32 bit integer from 2 registers = 32bit) + - ``S_DWORD`` (signed 32 bit integer from 2 registers = 32bit) + - ``U_DWORD_R`` (unsigned 32 bit integer from 2 registers low word first) + - ``S_DWORD_R`` (signed 32 bit integer from 2 registers low word first) + - ``U_QWORD`` (unsigned 64 bit integer from 4 registers = 64bit) + - ``S_QWORD`` (unsigned 64 bit integer from 4 registers = 64bit) + - ``U_QWORD_R`` (unsigned 64 bit integer from 4 registers low word first) + - ``U_QWORD_R`` signed 64 bit integer from 4 registers low word first) + - ``FP32`` (32 bit IEEE 754 floating point from 2 registers) + - ``FP32_R`` (32 bit IEEE 754 floating point - same as FP32 but low word first) + - **write_lambda** (*Optional*, :ref:`lambda `): Lambda is evaluated before the modbus write command is created. The value is passed in as ``float x`` and an empty vector is passed in as ``std::vector&payload``. You can directly define the payload by adding data to payload then the return value is ignored and the content of payload is used. + + Parameters passed into the lambda + + - **x** (float): The float value to be sent to the modbus device for ``register_type: holding`` + - **x** (bool): The boolean value to be sent to the modbus device for ``register_type: coil`` + - **payload** (```std::vector&payload```): + + - for ``register_type: holding``: empty vector for the payload. The lamdba can add 16 bit raw modbus register words. + - for ``register_type: coil``: empty vector for the payload. If payload is set in the lambda it is sent as a custom command and must include all required bytes for a modbus request + note: because the response contains data for all registers in the same range you have to use ``data[item->offset]`` to get the first response byte for your sensor. + + - **item** (const pointer to a SensorItem derived object): The sensor object itself. + + Possible return values for the lambda: + + - ``return ;`` the new value for the sensor. + - ``return ; and fill payload with data`` if the payload is added from the lambda then these 16 bit words will be sent + - ``return {};`` if you don't want write the command to the device (or do it from the lambda). + - **register_type** (*Optional*): ``coil`` to create a binary outout or ``holding`` to create a float output. - **multiply** (*Optional*, float): multiply the new value with this factor before sending the requests. Ignored if lambda is defined. Only valid for ``register_type: holding``. -- **offset**: (*Optional*, int): only required for uncommon response encodings - offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type -- **use_write_multiple**: (*Optional*, boolean): By default the modbus command ``Preset Single Registers`` (function code 6) is used for setting the holding register if only 1 register is set. If your device only supports ``Preset Multiple Registers`` (function code 16) set this option to true. +- **offset** (*Optional*, int): only required for uncommon response encodings + offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type +- **use_write_multiple** (*Optional*, boolean): By default the modbus command ``Preset Single Registers`` (function code 6) is used for setting the holding register if only 1 register is set. If your device only supports ``Preset Multiple Registers`` (function code 16) set this option to true. All other options from :ref:`Output `. -**Parameters passed into the lambda** - -- **x** (float): The float value to be sent to the modbus device for ``register_type: holding`` -- **x** (bool): The boolean value to be sent to the modbus device for ``register_type: coil`` - -- **payload** (`std::vector&payload`): - - - for ``register_type: holding``: empty vector for the payload. The lamdba can add 16 bit raw modbus register words. - - for ``register_type: coil``: empty vector for the payload. If payload is set in the lambda it is sent as a custom command and must include all required bytes for a modbus request - note: because the response contains data for all registers in the same range you have to use ``data[item->offset]`` to get the first response byte for your sensor. - -- **item** (const pointer to a SensorItem derived object): The sensor object itself. - -Possible return values for the lambda: - - - ``return ;`` the new value for the sensor. - - ``return ; and fill payload with data`` if the payload is added from the lambda then these 16 bit words will be sent - - ``return {};`` if you don't want write the command to the device (or do it from the lambda). - - **Example** .. code-block:: yaml diff --git a/components/output/pca9685.rst b/components/output/pca9685.rst index 2bd61347b..20ae7408f 100644 --- a/components/output/pca9685.rst +++ b/components/output/pca9685.rst @@ -45,8 +45,8 @@ Configuration variables: .. _pca9685-output: -PWM Output ----------- +PCA9685 Output +-------------- The PCA9685 output component exposes a PCA9685 PWM channel of a global :ref:`PCA9685 hub ` as a float diff --git a/components/output/slow_pwm.rst b/components/output/slow_pwm.rst index ccb3781ca..6f3ec6f83 100644 --- a/components/output/slow_pwm.rst +++ b/components/output/slow_pwm.rst @@ -34,12 +34,12 @@ Configuration variables: - **period** (**Required**, :ref:`config-time`): The duration of each cycle. (i.e. a 10s period at 50% duty would result in the pin being turned on for 5s, then off for 5s) - **pin** (*Optional*, :ref:`Pin Schema `): The pin to pulse. -- **state_change_action** (*Optional*, :ref:`Automation `): An automation to perform when the load is switched. If a lambda is used the boolean ``state`` parameter holds the new status. -- **turn_on_action** (*Optional*, :ref:`Automation `): An automation to perform when the load is turned on. Can be used to control for example a switch or output component. +- **state_change_action** (*Optional*, :ref:`Automation `): An automation to perform when the load is switched. If a lambda is used the boolean ``state`` parameter holds the new status. +- **turn_on_action** (*Optional*, :ref:`Automation `): An automation to perform when the load is turned on. Can be used to control for example a switch or output component. - **turn_off_action** (*Optional*, :ref:`Automation `): An automation to perform when the load is turned off. ``turn_on_action`` and ``turn_off_action`` must be configured together. - **restart_cycle_on_state_change** (*Optional*, boolean): Restart a timer of a cycle when new state is set. Defaults to ``false``. - + - All other options from :ref:`Output `. diff --git a/components/output/tlc59208f.rst b/components/output/tlc59208f.rst index dfa28c77d..97a4276ae 100644 --- a/components/output/tlc59208f.rst +++ b/components/output/tlc59208f.rst @@ -8,8 +8,8 @@ TLC59208F .. _tlc59208f-component: -Component ---------- +Component/Hub +------------- The TLC59208F component represents a Texas Instruments TLC59208F 8-bit PWM driver (`datasheet `__, @@ -43,8 +43,8 @@ Configuration variables: .. _tlc59208f-output: -PWM Output ----------- +TLC59208F Output +---------------- The TLC59208F output component exposes a TLC59208F PWM channel of a global :ref:`TLC59208F chip ` as a float @@ -86,7 +86,7 @@ output. id: 'tlc59208f_3_ch7' channel: 7 tlc59208f_id: 'tlc59208f_3' - + # Sample use as a RGB light light: - platform: rgb diff --git a/components/pipsolar.rst b/components/pipsolar.rst index 5524cf0e7..d7f20ca46 100644 --- a/components/pipsolar.rst +++ b/components/pipsolar.rst @@ -5,14 +5,14 @@ PipSolar PV Inverter :description: Instructions for setting up PipSolar Compatible PV Inverter in ESPHome. :image: pipsolar.jpg -The PipSolar component allows you to integrate PIP-compatible Inverters in ESPHome. +The PipSolar component allows you to integrate PIP-compatible Inverters in ESPHome. It uses :ref:`UART ` for communication. Once configured, you can use sensors, binary sensors, switches and outputs as described below for your projects. .. warning:: - All functionality is working fine on esp8266 and esp32 chips. + All functionality is working fine on esp8266 and esp32 chips. If you configure a lot of the possible sensors etc. from below it could be that you run out of memory (on esp8266). If you configure more than one if this devices with nearly all sensors etc. you run in a stack-size issue. In this case you have to increase stack size. @@ -54,8 +54,8 @@ Configuration variables: - **id** (**Required**, :ref:`config-id`): The id to use for this pipsolar component. - **uart_id** (*Optional*): The uart Bus ID -Sensors -------- +Sensor +------ .. code-block:: yaml # Example configuration entry @@ -121,15 +121,13 @@ All sensors are normal sensors... so all sensor variables are working to. - **pv_input_voltage** (*Optional*): pv input voltage - **battery_voltage_scc** (*Optional*): battery voltage from scc - **battery_discharge_current** (*Optional*): battery discharge current -- **add_sbu_priority_version** (*Optional*): add sbu priority status -- **configuration_status** (*Optional*): configuration status -- **scc_firmware_version** (*Optional*): scc firmware version - **battery_voltage_offset_for_fans_on** (*Optional*): battery voltage offset for fans on - **eeprom_version** (*Optional*): eeprom version - **pv_charging_power** (*Optional*): pc charging power -Binary Sensors --------------- +Binary Sensor +------------- + .. code-block:: yaml # Example configuration entry @@ -205,8 +203,9 @@ All sensors are normal binary sensors... so all binary sensor variables are work - **warning_high_ac_input_during_bus_soft_start** (*Optional*): warning high ac input during bus soft start - **warning_battery_equalization** (*Optional*): warning battery equalization -Text Sensors ------------- +Text Sensor +----------- + .. code-block:: yaml # Example configuration entry @@ -234,9 +233,10 @@ All sensors are normal text sensors... so all text sensor variables are working - **last_qt** (*Optional*): last qt reponse - **last_qmn** (*Optional*): last qmn reponse -Switches --------- -Not all possible switches are exposed as they lead to the possibility to make serious damage. They should only be set at the physical device itself. +Switch +------ + +Not all possible switches are exposed as they lead to the possibility to make serious damage. They should only be set at the physical device itself. .. code-block:: yaml @@ -265,12 +265,13 @@ All sensors are normal text sensors... so all text sensor variables are working - **output_source_priority_solar** (*Optional*): output source priority solar - **output_source_priority_battery** (*Optional*): output source priority battery - **input_voltage_range** (*Optional*): input voltage range -- **pv_ok_condition_for_parallel** (*Optional*): pv ok condition for parallel +- **pv_ok_condition_for_parallel** (*Optional*): pv ok condition for parallel - **pv_power_balance** (*Optional*): pv power balance -Outputs --------------- -Not all possible outputs are exposed as they lead to the possibility to make serious damage. They should only be set at the physical device itself. +Output +------ + +Not all possible outputs are exposed as they lead to the possibility to make serious damage. They should only be set at the physical device itself. .. code-block:: yaml @@ -287,31 +288,31 @@ All sensors are normal text sensors... so all text sensor variables are working - **battery_recharge_voltage** (*Optional*): battery recharge voltage; - - **possible_values** (*Optional*,list): a list of possible values default: 44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0 + - **possible_values** (*Optional*, list): a list of possible values default: 44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0 - **battery_under_voltage** (*Optional*): battery under voltage; - - **possible_values** (*Optional*,list): a list of possible values default: 40.0,40.1,42,43,44,45,46,47,48.0 + - **possible_values** (*Optional*, list): a list of possible values default: 40.0,40.1,42,43,44,45,46,47,48.0 - **battery_float_voltage** (*Optional*): battery float voltage; - - **possible_values** (*Optional*,list): a list of possible values default: 48.0,49.0,50.0,51.0 + - **possible_values** (*Optional*, list): a list of possible values default: 48.0,49.0,50.0,51.0 - **battery_type** (*Optional*): battery type; - - **possible_values** (*Optional*,list): a list of possible values default: 0,1,2 + - **possible_values** (*Optional*, list): a list of possible values default: 0,1,2 - **current_max_ac_charging_current** (*Optional*): current max ac charging current; - - **possible_values** (*Optional*,list): a list of possible values default: 2,10,20 + - **possible_values** (*Optional*, list): a list of possible values default: 2,10,20 - **current_max_charging_current** (*Optional*): current max charging current; - - **possible_values** (*Optional*,list): a list of possible values default: 10,20,30,40 + - **possible_values** (*Optional*, list): a list of possible values default: 10,20,30,40 - **output_source_priority** (*Optional*): output source priority; - - **possible_values** (*Optional*,list): a list of possible values default: 0,1,2 + - **possible_values** (*Optional*, list): a list of possible values default: 0,1,2 - **charger_source_priority** (*Optional*): charger source priority; - - **possible_values** (*Optional*,list): a list of possible values default: 0,1,2,3 + - **possible_values** (*Optional*, list): a list of possible values default: 0,1,2,3 - **battery_redischarge_voltage** (*Optional*): battery redischarge voltage; - - **possible_values** (*Optional*,list): a list of possible values default: 00.0,48.0,49,50.0,51.0,52,53,54,55,56,57,58 + - **possible_values** (*Optional*, list): a list of possible values default: 00.0,48.0,49,50.0,51.0,52,53,54,55,56,57,58 .. _pipsolaroutput_set_level_action: @@ -333,7 +334,7 @@ target level of the output. Configuration options: - **id** (**Required**, :ref:`config-id`): The ID of the output. -- **level** (*Optional*, percentage, :ref:`templatable `): The target level. +- **value** (*Optional*, percentage, :ref:`templatable `): The target level. See Also diff --git a/components/remote_receiver.rst b/components/remote_receiver.rst index af1a4e8e3..69b2f44cc 100644 --- a/components/remote_receiver.rst +++ b/components/remote_receiver.rst @@ -89,7 +89,7 @@ Automations: .. note:: In version 2021.12, the order of transferring bits was corrected from MSB to LSB in accordance with the NEC standard. - Therefore, if the the configuration file has come from an earlier version of ESPhome, it is necessary to reverse the order of the address and command bits when moving to 2021.12 or above. + Therefore, if the configuration file has come from an earlier version of ESPhome, it is necessary to reverse the order of the address and command bits when moving to 2021.12 or above. For example, address: 0x84ED, command: 0x13EC becomes 0xB721 and 0x37C8 respectively. - **on_nexa** (*Optional*, :ref:`Automation `): An automation to perform when a @@ -190,7 +190,7 @@ Remote code selection (exactly one of these has to be included): .. note:: In version 2021.12, the order of transferring bits was corrected from MSB to LSB in accordance with the NEC standard. - Therefore, if the the configuration file has come from an earlier version of ESPhome, it is necessary to reverse the order of the address and command bits when moving to 2021.12 or above. + Therefore, if the configuration file has come from an earlier version of ESPhome, it is necessary to reverse the order of the address and command bits when moving to 2021.12 or above. For example, address: 0x84ED, command: 0x13EC becomes 0xB721 and 0x37C8 respectively. - **address** (**Required**, int): The address to trigger on, see dumper output for more info. diff --git a/components/remote_transmitter.rst b/components/remote_transmitter.rst index 1eb9be778..827f84907 100644 --- a/components/remote_transmitter.rst +++ b/components/remote_transmitter.rst @@ -159,7 +159,7 @@ Configuration variables: ``remote_transmitter.transmit_magiquest`` Action ************************************************ -This :ref:`action ` sends a MagiQuest wand code to a remote transmitter. +This :ref:`action ` sends a MagiQuest wand code to a remote transmitter. .. code-block:: yaml @@ -200,7 +200,7 @@ This :ref:`action ` sends an NEC infrared remote code to a remote .. note:: In version 2021.12, the order of transferring bits was corrected from MSB to LSB in accordance with the NEC standard. - Therefore, if the the configuration file has come from an earlier version of ESPhome, it is necessary to reverse the order of the address and command bits when moving to 2021.12 or above. + Therefore, if the configuration file has come from an earlier version of ESPhome, it is necessary to reverse the order of the address and command bits when moving to 2021.12 or above. For example, address: 0x84ED, command: 0x13EC becomes 0xB721 and 0x37C8 respectively. .. code-block:: yaml @@ -576,6 +576,10 @@ Configuration variables: This :ref:`action ` sends a Toshiba AC infrared remote code to a remote transmitter. +.. note:: + + This action transmits codes using the new(er) Toshiba AC protocol and likely will not work with older units. + .. code-block:: yaml on_...: @@ -588,7 +592,7 @@ Configuration variables: - **rc_code_1** (**Required**, int): The remote control code to send, see dumper output for more details. - **rc_code_2** (*Optional*, int): The secondary remote control code to send; some codes are sent in two parts. -- **Note:** this action transmits codes using the new(er) Toshiba AC protocol and likely will not work with older units. + - All other options from :ref:`remote_transmitter-transmit_action`. diff --git a/components/rtttl.rst b/components/rtttl.rst index 077edceb8..ea66970b4 100644 --- a/components/rtttl.rst +++ b/components/rtttl.rst @@ -59,7 +59,7 @@ Plays an rtttl tone. Configuration options: -- **play** (**Required**, string, :ref:`templatable `): The rtttl string. +- **rtttl** (**Required**, string, :ref:`templatable `): The rtttl string. You can find many rtttl strings online on the web, they must start with a name, then a colon: ``:`` symbol and more codes of the song itself. Tip: you can try playing with the values of d=16,o=6,b=95 and make the diff --git a/components/select/modbus_controller.rst b/components/select/modbus_controller.rst index c288418b5..05fd4f8e7 100644 --- a/components/select/modbus_controller.rst +++ b/components/select/modbus_controller.rst @@ -26,12 +26,13 @@ Configuration variables: ------------------------ - **name** (**Required**, string): The name of the Select. -- **address**: (**Required**, int): The start address of the first or only register +- **address** (**Required**, int): The start address of the first or only register of the Select. -- **optionsmap**: (**Required**, Map[str, int]): Provide a mapping from options (str) of +- **optionsmap** (**Required**, Map[str, int]): Provide a mapping from options (str) of this Select to values (int) of the modbus register and vice versa. All options and all values have to be unique. -- **value_type**: (*Optional*): The datatype of the modbus data. Defaults to ``U_WORD``. +- **value_type** (*Optional*): The datatype of the modbus data. Defaults to ``U_WORD``. + - ``U_WORD`` (unsigned 16 bit integer from 1 register = 16bit) - ``S_WORD`` (signed 16 bit integer from 1 register = 16bit) - ``U_DWORD`` (unsigned 32 bit integer from 2 registers = 32bit) @@ -42,24 +43,39 @@ Configuration variables: - ``S_QWORD`` (unsigned 64 bit integer from 4 registers = 64bit) - ``U_QWORD_R`` (unsigned 64 bit integer from 4 registers low word first) - ``U_QWORD_R`` (signed 64 bit integer from 4 registers low word first) -- **register_count**: (*Optional*): The number of registers which are used for this Select. Only - required for uncommon response encodings or to - :ref:`optimize modbus communications`. Overrides the defaults determined + +- **register_count** (*Optional*): The number of registers which are used for this Select. Only + required for uncommon response encodings or to + :ref:`optimize modbus communications`. Overrides the defaults determined by ``value_type``. -- **skip_updates**: (*Optional*, int): By default all sensors of of a modbus_controller are +- **skip_updates** (*Optional*, int): By default all sensors of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle. Defaults to ``0``. Note: The modbus_controller merges several registers into groups which are updated together. For each group the smallest update cycle is used. -- **force_new_range**: (*Optional*, boolean): If possible sensors with sequential addresses are - grouped together and requested in one range. Setting this to ``true`` enforces the start of a new +- **force_new_range** (*Optional*, boolean): If possible sensors with sequential addresses are + grouped together and requested in one range. Setting this to ``true`` enforces the start of a new range at that address. - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **lambda** (*Optional*, :ref:`lambda `): Lambda to be evaluated every update interval to get the current option of the select. + + Parameters passed into lambda + + - **x** (``int64_t``): The parsed integer value of the modbus data. + - **data** (``const std::vector&``): vector containing the complete raw modbus response bytes for this + sensor. Note: because the response contains data for all registers in the same range you have to + use ``data[item->offset]`` to get the first response byte for your sensor. + - **item** (``ModbusSelect*const``): The sensor object itself. + + Possible return values for the lambda: + + - ``return ;`` The new option for this Select. + - ``return {};`` Use default mapping (see ``optionsmap``). + - **write_lambda** (*Optional*, :ref:`lambda `): Lambda to be evaluated on every update of the Sensor, before the new value is written to the modbus registers. -- **use_write_multiple**: (*Optional*, boolean): By default the modbus command ``Preset Single Registers`` +- **use_write_multiple** (*Optional*, boolean): By default the modbus command ``Preset Single Registers`` (function code 6) is used for setting the holding register if only 1 register is set. If your device only supports *Preset Multiple Registers* (function code 16) set this option to ``true``. Defaults to ``false``. - **optimistic**: (*Optional*, boolean): Whether to operate in optimistic mode - when in this mode, @@ -68,19 +84,7 @@ Configuration variables: - All other options from :ref:`Select `. -Parameters passed into ``lambda`` ---------------------------------- -- **x** (``int64_t``): The parsed integer value of the modbus data. -- **data** (``const std::vector&``): vector containing the complete raw modbus response bytes for this - sensor. Note: because the response contains data for all registers in the same range you have to - use ``data[item->offset]`` to get the first response byte for your sensor. -- **item** (``ModbusSelect*const``): The sensor object itself. - -Possible return values for the lambda: - - - ``return ;`` The new option for this Select. - - ``return {};`` Use default mapping (see ``optionsmap``). .. code-block:: yaml diff --git a/components/sensor/airthings_ble.rst b/components/sensor/airthings_ble.rst index c7fcbb734..54ae15baf 100644 --- a/components/sensor/airthings_ble.rst +++ b/components/sensor/airthings_ble.rst @@ -1,5 +1,5 @@ AirThings BLE Sensors -======================== +===================== .. seo:: :description: Instructions for setting up AirThings bluetooth-based sensors in ESPHome. @@ -28,7 +28,7 @@ The device will then listen for nearby devices, and display a message like this .. code-block:: text - [D][airthings_ble:019]: + [D][airthings_ble:019]: Found AirThings device Serial: 123456789 (MAC: 01:02:03:04:05:06) Once the device is found, remove the ``airthings_ble`` device tracker from your configuration and take note of the device MAC address, and use it when configuring a sensor below. @@ -36,8 +36,8 @@ Once the device is found, remove the ``airthings_ble`` device tracker from your Supported Devices ----------------- -Wave Plus -********* +Airthings Wave Plus Sensor +************************** AirThings Wave Plus tracks radon (24h and long term), airborne chemicals, CO2, temperature, atmospheric pressure and humidity. @@ -76,8 +76,8 @@ Configuration example: esp32_ble_tracker: -Wave Mini -********* +Airthings Wave Mini Sensor +************************** AirThings Wave Mini tracks airborne chemicals, temperature, pressure and humidity. diff --git a/components/sensor/apds9960.rst b/components/sensor/apds9960.rst index af079f144..558d38830 100644 --- a/components/sensor/apds9960.rst +++ b/components/sensor/apds9960.rst @@ -66,11 +66,11 @@ Configuration variables: - **name** (**Required**, string): The name for the sensor. - **type** (**Required**, string): The type of sensor measurement. One of - - **CLEAR** - - **RED** - - **GREEN** - - **BLUE** - - **PROXIMITY** + - ``CLEAR`` + - ``RED`` + - ``GREEN`` + - ``BLUE`` + - ``PROXIMITY`` - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - All other options from :ref:`Sensor `. @@ -86,10 +86,10 @@ Configuration variables: - **name** (**Required**, string): The name for the binary sensor. - **direction** (**Required**, string): The direction to measure. One of: - - **UP** - - **DOWN** - - **LEFT** - - **RIGHT** + - ``UP`` + - ``DOWN`` + - ``LEFT`` + - ``RIGHT`` - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - All other options from :ref:`Binary Sensor `. diff --git a/components/sensor/ccs811.rst b/components/sensor/ccs811.rst index 20825bd3c..2ab3a2e43 100644 --- a/components/sensor/ccs811.rst +++ b/components/sensor/ccs811.rst @@ -54,7 +54,7 @@ Configuration variables: - **update_interval** (*Optional*, :ref:`config-time`): The interval to check the sensor. Defaults to ``60s``. -- **version:** (*Optional*): This sensor reports the firmware ('application') version in text, with the internal hex representation of the version number behind it, so version 1.0.0 will be reported as '1.0.0 (0x1000)'. +- **version** (*Optional*): This sensor reports the firmware ('application') version in text, with the internal hex representation of the version number behind it, so version 1.0.0 will be reported as '1.0.0 (0x1000)'. - **name** (**Required**, string): The name for the version sensor. diff --git a/components/sensor/daly_bms.rst b/components/sensor/daly_bms.rst index fcfd0cd15..4d8e9c562 100644 --- a/components/sensor/daly_bms.rst +++ b/components/sensor/daly_bms.rst @@ -1,5 +1,5 @@ -Daly BMS -======== +Daly BMS Sensor +=============== .. seo:: :description: Instructions for setting up a Daly Smart BMS @@ -23,10 +23,10 @@ The BMS communicates via :ref:`UART `. tx_pin: GPIO1 rx_pin: GPIO3 baud_rate: 9600 - + daly_bms: update_interval: 20s - + sensor: - platform: daly_bms voltage: @@ -72,8 +72,8 @@ The BMS communicates via :ref:`UART `. - platform: daly_bms status: name: "BMS Status" - - + + binary_sensor: - platform: daly_bms charging_mos_enabled: @@ -84,12 +84,14 @@ The BMS communicates via :ref:`UART `. Component/Hub ------------- -- **update_interval** (*Optional*, :ref:`config-time`): Delay between data requests. - Configuration variables: ************************ -Sensor: -------- + +- **update_interval** (*Optional*, :ref:`config-time`): Delay between data requests. + +Sensor +------ + A sensor platform to read BMS data Configuration variables: @@ -184,15 +186,16 @@ Configuration variables: - **name** (**Required**, string): The name for the second temperature sensor. - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - All other options from :ref:`Sensor `. - -- **cell_x_voltage** (*Optional*): The voltage of cell x. + +- **cell_1_voltage** (*Optional*): The voltage of cell number 1. Cell number can be from 1 to 16. - **name** (**Required**, string): The name for the cell voltage sensor. - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - All other options from :ref:`Sensor `. -Text Sensor: ------------- +Text Sensor +----------- + Text sensor that indicates the status of BMS. Configuration variables: @@ -204,8 +207,9 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - All other options from :ref:`Text Sensor `. -Binary Sensor: --------------- +Binary Sensor +------------- + Binary sensor that indicates the status of MOS. Configuration variables: @@ -223,8 +227,9 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - All other options from :ref:`Binary Sensor `. -UART Connection: ----------------- +UART Connection +--------------- + Connect RX from BMS to TX in ESP board and TX from BMS to RX in ESP board .. figure:: images/daly_bms_pinout.png diff --git a/components/sensor/kalman_combinator.rst b/components/sensor/kalman_combinator.rst index 24a2f7a38..8b51c85ef 100644 --- a/components/sensor/kalman_combinator.rst +++ b/components/sensor/kalman_combinator.rst @@ -45,7 +45,7 @@ Configuration variables: source must have either **error** or **error_function** set. These work like the **process_std_dev** parameter, with low values marking accurate data. - - **sensor** (**Required**, :ref:`config-id` of a :doc:`/components/sensor/index`): The + - **source** (**Required**, :ref:`config-id` of a :doc:`/components/sensor/index`): The sensor that is used as sample source - **error** (**Required**, float, :ref:`templatable `): The standard deviation of the sensor's measurements. If implemented as a template, the measurement is in diff --git a/components/sensor/ltr390.rst b/components/sensor/ltr390.rst index 592f36725..867ccff30 100644 --- a/components/sensor/ltr390.rst +++ b/components/sensor/ltr390.rst @@ -36,7 +36,7 @@ Configuration variables: - **gain** (*Optional*, string): Adjusts the sensitivity of the sensor. A larger value means higher sensitivity. See table below for details. Default is ``"X3"``. - **resolution** (*Optional*, int): ADC resolution. Higher resolutions require longer sensor integration times. See table below for details. Default is ``18``. - **window_correction_factor** (*Optional*, float): Window correction factor. Use larger values when using under tinted windows. Default is ``1.0``, must be ``>= 1.0``. -- **address** (*Optional*, int): Manually specify the I²C address of the sensor. Default is `0x53`. +- **address** (*Optional*, int): Manually specify the I²C address of the sensor. Default is ``0x53``. - **update_interval** (*Optional*, :ref:`config-time`): The interval to check the sensor. Defaults to ``60s``. It is recommended that the update interval is at least 1 second since updates can take up to 800ms when using a high resolution value. diff --git a/components/sensor/max9611.rst b/components/sensor/max9611.rst index 4f3b02428..5cfbd5ff5 100644 --- a/components/sensor/max9611.rst +++ b/components/sensor/max9611.rst @@ -8,10 +8,10 @@ MAX9611/9612 High Side Current+Voltage+Temperature Sensor The ``MAX9611`` sensor platform allows you to use your MAX9611/MAX9612 (`datasheet `__) -High-side current, voltage and temperature sensors with ESPHome. +High-side current, voltage and temperature sensors with ESPHome. -This sensor supports up to +60V DC common mode voltage, has a 1.8V to 3.3V logic range, -a 12-Bit integrated ADC with :ref:`I²C `, and is meant to act as a high-side current sense amplifier. +This sensor supports up to +60V DC common mode voltage, has a 1.8V to 3.3V logic range, +a 12-Bit integrated ADC with :ref:`I²C `, and is meant to act as a high-side current sense amplifier. The :ref:`I²C ` is required to be set up in your configuration for this sensor to work. @@ -43,19 +43,19 @@ required to be set up in your configuration for this sensor to work. Configuration variables: ------------------------ -- **shunt_resistance** (*Required*): The value of the High Side Shunt Resistor. +- **shunt_resistance** (**Required**, ohms): The value of the High Side Shunt Resistor. -- **Voltage** (*Optional*): The information for the voltage sensor +- **voltage** (*Optional*): The information for the voltage sensor - **name** (**Required**, string): The name for the voltage sensor. - All other options from :ref:`Sensor `. -- **Current** (*Optional*): The information for the current sensor, scaled by the gain factor and multiplied by voltage +- **current** (*Optional*): The information for the current sensor, scaled by the gain factor and multiplied by voltage - **name** (**Required**, string): The name for the current sensor. - All other options from :ref:`Sensor `. -- **Power** (*Optional*): The information for the power sensor +- **power** (*Optional*): The information for the power sensor - **name** (**Required**, string): The name for the power sensor. - All other options from :ref:`Sensor `. @@ -67,7 +67,7 @@ Configuration variables: - **address** (*Optional*, int): Manually specify the I²C address of - the sensor. Defaults to ``0x70``. + the sensor. Defaults to ``0x70``. - **update_interval** (*Optional*, :ref:`config-time`): The interval to check the sensor. Defaults to ``60s``. diff --git a/components/sensor/mlx90393.rst b/components/sensor/mlx90393.rst index 6ffbac5db..fb4700e24 100644 --- a/components/sensor/mlx90393.rst +++ b/components/sensor/mlx90393.rst @@ -40,12 +40,12 @@ Configuration variables: - **name** (**Required**, string): The name for the x-axis sensor. - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - **resolution** (*Optional*, int): Set resolution. Defaults to ``19BIT``. Must be one of: - + - ``16BIT`` - ``17BIT`` - ``18BIT`` - ``19BIT`` - + - All other options from :ref:`Sensor `. - **y_axis** (*Optional*): The information for the y-axis. @@ -53,12 +53,12 @@ Configuration variables: - **name** (**Required**, string): The name for the y-axis sensor. - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - **resolution** (*Optional*, int): Set resolution. Defaults to ``19BIT``. Must be one of: - + - ``16BIT`` - ``17BIT`` - ``18BIT`` - ``19BIT`` - + - All other options from :ref:`Sensor `. - **z_axis** (*Optional*): The information for the z-axis. @@ -66,19 +66,19 @@ Configuration variables: - **name** (**Required**, string): The name for the z-axis sensor. - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - **resolution** (*Optional*, int): Set resolution. Defaults to ``16BIT``. Must be one of: - + - ``16BIT`` - ``17BIT`` - ``18BIT`` - ``19BIT`` - + - All other options from :ref:`Sensor `. - + - **temperature** (*Optional*): Built-in temperature sensor. - **name** (**Required**, string): The name for the temperature sensor. - **id** (*Optional*, :ref:`config-id`): Set the ID of this sensor for use in lambdas. - - **oversampling** (*Optional*, int): On-chip oversampling for the temperature sensor. Defaults to `0`. Must be between `0` and `3`. + - **oversampling** (*Optional*, int): On-chip oversampling for the temperature sensor. Defaults to ``0``. Must be between ``0`` and ``3``. - All other options from :ref:`Sensor `. - **drdy_pin** (*Optional*, :ref:`Pin Schema `): Data-ready pin. Often labelled ``INT``. Using this pin might lead to slightly quicker read times. diff --git a/components/sensor/modbus_controller.rst b/components/sensor/modbus_controller.rst index 90c3fa40d..68d923363 100644 --- a/components/sensor/modbus_controller.rst +++ b/components/sensor/modbus_controller.rst @@ -1,5 +1,5 @@ -Modbus Sensor -============= +Modbus Controller Sensor +======================== .. seo:: :description: Instructions for setting up a modbus_controller device sensor. @@ -14,43 +14,59 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. - **register_type** (**Required**): type of the modbus register. - - coil: coils are also called discrete output. Coils are 1-bit registers (on/off values) that are used to control discrete outputs. Read and Write access. Modbus function code 1 (Read Coil Status) will be used - - discrete_input: discrete input register (read only coil) are similar to coils but can only be read. Modbus function code 2 (Read Input Status) will be used. - - holding: Holding Registers - Holding registers are the most universal 16-bit register. Read and Write access. Modbus function code 3 (Read Holding Registers) will be used. - - read: Read Input Registers - registers are 16-bit registers used for input, and may only be read. Modbus function code 4 (Read Input Registers) will be used. -- **address**: (**Required**, int): start address of the first register in a range -- **value_type**: (**Required**): datatype of the mod_bus register data. The default data type for modbus is a 16 bit integer in big endian format (MSB first) - - U_WORD (unsigned 16 bit integer from 1 register = 16bit) - - S_WORD (signed 16 bit integer from 1 register = 16bit) - - U_DWORD (unsigned 32 bit integer from 2 registers = 32bit) - - S_DWORD (signed 32 bit integer from 2 registers = 32bit) - - U_DWORD_R (unsigned 32 bit integer from 2 registers low word first) - - S_DWORD_R (signed 32 bit integer from 2 registers low word first) - - U_QWORD (unsigned 64 bit integer from 4 registers = 64bit) - - S_QWORD (signed 64 bit integer from 4 registers = 64bit) - - U_QWORD_R (unsigned 64 bit integer from 4 registers low word first) - - S_QWORD_R (signed 64 bit integer from 4 registers low word first) - - FP32 (32 bit IEEE 754 floating point from 2 registers) - - FP32_R (32 bit IEEE 754 floating point - same as FP32 but low word first)s -- **bitmask**: (*Optional*) some values are packed in a response. The bitmask can be used to extract a value from the response. For example, if the high byte value register 0x9013 contains the minute value of the current time. To only exctract this value use bitmask: 0xFF00. The result will be automatically right shifted by the number of 0 before the first 1 in the bitmask. For 0xFF00 (0b1111111100000000) the result is shifted 8 posistions. More than one sensor can use the same address/offset if the bitmask is different. -- **skip_updates**: (*Optional*, int): By default all sensors of of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle + - ``coil``: coils are also called discrete output. Coils are 1-bit registers (on/off values) that are used to control discrete outputs. Read and Write access. Modbus function code 1 (Read Coil Status) will be used + - ``discrete_input``: discrete input register (read only coil) are similar to coils but can only be read. Modbus function code 2 (Read Input Status) will be used. + - ``holding``: Holding Registers - Holding registers are the most universal 16-bit register. Read and Write access. Modbus function code 3 (Read Holding Registers) will be used. + - ``read``: Read Input Registers - registers are 16-bit registers used for input, and may only be read. Modbus function code 4 (Read Input Registers) will be used. + +- **address** (**Required**, int): start address of the first register in a range +- **value_type** (**Required**): datatype of the mod_bus register data. The default data type for modbus is a 16 bit integer in big endian format (MSB first) + + - ``U_WORD``: unsigned 16 bit integer from 1 register = 16bit + - ``S_WORD``: signed 16 bit integer from 1 register = 16bit + - ``U_DWORD``: unsigned 32 bit integer from 2 registers = 32bit + - ``S_DWORD``: signed 32 bit integer from 2 registers = 32bit + - ``U_DWORD_R``: unsigned 32 bit integer from 2 registers low word first + - ``S_DWORD_R``: signed 32 bit integer from 2 registers low word first + - ``U_QWORD``: unsigned 64 bit integer from 4 registers = 64bit + - ``S_QWORD``: signed 64 bit integer from 4 registers = 64bit + - ``U_QWORD_R``: unsigned 64 bit integer from 4 registers low word first + - ``S_QWORD_R``: signed 64 bit integer from 4 registers low word first + - ``FP32``: 32 bit IEEE 754 floating point from 2 registers + - ``FP32_R``: 32 bit IEEE 754 floating point - same as FP32 but low word first + +- **bitmask** (*Optional*, int): some values are packed in a response. The bitmask can be used to extract a value from the response. For example, if the high byte value register 0x9013 contains the minute value of the current time. To only exctract this value use bitmask: 0xFF00. The result will be automatically right shifted by the number of 0 before the first 1 in the bitmask. For 0xFF00 (0b1111111100000000) the result is shifted 8 posistions. More than one sensor can use the same address/offset if the bitmask is different. +- **skip_updates** (*Optional*, int): By default all sensors of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle Note: The modbus_controller groups component by address ranges to reduce number of transactions. All compoents with the same address will be updated in one request. skip_updates applies for all components in the same range. -- **register_count**: (*Optional*): only required for uncommon response encodings or to :ref:`optimize modbus communications` +- **register_count** (*Optional*): only required for uncommon response encodings or to :ref:`optimize modbus communications` The number of registers this data point spans. Overrides the defaults determined by ``value_type``. If no value for ``register_count`` is provided, it is calculated based on the register type. The default size for 1 register is 16 bits (1 Word). Some devices are not adhering to this convention and have registers larger than 16 bits. In this case ``register_count`` and ``response_size`` must be set. For example, if your modbus device uses 1 registers for a FP32 value instead the default of two set ``register_count: 1`` and ``response_size: 4``. -- **response_size**: (*Optional*): Size of the response for the register in bytes. Defaults to register_count*2. -- **force_new_range**: (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting ``force_new_range: true`` enforces the start of a new range at that address. -- **custom_data** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_data`` is used ``address`` and ``register_type`` can't be used. +- **response_size** (*Optional*, int): Size of the response for the register in bytes. Defaults to register_count*2. +- **force_new_range** (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting ``force_new_range: true`` enforces the start of a new range at that address. +- **custom_command** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_command`` is used ``address`` and ``register_type`` can't be used. custom data must contain all required bytes including the modbus device address. The crc is automatically calculated and appended to the command. - See :ref:`modbus_custom_data` how to use ``custom_command`` + See :ref:`modbus_custom_command` how to use ``custom_command`` - **lambda** (*Optional*, :ref:`lambda `): Lambda to be evaluated every update interval to get the new value of the sensor. -- **offset**: (*Optional*, int): only required for uncommon response encodings - offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type - For coil or discrete input registers offset is the position of the coil/register because these registers encode 8 coils in one byte. + + Parameters passed into the lambda + + - **x** (float): The parsed float value of the modbus data + - **data** (std::vectoroffset]`` to get the first response byte for your sensor. + - **item** (const pointer to a SensorItem derived object): The sensor object itself. + + Possible return values for the lambda: + + - ``return ;`` the new value for the sensor. + - ``return NAN;`` if the state should be considered invalid to indicate an error (advanced). + +- **offset** (*Optional*, int): only required for uncommon response encodings + offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type + For coil or discrete input registers offset is the position of the coil/register because these registers encode 8 coils in one byte. - All other options from :ref:`Sensor `. @@ -122,28 +138,14 @@ This example logs the value as parsed and the raw modbus bytes received for this } return x ; +.. _modbus_custom_command: -Parameters passed into the lambda +Using ``custom_command`` +------------------------ -- **x** (float): The parsed float value of the modbus data - -- **data** (std::vectoroffset]`` to get the first response byte for your sensor. -- **item** (const pointer to a SensorItem derived object): The sensor object itself. - -Possible return values for the lambda: - - - ``return ;`` the new value for the sensor. - - ``return NAN;`` if the state should be considered invalid to indicate an error (advanced). - -.. _modbus_custom_data: - -Using custom_data ------------------ - -``custom_data`` can be used to create an arbitrary modbus command. Combined with a lambda any response can be handled. +``custom_command`` can be used to create an arbitrary modbus command. Combined with a lambda any response can be handled. This example re-implements the command to read the registers 0x156 (Total active energy) and 0x158 Total (reactive energy) from a SDM-120. -SDM-120 returns the values as floats using 32 bits in 2 registers. +SDM-120 returns the values as floats using 32 bits in 2 registers. .. code-block:: yaml @@ -171,7 +173,7 @@ SDM-120 returns the values as floats using 32 bits in 2 registers. # 0x4 : modbus function code # 0x1 : high byte of modbus register address # 0x56: low byte of modbus register address - # 0x00: high byte of total number of registers requested + # 0x00: high byte of total number of registers requested # 0x02: low byte of total number of registers requested custom_command: [ 0x2, 0x4, 0x1, 0x56,0x00, 0x02] value_type: FP32 @@ -205,10 +207,10 @@ SDM-120 returns the values as floats using 32 bits in 2 registers. .. note:: **Optimize modbus communications** - ``register_count`` can also be used to skip a register in consecutive range. - - An example is a SDM meter: - + ``register_count`` can also be used to skip a register in consecutive range. + + An example is a SDM meter: + .. code-block:: yaml - platform: modbus_controller @@ -236,9 +238,9 @@ SDM-120 returns the values as floats using 32 bits in 2 registers. value_type: FP32 accuracy_decimals: 1 - Maybe you don’t care about the Voltage value for Phase 2 and Phase 3 (or you have a SDM-120). + Maybe you don’t care about the Voltage value for Phase 2 and Phase 3 (or you have a SDM-120). Of course, you can delete the sensors your don’t care about. But then you have a gap in the addresses. The configuration above will generate one modbus command `read multiple registers from 0 to 6`. If you remove the registers at address 2 and 4 then 2 commands will be generated `read register 0` and `read register 6`. - To avoid the generation of multiple commands and reduce the amount of uart communication ``register_count`` can be used to fill the gaps + To avoid the generation of multiple commands and reduce the amount of uart communication ``register_count`` can be used to fill the gaps .. code-block:: yaml @@ -256,7 +258,7 @@ SDM-120 returns the values as floats using 32 bits in 2 registers. register_type: "read" value_type: FP32 - Because `register_count: 6` is used for the first register the command “read registers from 0 to 6” can still be used but the values in between are ignored. + Because `register_count: 6` is used for the first register the command “read registers from 0 to 6” can still be used but the values in between are ignored. **Calculation:** FP32 is a 32 bit value and uses 2 registers. Therefore, to skip the 2 FP32 registers the size of these 2 registers must be added to the default size for the first register. So we have 2 for address 0, 2 for address 2 and 2 for address 4 then ``register_count`` must be 6. diff --git a/components/sensor/mopeka_ble.rst b/components/sensor/mopeka_pro_check.rst similarity index 79% rename from components/sensor/mopeka_ble.rst rename to components/sensor/mopeka_pro_check.rst index 6c787dfec..22419b7ae 100644 --- a/components/sensor/mopeka_ble.rst +++ b/components/sensor/mopeka_pro_check.rst @@ -1,12 +1,12 @@ Mopeka Pro Check BLE Sensor -=============================== +=========================== .. seo:: :description: Instructions for setting up Mopeka Pro Check bluetooth-based sensors in ESPHome. :image: mopeka_pro_check.jpg :keywords: Mopeka, Mopeka Pro Check, BLE, Bluetooth -The ``mopeka_pro_check`` sensor platform lets you track the output of Mopeka +The ``mopeka_pro_check`` sensor platform lets you track the output of Mopeka Pro Check LP Bluetooth Low Energy devices using the :doc:`/components/esp32_ble_tracker`. This component will track the tank level, distance, temperature, and battery percentage of a Mopeka Pro Check LP device every time the sensor sends @@ -27,33 +27,33 @@ out a BLE broadcast. esp32_ble_tracker: sensor: - # Example using 20lb vertical propane tank. - - platform: mopeka_pro_check - mac_address: D3:75:F2:DC:16:91 - tank_type: 20LB_V - temperature: - name: "Propane test temp" - level: - name: "Propane test level" - distance: - name: "Propane test distance" - battery_level: - name: "Propane test battery level" + # Example using 20lb vertical propane tank. + - platform: mopeka_pro_check + mac_address: D3:75:F2:DC:16:91 + tank_type: 20LB_V + temperature: + name: "Propane test temp" + level: + name: "Propane test level" + distance: + name: "Propane test distance" + battery_level: + name: "Propane test battery level" - # Custom example - user defined empty / full points - - platform: mopeka_pro_check - mac_address: D3:75:F2:DC:16:91 - tank_type: CUSTOM - custom_distance_full: 40cm - custom_distance_empty: 10mm - temperature: - name: "Propane c test temp" - level: - name: "Propane c test level" - distance: - name: "Propane c test distance" - battery_level: - name: "Propane c test battery level" + # Custom example - user defined empty / full points + - platform: mopeka_pro_check + mac_address: D3:75:F2:DC:16:91 + tank_type: CUSTOM + custom_distance_full: 40cm + custom_distance_empty: 10mm + temperature: + name: "Propane c test temp" + level: + name: "Propane c test level" + distance: + name: "Propane c test distance" + battery_level: + name: "Propane c test battery level" Configuration variables: diff --git a/components/sensor/radon_eye_ble.rst b/components/sensor/radon_eye_ble.rst index f402c387a..cbf735666 100644 --- a/components/sensor/radon_eye_ble.rst +++ b/components/sensor/radon_eye_ble.rst @@ -37,8 +37,8 @@ take note of the device MAC address, and use it when configuring a sensor below. Supported Devices ----------------- -Radon Eye RD200 -*************** +Radon Eye RD200 Sensor +********************** Radon Eye RD200 tracks radon concentration over short periods (5 min interval) and longer periods (24h or month). diff --git a/components/sensor/rotary_encoder.rst b/components/sensor/rotary_encoder.rst index 8a42baf16..f73063da3 100644 --- a/components/sensor/rotary_encoder.rst +++ b/components/sensor/rotary_encoder.rst @@ -41,7 +41,7 @@ To modify additional parameters of pins like active state or pull-ups, you may a .. code-block:: yaml # Example of advanced pin configuration - pin_a: + pin_a: number: D5 inverted: true mode: @@ -62,9 +62,9 @@ Configuration variables: - **resolution** (*Optional*, string): The resolution of the sensor, this controls how many pulses are generated by one step: - - 1 (default) - - 2 - - 4 + - ``1`` - (Default) + - ``2`` + - ``4`` - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **min_value** (*Optional*, int): The minimum value this rotary encoder will go to, turning @@ -79,7 +79,7 @@ Configuration variables: For restoring on ESP8266s, also see ``esp8266_restore_from_flash`` in the :doc:`esphome section `. - - ``RESTORE_DEFAULT_ZERO`` (Default) - Attempt to restore state and default to zero (0) if not possible to restore. + - ``RESTORE_DEFAULT_ZERO`` - (Default) Attempt to restore state and default to zero (0) if not possible to restore. - ``ALWAYS_ZERO`` - Always initialize the counter with value zero (0). - **on_clockwise** (*Optional*, :ref:`Automation `): Actions to be performed when diff --git a/components/sensor/tsl2591.rst b/components/sensor/tsl2591.rst index 7c3f24a6a..cb4092d79 100644 --- a/components/sensor/tsl2591.rst +++ b/components/sensor/tsl2591.rst @@ -131,13 +131,13 @@ For the TSL2591 device: - **update_interval** (*Optional*, :ref:`config-time`): The interval for checking the sensors. Defaults to ``60s``. -- **power_save_mode** (*Optional*, boolean) Should the device be powered down between update intervals? +- **power_save_mode** (*Optional*, boolean): Should the device be powered down between update intervals? Defaults to ``True``. -- **device_factor** (*Optional*, float) The default is ``53.0``. +- **device_factor** (*Optional*, float): The default is ``53.0``. The device factor to be used as part of the lux equation for ``calculated_lux``. -- **glass_attenuation_factor** (*Optional*, float) The default is ``7.7``. +- **glass_attenuation_factor** (*Optional*, float): The default is ``7.7``. The glass attenuation factor to be used as part of the lux equation for ``calculated_lux``. - + - All other options for I²C devices described at :ref:`I²C Bus `. diff --git a/components/sensor/xiaomi_miscale.rst b/components/sensor/xiaomi_miscale.rst index 75947a087..7fa523872 100644 --- a/components/sensor/xiaomi_miscale.rst +++ b/components/sensor/xiaomi_miscale.rst @@ -47,7 +47,8 @@ Configuration variables: - All other options from :ref:`Sensor `. - **clear_impedance** (*Optional*): Clear the impedance information if a weight reading without impedance is received. Defaults to ``false``. **Only available on MiScale2** - Useful in the example below if a person steps onto the scale without waiting for the complete measurement. Without setting the flag the impedance reading of the measurement before will be used for the currently measured person. + + Useful in the example below if a person steps onto the scale without waiting for the complete measurement. Without setting the flag the impedance reading of the measurement before will be used for the currently measured person. Configuration example with multiple users: ****************************************** diff --git a/components/sim800l.rst b/components/sim800l.rst index 3c01c990a..5cea41c1c 100644 --- a/components/sim800l.rst +++ b/components/sim800l.rst @@ -75,7 +75,7 @@ Configuration variables: - All other options from :ref:`Sensor `. -Binary sensor +Binary Sensor ------------- Configuration variables: @@ -127,6 +127,20 @@ Send a SMS message to a phone recipient using this action in automations. message: !lambda |- return id(reed_switch).state ? "Door is now OPEN" : "Hey door just CLOSED"; +Configuration options: + +- **recipient** (**Required**, string, :ref:`templatable `): The message recipient. + number. +- **message** (**Required**, string, :ref:`templatable `): The message content. +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID of the SIM800L if you have multiple components. + +.. note:: + + This action can also be written in :ref:`lambdas `: + + .. code-block:: cpp + + id(sim800l1).send_sms("+15551234567", "The message content"); .. _sim800l-dial_action: @@ -144,7 +158,7 @@ Dial to a phone recipient using this action in automations. Configuration options: -- **recipient** (***Required**, string, :ref:`templatable `): The number to dial. +- **recipient** (**Required**, string, :ref:`templatable `): The number to dial. - **id** (*Optional*, :ref:`config-id`): Manually specify the ID of the SIM800L if you have multiple components. .. note:: diff --git a/components/switch/modbus_controller.rst b/components/switch/modbus_controller.rst index bc7e6d539..3f173655d 100644 --- a/components/switch/modbus_controller.rst +++ b/components/switch/modbus_controller.rst @@ -1,5 +1,5 @@ -Modbus Switch -============= +Modbus Controller Switch +======================== .. seo:: :description: Instructions for setting up a modbus_controller device sensor. @@ -14,35 +14,34 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. - **register_type** (**Required**): type of the modbus register. -- **address**: (**Required**, int): start address of the first register in a range -- **offset**: (*Optional*, int): not required in most cases +- **address** (**Required**, int): start address of the first register in a range +- **offset** (*Optional*, int): not required in most cases offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type The value for offset depends on the register type. For holding input registers the offset is in bytes. For coil and discrete input resisters the LSB of the first data byte contains the coil addressed in the request. The other coils follow toward the high-order end of this byte and from low order to high order in subsequent bytes. For the registers offset is the position of the relevant bit. - To get the value of the coil register 2 can be retrived using address: 2 / offset: 0 or address: 0 / offset 2 -- **bitmask** : some values are packed in a response. The bitmask is used to determined if the result is true or false -- **skip_updates**: (*Optional*, int): By default all sensors of of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle -- **use_write_multiple**: (*Optional*, boolean): By default the modbus command ``Force Single Coil`` (function code 5) is used to send state changes to the device. If your device only supports ``Force Multiple Coils`` (function code 15) set this option to true. -- **custom_data** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_data`` is used ``address`` and ``register_type`` can't be used. + To get the value of the coil register 2 can be retrieved using address: 2 / offset: 0 or address: 0 / offset 2 +- **bitmask** (*Optional*, int): Some values are packed in a response. The bitmask is used to determined if the result is true or false. +- **skip_updates** (*Optional*, int): By default all sensors of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle +- **use_write_multiple** (*Optional*, boolean): By default the modbus command ``Force Single Coil`` (function code 5) is used to send state changes to the device. If your device only supports ``Force Multiple Coils`` (function code 15) set this option to true. +- **custom_command** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_command`` is used ``address`` and ``register_type`` can't be used. custom data must contain all required bytes including the modbus device address. The crc is automatically calculated and appended to the command. - See :ref:`modbus_custom_data` how to use ``custom_command`` + See :ref:`modbus_custom_command` how to use ``custom_command`` - **lambda** (*Optional*, :ref:`lambda `): Lambda to be evaluated every update interval to read the status of the switch. - **write_lambda** (*Optional*, :ref:`lambda `): Lambda called before send. Lambda is evaluated before the modbus write command is created. -**Parameters passed into write_lambda** + Parameters passed into the lambda -- **x** (float): The float value to be sent to the modbus device + - **x** (float): The float value to be sent to the modbus device + - **payload** (``std::vector&payload``): empty vector for the payload. If payload is set in the lambda it is sent as a custom command and must include all required bytes for a modbus request + *note:* because the response contains data for all registers in the same range you have to use ``data[item->offset]`` to get the first response byte for your sensor. + - **item** (const pointer to a Switch derived object): The sensor object itself. -- **payload** (`std::vector&payload`): empty vector for the payload. If payload is set in the lambda it is sent as a custom command and must include all required bytes for a modbus request - note: because the response contains data for all registers in the same range you have to use ``data[item->offset]`` to get the first response byte for your sensor. -- **item** (const pointer to a Switch derived object): The sensor object itself. + Possible return values for the lambda: -Possible return values for the lambda: - - - ``return ;`` the new value for the sensor. - - ``return ; and fill payload with data`` if the payload is added from the lambda then these bytes will be sent. - - ``return {};`` in the case the lambda handles the sending of the value itself. + - ``return ;`` the new value for the sensor. + - ``return ; and fill payload with data`` if the payload is added from the lambda then these bytes will be sent. + - ``return {};`` in the case the lambda handles the sending of the value itself. **Example** diff --git a/components/text_sensor/modbus_controller.rst b/components/text_sensor/modbus_controller.rst index f824a1a2e..10a49b574 100644 --- a/components/text_sensor/modbus_controller.rst +++ b/components/text_sensor/modbus_controller.rst @@ -1,5 +1,5 @@ -Modbus Text Sensor -================== +Modbus Controller Text Sensor +============================= .. seo:: :description: Instructions for setting up a modbus_controller modbus text sensor. @@ -13,43 +13,45 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. - **register_type** (**Required**): type of the modbus register. - - coil: coils are also called discrete outout. Coils are 1-bit registers (on/off values) that are used to control discrete outputs. Read and Write access - - discrete_input: discrete input register (read only coil) are similar to coils but can only be read. - - holding: Holding Registers - Holding registers are the most universal 16-bit register. Read and Write access - - read: Read Input Registers - registers are 16-bit registers used for input, and may only be read -- **address**: (**Required**, int): start address of the first register in a range -- **skip_updates**: (*Optional*, int): By default all sensors of of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle -- **register_count**: (*Optional*): The number of registers this data point spans. Default is 1 -- **response_size**: (**Required**): Number of bytes of the response -- **raw_encode**: (*Optional*, enum) If the response is binary it can't be published directly. Since a text sensor only publishes strings the binary data can be encoded + + - ``coil``: coils are also called discrete outout. Coils are 1-bit registers (on/off values) that are used to control discrete outputs. Read and Write access + - ``discrete_input``: discrete input register (read only coil) are similar to coils but can only be read. + - ``holding``: Holding Registers - Holding registers are the most universal 16-bit register. Read and Write access + - ``read``: Read Input Registers - registers are 16-bit registers used for input, and may only be read + +- **address** (**Required**, int): start address of the first register in a range +- **skip_updates** (*Optional*, int): By default all sensors of a modbus_controller are updated together. For data points that don't change very frequently updates can be skipped. A value of 5 would only update this sensor range in every 5th update cycle +- **register_count** (*Optional*): The number of registers this data point spans. Default is 1 +- **response_size** (**Required**): Number of bytes of the response +- **raw_encode** (*Optional*, enum): If the response is binary it can't be published directly. Since a text sensor only publishes strings the binary data can be encoded + - ``NONE``: Don't encode data. - ``HEXBYTES``: 2 byte hex string. 0x2011 will be sent as "2011". - ``COMMA``: Byte values as integers, delimited by a coma. 0x2011 will be sent as "32,17" -- **force_new_range**: (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting `foce_new_range: true` enforces the start of a new range at that address. -- **custom_data** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_data`` is used ``address`` and ``register_type`` can't be used. - custom data must contain all required bytes including the modbus device address. The crc is automatically calculated and appended to the command. - See :ref:`modbus_custom_data` how to use ``custom_command`` + +- **force_new_range** (*Optional*, boolean): If possible sensors with sequential addresses are grouped together and requested in one range. Setting ``force_new_range: true`` enforces the start of a new range at that address. +- **custom_command** (*Optional*, list of bytes): raw bytes for modbus command. This allows using non-standard commands. If ``custom_command`` is used ``address`` and ``register_type`` can't be used. + custom command must contain all required bytes including the modbus device address. The crc is automatically calculated and appended to the command. + See :ref:`modbus_custom_command` how to use ``custom_command`` - **lambda** (*Optional*, :ref:`lambda `): Lambda to be evaluated every update interval to get the new value of the sensor. It is called after the encoding according to **raw_encode**. -- **offset**: (*Optional*, int): not required in most cases + + Parameters passed into the lambda + + - **x** (std:string): The parsed value of the modbus data according to **raw_encode** + - **data** (std::vectoroffset]`` to get the first response byte for your sensor. + - **item** (const pointer to a SensorItem derived object): The sensor object itself. + + Possible return values for the lambda: + + - ``return ;`` the new value for the sensor. + - ``return {};`` uses the parsed value for the state (same as ``return x;``). + +- **offset** (*Optional*, int): not required in most cases offset from start address in bytes. If more than one register is read a modbus read registers command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type - All options from :ref:`Text Sensor `. -Parameters passed into the lambda - -- **x** (std:string): The parsed value of the modbus data according to **raw_encode** - -- **data** (std::vectoroffset]`` to get the first response byte for your sensor. -- **item** (const pointer to a SensorItem derived object): The sensor object itself. - -Possible return values for the lambda: - - - ``return ;`` the new value for the sensor. - - ``return {};`` uses the parsed value for the state (same as ``return x;``). - - - **Example** diff --git a/components/touchscreen/ektf2232.rst b/components/touchscreen/ektf2232.rst index 29aa7237b..220c61a37 100644 --- a/components/touchscreen/ektf2232.rst +++ b/components/touchscreen/ektf2232.rst @@ -24,7 +24,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually set the ID of this touchscreen. - **rts_pin** (*Optional*, :ref:`Pin Schema `): The reset pin of the controller. -- **interupt_pin** (*Optional*, :ref:`Pin Schema `): The touch detection pin. +- **interrupt_pin** (*Optional*, :ref:`Pin Schema `): The touch detection pin. - All other options from :ref:`config-touchscreen`. diff --git a/components/touchscreen/index.rst b/components/touchscreen/index.rst index b40f7e6ed..4949cbdd0 100644 --- a/components/touchscreen/index.rst +++ b/components/touchscreen/index.rst @@ -59,7 +59,7 @@ buttons. y_max: 100 page_id: home_page_id -Configuration Variables: +Configuration variables: ************************ - **name** (*Optional*, string): The name for the binary sensor. diff --git a/components/touchscreen/lilygo_t5_47.rst b/components/touchscreen/lilygo_t5_47.rst index ba6a8336e..24673c618 100644 --- a/components/touchscreen/lilygo_t5_47.rst +++ b/components/touchscreen/lilygo_t5_47.rst @@ -22,7 +22,7 @@ Configuration variables: ------------------------ - **id** (*Optional*, :ref:`config-id`): Manually set the ID of this touchscreen. -- **interupt_pin** (*Optional*, :ref:`Pin Schema `): The touch detection pin. +- **interrupt_pin** (*Optional*, :ref:`Pin Schema `): The touch detection pin. Must be ``GPIO13``. - All other options from :ref:`config-touchscreen`. diff --git a/components/tuya.rst b/components/tuya.rst index 6067dc5c4..a458fe1ce 100644 --- a/components/tuya.rst +++ b/components/tuya.rst @@ -50,7 +50,7 @@ Configuration variables: Automations: -- **on_datapoint_update**: (*Optional*): An automation to perform when a Tuya datapoint update is received. See :ref:`tuya-on_datapoint_update`. +- **on_datapoint_update** (*Optional*): An automation to perform when a Tuya datapoint update is received. See :ref:`tuya-on_datapoint_update`. Tuya Automation --------------- @@ -107,8 +107,8 @@ The type of ``x`` variable is depending on ``datapoint_type`` configuration vari Configuration variables: -- **sensor_datapoint** (*Required*, int): The datapoint id number of the sensor. -- **datapoint_type** (*Required*, string): The datapoint type one of *raw*, *string*, *bool*, *int*, *uint*, *enum*, *bitmask* or *any*. +- **sensor_datapoint** (**Required**, int): The datapoint id number of the sensor. +- **datapoint_type** (**Required**, string): The datapoint type one of *raw*, *string*, *bool*, *int*, *uint*, *enum*, *bitmask* or *any*. - See :ref:`Automation `. diff --git a/components/web_server.rst b/components/web_server.rst index 3c19d720b..1afe589fb 100644 --- a/components/web_server.rst +++ b/components/web_server.rst @@ -57,7 +57,7 @@ Configuration variables: - **include_internal** (*Optional*, boolean): Whether ``internal`` entities should be displayed on the web interface. Defaults to ``false``. -- **ota** (*Optional*, boolean): Turn on or off the OTA feature inside webserver. Strongly not suggested without enabled authentication settings. Default: `true` +- **ota** (*Optional*, boolean): Turn on or off the OTA feature inside webserver. Strongly not suggested without enabled authentication settings. Defaults to ``true``. - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **version** (*Optional*, string): 1 or 2. Version 1 displays as a table. Version 2 uses web components and has more functionality. Default: `2` diff --git a/conf.py b/conf.py index f97b45ce8..8e23562a8 100644 --- a/conf.py +++ b/conf.py @@ -40,7 +40,6 @@ extensions = [ "github", "seo", "sitemap", - "schema_doc", ] # Add any paths that contain templates here, relative to this directory. diff --git a/guides/physical_device_connection.rst b/guides/physical_device_connection.rst index 79c6146dc..53031aaa4 100644 --- a/guides/physical_device_connection.rst +++ b/guides/physical_device_connection.rst @@ -231,7 +231,7 @@ require different parts and tools. .. _jumper-wires: * - :ref:`Jumper wires ` - Used to connect two things together electrically. The male end has metal - protuding and is plugged into the the female end of a wire or board. + protuding and is plugged into the female end of a wire or board. They come in varying lengths too, but for our purposes, any length will do. - $3 to $8 for a pack diff --git a/index.rst b/index.rst index 4aec7a8fb..caf1bc993 100644 --- a/index.rst +++ b/index.rst @@ -588,7 +588,7 @@ Climate Components Thermostat Controller, components/climate/thermostat, air-conditioner.svg Custom Climate, components/climate/custom, language-cpp.svg PID Controller, components/climate/pid, function.svg - IR Remote Climate, components/climate/ir_climate, air-conditioner-ir.svg + IR Remote Climate, components/climate/climate_ir, air-conditioner-ir.svg Tuya Climate, components/climate/tuya, tuya.png Midea, components/climate/midea, midea.svg Anova Cooker, components/climate/anova, anova.png diff --git a/markdown.py b/markdown.py index 1043117e8..7f681e9fa 100644 --- a/markdown.py +++ b/markdown.py @@ -172,6 +172,19 @@ class Translator(nodes.NodeVisitor): def depart_block_quote(self, node): pass + def visit_raw(self, node): + pass + + def depart_raw(self, node): + pass + + def visit_note(self, node): + self.write("\n > ") + pass + + def depart_note(self, node): + pass + class MDWriter(writers.Writer): """GitHub-flavored markdown writer""" diff --git a/schema_doc.py b/schema_doc.py index cc07f587f..c62c64d03 100644 --- a/schema_doc.py +++ b/schema_doc.py @@ -1,53 +1,62 @@ +from genericpath import exists import re import json import urllib +import traceback from typing import MutableMapping from sphinx.util import logging from docutils import nodes -SCHEMA_PATH = "schema.json" +# Instructions for building +# you must have checked out this project in the same folder of +# esphome and esphome-vscode so the SCHEMA_PATH below can find the source schemas + +# This file is not processed by default as extension unless added. +# To add this extension from command line use: +# -Dextensions=github,seo,sitemap,schema_doc" + +# also for improve performance running old version +# -d_build/.doctrees-schema +# will put caches in another dir and not overwrite the ones without schema + +SCHEMA_PATH = "../esphome-vscode/server/src/schema/" CONFIGURATION_VARIABLES = "Configuration variables:" +CONFIGURATION_OPTIONS = "Configuration options:" PIN_CONFIGURATION_VARIABLES = "Pin configuration variables:" COMPONENT_HUB = "Component/Hub" -props_missing = 0 -props_verified = 0 -props_documented = 0 +JSON_DUMP_PRETTY = True + + +class Statistics: + props_documented = 0 + enums_good = 0 + enums_bad = 0 + + +statistics = Statistics() + +logger = logging.getLogger(__name__) def setup(app): - """Setup connects events to the sitemap builder""" - import os - if not os.path.isfile(SCHEMA_PATH): - logger = logging.getLogger(__name__) + if not os.path.isfile(SCHEMA_PATH + "esphome.json"): logger.info(f"{SCHEMA_PATH} not found. Not documenting schema.") - else: - app.connect("doctree-resolved", doctree_resolved) - app.connect("build-finished", build_finished) + return - f = open(SCHEMA_PATH, "r", encoding="utf-8-sig") - str = f.read() - app.jschema = json.loads(str) + app.connect("doctree-resolved", doctree_resolved) + app.connect("build-finished", build_finished) + app.files = {} return {"version": "1.0.0", "parallel_read_safe": True, "parallel_write_safe": True} -def find_component(jschema, component): - return jschema["properties"].get(component) - - -def find_platform_component(jschema, platform, component): - platform_items = jschema["properties"][platform].get("items") - if not platform_items: - return None - ar = platform_items["allOf"] - for p in ar: - if "if" in p: - if p["if"]["properties"]["platform"]["const"] == component: - return p +def find_platform_component(app, platform, component): + file_data = get_component_file(app, component) + return file_data[f"{component}.{platform}"]["schemas"]["CONFIG_SCHEMA"] def doctree_resolved(app, doctree, docname): @@ -59,8 +68,8 @@ def doctree_resolved(app, doctree, docname): except Exception as e: err_str = f"In {docname}: {str(e)}" - logger = logging.getLogger(__name__) logger.warning(err_str) + traceback.print_exc() PLATFORMS_TITLES = { @@ -69,89 +78,118 @@ PLATFORMS_TITLES = { "Text Sensor": "text_sensor", "Output": "output", "Cover": "cover", + "Button": "button", + "Select": "select", + "Fan": "fan", + "Lock": "lock", + "Number": "number", "Climate": "climate", "CAN Bus": "canbus", "Stepper": "stepper", + "Switch": "switch", + "I²C": "i2c", } CUSTOM_DOCS = { "guides/automations": { - "Global Variables": "properties/globals", + "Global Variables": "globals.schemas.CONFIG_SCHEMA", }, "guides/configuration-types": { - "Color": "properties/color", "Pin Schema": [ - "definitions/PIN.INPUT_INTERNAL", - "definitions/PIN.OUTPUT_INTERNAL", + "esp32.pin.schema", + "esp8266.pin.schema", ], }, "components/binary_sensor/index": { - "Binary Sensor Filters": "binary_sensor.FILTER_REGISTRY", + "Binary Sensor Filters": "binary_sensor.registry.filter", }, - "components/climate/ir_climate": { - "IR Remote Climate": [ - "properties/climate/coolix", - "properties/climate/daikin", - "properties/climate/fujitsu_general", - "properties/climate/mitsubishi", - "properties/climate/tcl112", - "properties/climate/toshiba", - "properties/climate/yashima", - "properties/climate/whirlpool", - "properties/climate/climate_ir_lg", - "properties/climate/hitachi_ac344", - ] + "components/canbus": { + "_LoadSchema": False, + "Base CAN Bus Configuration": "canbus.schemas.CANBUS_SCHEMA", }, + "components/climate/climate_ir": {"_LoadSchema": False, "IR Remote Climate": []}, "components/display/index": { - "Images": "properties/image", - "Drawing Static Text": "properties/font", - "Color": "properties/color", - "Animation": "properties/animation", + "Images": "image.schemas.CONFIG_SCHEMA", + "Drawing Static Text": "font.schemas.CONFIG_SCHEMA", + "Color": "color.schemas.CONFIG_SCHEMA", + "Animation": "animation.schemas.CONFIG_SCHEMA", }, "components/light/index": { "Base Light Configuration": [ - "definitions/light.ADDRESSABLE_LIGHT_SCHEMA", - "definitions/light.BINARY_LIGHT_SCHEMA", - "definitions/light.BRIGHTNESS_ONLY_LIGHT_SCHEMA", - "definitions/light.LIGHT_SCHEMA", + "light.schemas.ADDRESSABLE_LIGHT_SCHEMA", + "light.schemas.BINARY_LIGHT_SCHEMA", + "light.schemas.BRIGHTNESS_ONLY_LIGHT_SCHEMA", + "light.schemas.LIGHT_SCHEMA", ], - "Light Effects": "light.EFFECTS_REGISTRY", + "Light Effects": "light.registry.effects", }, "components/light/fastled": { - "Clockless": "properties/light/fastled_clockless", - "SPI": "properties/light/fastled_spi", + "_LoadSchema": False, + "Clockless": "fastled_clockless.platform.light.schemas.CONFIG_SCHEMA", + "SPI": "fastled_spi.platform.light.schemas.CONFIG_SCHEMA", + }, + "components/binary_sensor/ttp229": { + "_LoadSchema": False, }, "components/mcp230xx": { - PIN_CONFIGURATION_VARIABLES: [ - "definitions/PIN.INPUT_mcp23xxx", - "definitions/PIN.OUTPUT_mcp23xxx", - ] + "_LoadSchema": False, + PIN_CONFIGURATION_VARIABLES: "mcp23xxx.pin", }, "components/mqtt": { - "MQTT Component Base Configuration": "definitions/CONFIG.MQTT_COMMAND_COMPONENT_SCHEMA", + "MQTT Component Base Configuration": "core.schemas.MQTT_COMMAND_COMPONENT_SCHEMA", + "MQTTMessage": "mqtt.schemas.MQTT_MESSAGE_BASE", }, "components/output/index": { - "Base Output Configuration": "definitions/output.FLOAT_OUTPUT_SCHEMA", + "Base Output Configuration": "output.schemas.FLOAT_OUTPUT_SCHEMA", }, "components/remote_transmitter": { - "Remote Transmitter Actions": "definitions/REMOTE_BASE.BASE_REMOTE_TRANSMITTER_SCHEMA", + "Remote Transmitter Actions": "remote_base.schemas.BASE_REMOTE_TRANSMITTER_SCHEMA", }, "components/sensor/index": { - "Sensor Filters": "sensor.FILTER_REGISTRY", + "Sensor Filters": "sensor.registry.filter", }, "components/time": { - "Home Assistant Time Source": "properties/time/homeassistant", - "SNTP Time Source": "properties/time/sntp", - "GPS Time Source": "properties/time/gps", - "DS1307 Time Source": "properties/time/ds1307", + "_LoadSchema": False, + "Base Time Configuration": "time.schemas.TIME_SCHEMA", + "on_time Trigger": "time.schemas.TIME_SCHEMA.schema.config_vars.on_time.schema", + "Home Assistant Time Source": "homeassistant.platform.time.schemas.CONFIG_SCHEMA", + "SNTP Time Source": "sntp.platform.time.schemas.CONFIG_SCHEMA", + "GPS Time Source": "gps.platform.time.schemas.CONFIG_SCHEMA", + "DS1307 Time Source": "ds1307.platform.time.schemas.CONFIG_SCHEMA", }, "components/wifi": { - "Connecting to Multiple Networks": "definitions/wifi-networks", - "Enterprise Authentication": "definitions/wifi-networks/eap", + "Connecting to Multiple Networks": "wifi.schemas.CONFIG_SCHEMA.schema.config_vars.networks.schema", + "Enterprise Authentication": "wifi.schemas.EAP_AUTH_SCHEMA", }, "custom/custom_component": { - "Generic Custom Component": "properties/custom_component" + "Generic Custom Component": "custom_component.schemas.CONFIG_SCHEMA" }, + "components/esp32": { + "Arduino framework": "esp32.schemas.CONFIG_SCHEMA.schema.config_vars.framework.types.arduino", + "ESP-IDF framework": "esp32.schemas.CONFIG_SCHEMA.schema.config_vars.framework.types.esp-idf", + }, + "components/sensor/airthings_ble": { + "_LoadSchema": False, + }, + "components/sensor/radon_eye_ble": { + "_LoadSchema": False, + }, + "components/sensor/xiaomi_ble": { + "_LoadSchema": False, + }, + "components/sensor/xiaomi_miscale2": { + "_LoadSchema": False, + }, + "components/mcp23Sxx": { + "_LoadSchema": False, + }, + "components/display/lcd_display": {"_LoadSchema": False}, + "components/display/ssd1306": {"_LoadSchema": False}, + "components/display/ssd1322": {"_LoadSchema": False}, + "components/display/ssd1325": {"_LoadSchema": False}, + "components/display/ssd1327": {"_LoadSchema": False}, + "components/display/ssd1351": {"_LoadSchema": False}, + "components/copy": {"_LoadSchema": False}, } @@ -159,6 +197,16 @@ def get_node_title(node): return list(node.traverse(nodes.title))[0].astext() +def read_file(fileName): + f = open(SCHEMA_PATH + fileName + ".json", "r", encoding="utf-8-sig") + str = f.read() + return json.loads(str) + + +def is_config_vars_title(title_text): + return title_text == CONFIGURATION_VARIABLES or title_text == CONFIGURATION_OPTIONS + + class SchemaGeneratorVisitor(nodes.NodeVisitor): def __init__(self, app, doctree, docname): nodes.NodeVisitor.__init__(self, doctree) @@ -170,44 +218,45 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): self.props = None self.platform = None self.json_platform_component = None - self.json_base_config = None self.title_id = None self.props_section_title = None self.find_registry = None + self.component = None self.section_level = 0 + self.file_schema = None + self.custom_doc = CUSTOM_DOCS.get(docname) if self.path[0] == "components": if len(self.path) == 2: # root component, e.g. dfplayer, logger - component = docname[11:] - self.json_component = app.jschema["properties"].get(component) + self.component = docname[11:] + if not self.custom_doc or self.custom_doc.get("_LoadSchema", True): + self.file_schema = get_component_file(app, self.component) + self.json_component = self.file_schema[self.component]["schemas"][ + "CONFIG_SCHEMA" + ] else: # sub component, e.g. output/esp8266_pwm # components here might have a core / hub, eg. dallas, ads1115 # and then they can be a binary_sensor, sensor, etc. - - component = self.path[2] - - if component == "ssd1331": - component = "ssd1331_spi" - self.platform = self.path[1] - if component == "index": - # these are e.g. sensor, binary sensor etc. - p = self.platform.replace(" ", "_").lower() - self.json_component = find_component( - self.app.jschema, self.platform - ) - self.json_base_config = self.app.jschema["definitions"].get( - p + "." + p.upper() + "_SCHEMA" - ) + self.component = self.path[2] - else: - self.json_component = find_component(self.app.jschema, component) + if self.component == "ssd1331": + self.component = "ssd1331_spi" - self.json_platform_component = find_platform_component( - self.app.jschema, self.platform, component - ) - - self.custom_doc = CUSTOM_DOCS.get(docname) + if not self.custom_doc or self.custom_doc.get("_LoadSchema", True): + if self.component == "index": + # these are e.g. sensor, binary sensor etc. + self.component = self.platform.replace(" ", "_").lower() + self.file_schema = get_component_file(app, self.component) + self.json_component = self.file_schema[self.component][ + "schemas" + ].get(self.component.upper() + "_SCHEMA") + pass + else: + self.json_component = get_component_file(app, self.component) + self.json_platform_component = find_platform_component( + app, self.platform, self.component + ) self.previous_title_text = "No title" @@ -231,7 +280,24 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): # Found a Configuration variables: heading, this is to increase docs consistency self.accept_props = False - self.props_level = 0 + self.bullet_list_level = 0 + + def set_component_description(self, description, componentName, platformName=None): + if platformName is not None: + platform = get_component_file(self.app, platformName) + platform[platformName]["components"][componentName.lower()][ + "docs" + ] = description + else: + core = get_component_file(self.app, "esphome")["core"] + if componentName in core["components"]: + core["components"][componentName]["docs"] = description + elif componentName in core["platforms"]: + core["platforms"][componentName]["docs"] = description + else: + raise ValueError( + "Cannot set description for component " + componentName + ) def visit_document(self, node): # ESPHome page docs follows strict formatting guidelines which allows @@ -241,6 +307,10 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): # temporarily not supported raise nodes.SkipChildren + if self.docname in ["components/climate/climate_ir"]: + # not much to do on the visit to the document, component will be found by title + return + if len(list(node.traverse(nodes.paragraph))) == 0: # this is empty, not much to do raise nodes.SkipChildren @@ -251,32 +321,40 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): description = self.getMarkdownParagraph(node) if self.json_platform_component: - self.json_platform_component["markdownDescription"] = description + self.set_component_description(description, self.component, self.platform) elif self.json_component: - self.json_component["markdownDescription"] = description - - if self.json_base_config: - self.json_component = self.json_base_config + self.set_component_description(description, self.component) # for most components / platforms get the props, this allows for a less restrictive # first title on the page if self.json_component or self.json_platform_component: - self.props = self.find_props( - self.json_platform_component - if self.json_platform_component - else self.json_component - ) + if is_component_file( + self.app, + self.component, + ): + self.props = self.find_props( + self.json_platform_component + if self.json_platform_component + else self.json_component, + True, + ) - if not self.props: - # get props for base components, Sensor, Binary Sensor, Light, etc. - - if len(self.path) == 2: - # "#/definitions/schema_canbus.CONFIG_SCHEMA" - self.json_base_config = self.app.jschema["definitions"].get( - f"{self.path[1]}.{self.path[1].upper()}_SCHEMA" - ) - if self.json_base_config: - self.props = self.find_props(self.json_base_config) + def visit_table(self, node): + if ( + self.docname == "components/climate/climate_ir" + and len(CUSTOM_DOCS["components/climate/climate_ir"]["IR Remote Climate"]) + == 0 + ): + # figure out multi components from table + table_rows = node[0][4] + for row in table_rows: + components_paths = [ + components + ".platform.climate.schemas.CONFIG_SCHEMA" + for components in row[1].astext().split("\n") + ] + CUSTOM_DOCS["components/climate/climate_ir"][ + "IR Remote Climate" + ] += components_paths def depart_document(self, node): pass @@ -286,13 +364,8 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): 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 + if ".registry." in r: + self.find_registry = r def depart_section(self, node): self.section_level -= 1 @@ -307,15 +380,16 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): def visit_title(self, node): title_text = node.astext() - - if "interval" in title_text: - title_text = title_text if self.custom_doc is not None and title_text in self.custom_doc: if isinstance(self.custom_doc[title_text], list): self.multi_component = self.custom_doc[title_text] self.filled_props = False self.props = None - # TODO: add same markdown description to each? + + desc = self.getMarkdownParagraph(node.parent) + for c in self.multi_component: + if len(c.split(".")) == 2: + self.set_component_description(desc, c.split(".")[0]) return @@ -323,36 +397,46 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): if not json_component: return - json_component["markdownDescription"] = self.getMarkdownParagraph( - node.parent - ) + parts = self.custom_doc[title_text].split(".") + if parts[0] not in ["core", "remote_base"] and parts[-1] != "pin": + if parts[1] == "platform": + self.set_component_description( + self.getMarkdownParagraph(node.parent), parts[0], parts[2] + ) + else: + self.set_component_description( + self.getMarkdownParagraph(node.parent), + parts[0], + ) self.props_section_title = title_text self.props = self.find_props(json_component) return - if title_text == COMPONENT_HUB: + elif title_text == COMPONENT_HUB: # here comes docs for the component, make sure we have props of the component # Needed for e.g. ads1115 self.props_section_title = f"{self.path[-1]} {title_text}" - json_component = find_component(self.app.jschema, self.path[-1]) + json_component = self.get_component_schema( + self.path[-1] + ".CONFIG_SCHEMA" + ).get("schema", {}) if json_component: self.props = self.find_props(json_component) - json_component["markdownDescription"] = self.getMarkdownParagraph( - node.parent + self.set_component_description( + self.getMarkdownParagraph(node.parent), self.path[-1] ) # mark this to retrieve components instead of platforms self.is_component_hub = True - if title_text == CONFIGURATION_VARIABLES: + elif is_config_vars_title(title_text): if not self.props and self.multi_component is None: raise ValueError( - f'Found a "{CONFIGURATION_VARIABLES}": title after {self.previous_title_text}. Unknown object.' + f'Found a "{title_text}": title after {self.previous_title_text}. Unknown object.' ) - if title_text == "Over SPI" or title_text == "Over I²C": + elif title_text == "Over SPI" or title_text == "Over I²C": suffix = "_spi" if "SPI" in title_text else "_i2c" # these could be platform components, like the display's ssd1306 @@ -365,7 +449,7 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): if self.platform is not None and not self.is_component_hub: json_platform_component = find_platform_component( - self.app.jschema, self.platform, component + self.app, self.platform, component ) if not json_platform_component: raise ValueError( @@ -374,12 +458,12 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): self.props = self.find_props(json_platform_component) # Document first paragraph is description of this thing - json_platform_component[ - "markdownDescription" - ] = self.getMarkdownParagraph(node.parent) + json_platform_component["docs"] = self.getMarkdownParagraph(node.parent) else: - json_component = find_component(self.app.jschema, component) + json_component = self.get_component_schema( + component + ".CONFIG_SCHEMA" + ).get("schema", {}) if not json_component: raise ValueError( f"Cannot find component '{component}' after found title: '{title_text}'." @@ -387,12 +471,12 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): self.props = self.find_props(json_component) # Document first paragraph is description of this thing - json_component["markdownDescription"] = self.getMarkdownParagraph( - node.parent + self.set_component_description( + self.getMarkdownParagraph(node.parent), component ) # Title is description of platform component, those ends with Sensor, Binary Sensor, Cover, etc. - if ( + elif ( len( list( filter( @@ -405,26 +489,45 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): if title_text in PLATFORMS_TITLES: # this omits the name of the component, but we know the platform platform_name = PLATFORMS_TITLES[title_text] - component_name = self.path[-1] - self.props_section_title = self.path[-1] + " " + title_text + if self.path[-1] == "index": + component_name = self.path[-2] + else: + component_name = self.path[-1] + self.props_section_title = component_name + " " + title_text else: - # title first word is the component name - component_name = title_text.split(" ")[0] - # and the rest is the platform - platform_name = PLATFORMS_TITLES.get( - title_text[len(component_name) + 1 :] - ) + # # title first word is the component name + # component_name = title_text.split(" ")[0] + # # and the rest is the platform + # platform_name = PLATFORMS_TITLES.get( + # title_text[len(component_name) + 1 :] + # ) + # if not platform_name: + # # Some general title which does not locate a component directly + # return + # self.props_section_title = title_text + + for t in PLATFORMS_TITLES: + if title_text.endswith(t): + component_name = title_text[ + 0 : len(title_text) - len(t) - 1 + ].replace(" ", "_") + platform_name = PLATFORMS_TITLES[t] + if not platform_name: # Some general title which does not locate a component directly return self.props_section_title = title_text - c = find_platform_component( - self.app.jschema, platform_name, component_name.lower() - ) + if not is_component_file(self.app, component_name): + return + + c = find_platform_component(self.app, platform_name, component_name.lower()) if c: self.json_platform_component = c - - c["markdownDescription"] = self.getMarkdownParagraph(node.parent) + self.set_component_description( + self.getMarkdownParagraph(node.parent), + component_name, + platform_name, + ) # Now fill props for the platform element try: @@ -432,34 +535,50 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): except KeyError: raise ValueError("Cannot find platform props") - if title_text.endswith("Component") or title_text.endswith("Bus"): + elif title_text.endswith("Component") or title_text.endswith("Bus"): # if len(path) == 3 and path[2] == 'index': # # skip platforms index, e.g. sensors/index # continue split_text = title_text.split(" ") self.props_section_title = title_text - if len(split_text) == 2: - # some components are several components in a single platform doc - # e.g. ttp229 binary_sensor has two different named components. - component_name = split_text[0].lower().replace(".", "") - if component_name.lower() == self.platform: - return - c = find_component(self.app.jschema, component_name) - if c: - self.json_component = c - try: - self.props = self.find_props(self.json_component) - self.multi_component = None - except KeyError: - raise ValueError( - "Cannot find props for component " + component_name - ) - return - c = find_platform_component( - self.app.jschema, self.path[1], component_name - ) - if c: - self.json_platform_component = c + + # some components are several components in a single platform doc + # e.g. ttp229 binary_sensor has two different named components. + component_name = ( + "_".join(split_text[:-1]).lower().replace(".", "").replace("i²c", "i2c") + ) + + if component_name != self.platform and is_component_file( + self.app, component_name + ): + f = get_component_file(self.app, component_name) + + # Document first paragraph is description of this thing + description = self.getMarkdownParagraph(node.parent) + + if component_name in f: + self.set_component_description(description, component_name) + + c = f[component_name] + if c: + self.json_component = c["schemas"]["CONFIG_SCHEMA"] + try: + self.props = self.find_props(self.json_component) + self.multi_component = None + except KeyError: + raise ValueError( + "Cannot find props for component " + component_name + ) + return + + # component which are platforms in doc, used by: stepper and canbus, lcd_pcf8574 + elif f"{component_name}.{self.path[1]}" in f: + self.set_component_description( + description, component_name, self.path[1] + ) + self.json_platform_component = f[ + f"{component_name}.{self.path[1]}" + ]["schemas"]["CONFIG_SCHEMA"] try: self.props = self.find_props(self.json_platform_component) @@ -469,7 +588,7 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): ) return - if title_text.endswith("Trigger"): + elif title_text.endswith("Trigger"): # Document first paragraph is description of this thing description = self.getMarkdownParagraph(node.parent) split_text = title_text.split(" ") @@ -477,29 +596,26 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): return key = split_text[0] - # handles Time / on_time - c = self.json_base_config or self.json_component - if c: - trigger_schema = self.find_props(c).get(key) - if trigger_schema is not None: - self.props = self.find_props(trigger_schema) + if ( + not self.props or not self.props.typed + ): # props are right for typed components so far + c = self.json_component + if c: + trigger_schema = self.find_props(c).get(key) + if trigger_schema is not None: + self.props = self.find_props(trigger_schema) self.props_section_title = title_text - 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]}") + elif title_text == PIN_CONFIGURATION_VARIABLES: + self.component = self.find_component(self.path[-1] + ".pin") + self.props = self.find_props(self.component) self.accept_props = True - self.filled_props = False - self.props = None - if len(self.multi_component) == 0: + if not self.component: 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"): + elif 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(" ") @@ -507,16 +623,24 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): 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) + component_parts = split_text[0].split(".") + if len(component_parts) == 3: + cv = get_component_file(self.app, component_parts[1])[ + component_parts[1] + "." + component_parts[0] + ][split_text[1].lower()][component_parts[2]] + if cv is not None: + cv["docs"] = description + self.props = self.find_props(cv.get("schema", {})) + elif len(component_parts) == 2: + registry_name = ".".join( + [component_parts[0], "registry", split_text[1].lower()] + ) + key = component_parts[1] + self.find_registry_prop(registry_name, key, description) + else: + registry_name = f"core.registry.{split_text[1].lower()}" + # 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 @@ -529,31 +653,37 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): self.find_registry_prop(self.find_registry, key, description) self.props_section_title = title_text - 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' - ) + def get_component_schema(self, name): + parts = name.split(".") + schema_file = get_component_file(self.app, parts[0]) + if parts[1] == "registry": + schema = schema_file.get(parts[0], {}).get(parts[2], {}) + elif len(parts) == 3: + schema = ( + schema_file.get(f"{parts[0]}.{parts[1]}") + .get("schemas", {}) + .get(parts[2], {}) + ) + else: + schema = schema_file.get(parts[0], {}).get("schemas", {}).get(parts[1], {}) + return schema + + def get_component_config_var(self, name, key): + c = self.get_component_schema(name) + if key in c: + return c[key] + if "config_vars" not in c: + return c + if key in c["config_vars"]: + return c["config_vars"][c] def find_registry_prop(self, registry_name, key, description): - registry = self.app.jschema["definitions"][registry_name]["anyOf"] - for item in registry: - if "$ref" in item: - item = self.get_ref(item) - 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}") + c = self.get_component_schema(registry_name) + if key in c: + cv = c[key] + if cv is not None: + cv["docs"] = description + self.props = self.find_props(cv.get("schema", {})) def depart_title(self, node): if self.filled_props: @@ -581,12 +711,12 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): def visit_Text(self, node): if self.multi_component: return - if node.astext() == CONFIGURATION_VARIABLES: + if is_config_vars_title(node.astext()): if not self.props: self.find_props_previous_title() if not self.props: raise ValueError( - f'Found a "{CONFIGURATION_VARIABLES}" entry for unknown object after {self.previous_title_text}' + f'Found a "{node.astext()}" entry for unknown object after {self.previous_title_text}' ) self.accept_props = True @@ -596,13 +726,16 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): pass def visit_paragraph(self, node): - if node.astext() == CONFIGURATION_VARIABLES: + if is_config_vars_title(node.astext()): if not self.props and not self.multi_component: self.find_props_previous_title() if not self.props and not self.multi_component: - raise ValueError( - f'Found a "{CONFIGURATION_VARIABLES}" entry for unknown object after {self.previous_title_text}' + logger.info( + f"In {self.docname} / {self.previous_title_text} found a {node.astext()} title and there are no props." ) + # raise ValueError( + # f'Found a "{node.astext()}" entry for unknown object after {self.previous_title_text}' + # ) self.accept_props = True raise nodes.SkipChildren @@ -611,89 +744,51 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): pass def visit_bullet_list(self, node): - self.props_level = self.props_level + 1 - if self.current_prop and self.props and self.props_level > 1: + self.bullet_list_level = self.bullet_list_level + 1 + if ( + self.current_prop + and (self.props or self.multi_component) + and self.bullet_list_level > 1 + ): - # if '$ref' in self.props[self.current_prop]: - # if self.props[self.current_prop]['$ref'].endswith('_SCHEMA'): - # nowhere put this props info... - # raise nodes.SkipChildren - - # this can be list of values, list of subproperties - - # deep configs - # e.g. wifi manual_ip, could also be a enum list - - # if this prop has a reference - prop = self.props[self.current_prop] - if isinstance(prop, dict): - if "$ref" in prop: - ref = self.get_ref(prop) - self.prop_stack.append(self.props) - self.props = self.find_props(ref) - self.accept_props = True - elif "properties" in prop: - self.prop_stack.append(self.props) - self.props = prop["properties"] - elif ( - "anyOf" in prop - and len(prop["anyOf"]) > 0 - and isinstance(self.get_ref(prop["anyOf"][0]), dict) - and "$ref" in self.get_ref(prop["anyOf"][0]) - ): - ref = self.get_ref(prop["anyOf"][0]) - self.prop_stack.append(self.props) - self.props = self.find_props(ref) - else: - # TODO: if the list items are formatted like: - # - ``value`` - # - ``other value`` - # then we could ensure these are enum values (or populate enum values double check.) - # Currently some enum values are also in the **value** format. - if ( - # most likely an enum, the values are most likely retrieved from ESPHome validation schema - "enum" in prop - # or custom components has list of sensors/binary sensors, etc. - or ( - prop.get("markdownDescription", "").startswith("**list**") - and self.docname.endswith("/custom") - ) - ): - raise nodes.SkipChildren - # nowhere put this props info... - # otherwise inner bullet list will be interpreted as property list - logger = logging.getLogger(__name__) - logger.info( - f"In {self.docname} / {self.previous_title_text} property {self.current_prop} a unknown info sub bullet list." - ) - raise nodes.SkipChildren - else: - # nowhere put this props info... - # otherwise inner bullet list will be interpreted as property list - raise nodes.SkipChildren + self.prop_stack.append((self.current_prop, node)) + self.accept_props = True + return if not self.props and self.multi_component is None: raise nodes.SkipChildren def depart_bullet_list(self, node): - self.props_level = self.props_level - 1 + self.bullet_list_level = self.bullet_list_level - 1 if len(self.prop_stack) > 0: - self.props = self.prop_stack.pop() - self.filled_props = True + stack_prop, stack_node = self.prop_stack[-1] + if stack_node == node: + self.prop_stack.pop() + self.filled_props = True + self.current_prop = stack_prop def visit_list_item(self, node): if self.accept_props and self.props: self.filled_props = True - try: - self.current_prop = self.update_prop(node, self.props) - except Exception as e: - raise ValueError(f"In '{self.previous_title_text}' {str(e)}") + self.current_prop, found = self.update_prop(node, self.props) + if self.current_prop and not found: + logger.info( + f"In '{self.docname} {self.previous_title_text} Cannot find property {self.current_prop}" + ) elif self.multi_component: # update prop for each component + found_any = False + self.current_prop = None for c in self.multi_component: props = self.find_props(self.find_component(c)) - self.current_prop = self.update_prop(node, props) + self.current_prop, found = self.update_prop(node, props) + if self.current_prop and found: + found_any = True + if self.current_prop and not found_any: + logger.info( + f"In '{self.docname} {self.previous_title_text} Cannot find property {self.current_prop}" + ) self.filled_props = True def depart_list_item(self, node): @@ -713,7 +808,7 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): self.doctree, ) node.walkabout(t) - return t.output + return t.output.strip("\n") def getMarkdownParagraph(self, node): paragraph = list(node.traverse(nodes.paragraph))[0] @@ -748,14 +843,58 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): return markdown def update_prop(self, node, props): + prop_name = None + for s_prop, n in self.prop_stack: + inner = props.get(s_prop) + if inner is not None and "schema" in inner: + props = self.Props(self, inner["schema"]) + elif inner is not None and inner.get("type") == "typed": + # this is used in external_components + props = self.Props(self, inner) + elif inner is not None and inner.get("type") == "enum": + enum_raw = self.getMarkdown(node) + # the regex allow the format to have either a ":" or a " -" as the value / docs separator, value must be in `back ticks` + # also description is optional + enum_match = re.search( + r"\* `([^`]*)`((:| -) (.*))*", enum_raw, re.IGNORECASE + ) + if enum_match: + enum_value = enum_match.group(1) + enum_docs = enum_match.group(4) + found = False + for name in inner["values"]: + if enum_value.upper().replace(" ", "_") == str(name).upper(): + found = True + if enum_docs: + enum_docs = enum_docs.strip() + if "values_docs" not in inner: + inner["values_docs"] = {name: enum_docs} + else: + inner["values_docs"][name] = enum_docs + statistics.props_documented += 1 + statistics.enums_good += 1 + if not found: + logger.info( + f"In '{self.docname} {self.previous_title_text} Property {s_prop} cannot find enum value {enum_value}" + ) + else: + statistics.enums_bad += 1 + logger.info( + f"In '{self.docname} {self.previous_title_text} Property {s_prop} unexpected enum member description format" + ) + + else: + # nothing to do? + return prop_name, False + raw = node.rawsource # this has the full raw rst code for this property if not raw.startswith("**"): # not bolded, most likely not a property definition, # usually texts like 'All properties from...' etc - return None + return prop_name, False markdown = self.getMarkdown(node) @@ -764,7 +903,10 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): try: name_type = markdown[: markdown.index(": ") + 2] except ValueError: - raise ValueError(f'Property format error. Missing ": " in {raw}') + logger.info( + f"In '{self.docname} {self.previous_title_text} Property format error. Missing ': ' in {raw}'" + ) + return prop_name, False # Example properties formats are: # **name** (**Required**, string): Long Description... @@ -793,11 +935,16 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): prop_name = s3.group(1) param_type = None else: - raise ValueError(f"Invalid property format: {node.rawsource}") + logger.info( + f"In '{self.docname} {self.previous_title_text} Invalid property format: {node.rawsource}" + ) + return prop_name, False k = str(prop_name) - jprop = props.get(k) - if not jprop: + + config_var = props.get(k) + + if not config_var: # Create docs for common properties when descriptions are overridden # in the most specific component. @@ -816,10 +963,10 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): "effects", "gamma_correct", "default_transition_length", + "flash_transition_length", "color_correct", # display "lambda", - "dither", "pages", "rotation", # spi @@ -831,126 +978,122 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): # climate "receiver_id", ]: - jprop = props[k] = {} + config_var = props[k] = {} else: - raise ValueError(f"Cannot find property {k}") + if self.path[1] == "esphome" and k in [ + # deprecated esphome + "platform", + "board", + "arduino_version", + "esp8266_restore_from_flash", + ]: + return prop_name, True + return prop_name, False desc = markdown[markdown.index(": ") + 2 :].strip() if param_type: desc = "**" + param_type + "**: " + desc - jprop["markdownDescription"] = desc - global props_documented - props_documented = props_documented + 1 + config_var["docs"] = desc - return prop_name + statistics.props_documented += 1 - def get_ref(self, node): - ref = node.get("$ref") - if ref and ref.startswith("#/definitions/"): - return self.app.jschema["definitions"][ref[14:]] + return prop_name, True 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]] + path = component_path.split(".") + file_content = get_component_file(self.app, path[0]) - if len(path) > 2: - # a property path - props = self.find_props(json_component) - if props: - json_component = props.get(path[2]) - else: - # a platform sub element - json_component = find_platform_component( - self.app.jschema, path[1], path[2] - ) - return json_component + if path[1] == "platform": + path[2] = f"{path[0]}.{path[2]}" + path = path[2:] + + component = file_content + for p in path: + component = component.get(p, {}) + + return component class Props(MutableMapping): """Smarter props dict. Props are mostly a dict, however some constructs have two issues: - An update is intended on an element which does not own a property, but it is based - on an schema that does have the property, those cases can be handled - - An update is done in a typed schema + on an schema that does have the property, those cases are handled by examining the extended + """ - def __init__(self, visitor, component): + def __init__(self, visitor, component, fail_silently=False): self.visitor = visitor self.component = component - self.store = self._get_props(component) + self.store = self._get_props(component, fail_silently) self.parent = None + self.typed = self.component.get("type") == "typed" - def _get_props(self, component): - # 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._get_props(self.visitor.get_ref(component)) + def _get_props(self, component, fail_silently): + # component is a 'schema' dict which has 'config_vars' and 'extends' + if not ( + "config_vars" in component + or "extends" in component + or len(component) == 0 + or component.get("type") == "typed" + ): + if fail_silently: return None - for x in arr: - props = x.get("properties") - if not ref: - ref = self.visitor.get_ref(x) - if props: - break - if not props and ref: - props = self._get_props(ref) + raise ValueError("Unexpected component data to get props") + + props = component.get("config_vars") return props + def _find_extended(self, component, key): + for extended in component.get("extends", []): + schema = self.visitor.get_component_schema(extended).get("schema", {}) + for k, cv in schema.get("config_vars", {}).items(): + if k == key: + return SetObservable( + cv, + setitem_callback=self._set_extended, + inner_key=key, + original_dict=schema.get("config_vars"), + ) + ex1 = self._find_extended(schema, key) + if ex1: + return ex1 + + def _set_extended(self, inner_key, original_dict, key, value): + original_dict[inner_key][key] = value + + def _iter_extended(self, component): + for extended in component.get("extends", []): + schema = self.visitor.get_component_schema(extended).get("schema", {}) + for s in self._iter_extended(schema): + yield s + yield schema + def __getitem__(self, key): if self.store and key in self.store: return self.store[key] - if "then" in self.component: - # check if it's typed - schemas = self.component["then"].get("allOf") - if ( - isinstance(schemas, list) - and "properties" in schemas[0] - and "type" in schemas[0]["properties"] - ): - for s in schemas: - if "then" in s: - props = self._get_props(s.get("then")) - if key in props: - return SetObservable( - props[key], - setitem_callback=self._update_typed, - inner_key=key, - ) - return # key not found + extended = self._find_extended(self.component, key) + if extended is not None: + return extended - # check if it's a registry and need to reset store - # e.g. remote_receiver binary sensor - if "$ref" in self.component["then"]: - ref = self.visitor.get_ref(self.component["then"]) - prop_set = ref.get("anyOf") - if isinstance(prop_set, list): - for k in prop_set: - if "$ref" in k: - k = self.visitor.get_ref(k) - if key in k["properties"]: - self.store = k["properties"] - return self.store[key] + if self.component.get("type") == "typed": + return SetObservable( + {key: {"type": "string"}}, + setitem_callback=self._set_typed, + inner_key=key, + original_dict={}, + ) - def _update_typed(self, inner_key, key, value): - # Make sure we update all types - if "then" in self.component: - schemas = self.component["then"].get("allOf") - assert "type" in schemas[0].get("properties") - for s in schemas: - if "then" in s: - props = self._get_props(s.get("then")) - if inner_key in props: - props[inner_key][key] = value + def _set_typed(self, inner_key, original_dict, key, value): + if inner_key == self.component.get("typed_key"): + self.component[key] = value + else: + for tk, tv in self.component["types"].items(): + for cv_k, cv_v in tv["config_vars"].items(): + if cv_k == inner_key: + cv_v[key] = value def __setitem__(self, key, value): self.store[key] = value @@ -962,10 +1105,28 @@ class SchemaGeneratorVisitor(nodes.NodeVisitor): return iter(self.store) def __len__(self): - return len(self.store) if self.store else 0 + len_extended = 0 - def find_props(self, component): - props = self.Props(self, component) + if self.component.get("type"): + types = self.component.get("types") + for t, tv in types.items(): + for s in self._iter_extended(types.get(t, {})): + len_extended += len(s.get("config_vars", {})) + len_extended += len(tv.get("config_vars", {})) + return len_extended + + for s in self._iter_extended(self.component): + len_extended += len(s.get("config_vars", {})) + return len_extended + (len(self.store) if self.store else 0) + + def find_props(self, component, fail_silently=False): + if component.get("type") in ["trigger", "schema"]: + # can have schema + if "schema" not in component: + return None + component = component.get("schema") + + props = self.Props(self, component, fail_silently) if props: self.filled_props = False @@ -989,11 +1150,14 @@ def handle_component(app, doctree, docname): def build_finished(app, exception): # TODO: create report of missing descriptions - f = open(SCHEMA_PATH, "w") - f.write(json.dumps(app.jschema)) + for fname, contents in app.files.items(): + f = open(SCHEMA_PATH + fname + ".json", "w") + if JSON_DUMP_PRETTY: + f.write(json.dumps(contents, indent=2)) + else: + f.write(json.dumps(contents, separators=(",", ":"))) - str = f"Documented: {props_documented}" - logger = logging.getLogger(__name__) + str = f"Documented: {statistics.props_documented} Enums: {statistics.enums_good}/{statistics.enums_bad}" logger.info(str) @@ -1004,12 +1168,35 @@ class SetObservable(dict): MyDict instance was created """ - def __init__(self, value, setitem_callback=None, inner_key=None, *args, **kwargs): + def __init__( + self, + value, + setitem_callback=None, + inner_key=None, + original_dict=None, + *args, + **kwargs, + ): super(SetObservable, self).__init__(value, *args, **kwargs) self._setitem_callback = setitem_callback self.inner_key = inner_key + self.original_dict = original_dict def __setitem__(self, key, value): if self._setitem_callback: - self._setitem_callback(self.inner_key, key, value) + self._setitem_callback(self.inner_key, self.original_dict, key, value) super(SetObservable, self).__setitem__(key, value) + + +def is_component_file(app: SchemaGeneratorVisitor, component): + if component == "core" or component == "automation": + component = "esphome" + return exists(SCHEMA_PATH + component + ".json") + + +def get_component_file(app: SchemaGeneratorVisitor, component): + if component == "core" or component == "automation": + component = "esphome" + if component not in app.files: + app.files[component] = read_file(component) + return app.files[component]