diff --git a/_redirects b/_redirects index 2e8b63402b..757b76940b 100644 --- a/_redirects +++ b/_redirects @@ -14,6 +14,20 @@ /components/sensor/mmc5063.html /components/sensor/mmc5603.html 301 /components/sensor/kalman_combinator.html /components/sensor/combination.html 301 +/components/binary_sensor/custom* /guides/contributing#a-note-about-custom-components 301 +/components/climate/custom* /guides/contributing#a-note-about-custom-components 301 +/components/cover/custom* /guides/contributing#a-note-about-custom-components 301 +/components/light/custom* /guides/contributing#a-note-about-custom-components 301 +/components/output/custom* /guides/contributing#a-note-about-custom-components 301 +/components/sensor/custom* /guides/contributing#a-note-about-custom-components 301 +/components/switch/custom* /guides/contributing#a-note-about-custom-components 301 +/components/text_sensor/custom* /guides/contributing#a-note-about-custom-components 301 +/custom/custom_component* /guides/contributing#a-note-about-custom-components 301 +/custom/i2c* /guides/contributing#a-note-about-custom-components 301 +/custom/index* /guides/contributing#a-note-about-custom-components 301 +/custom/spi* /guides/contributing#a-note-about-custom-components 301 +/custom/uart* /guides/contributing#a-note-about-custom-components 301 + /cookbook/brilliant-mirabella-genio-smart-plugs.html https://devices.esphome.io/devices/Mirabella-Genio-Wi-Fi-1-USB 301 /cookbook/zemismart-rgbw-downlights.html https://devices.esphome.io/devices/Zemismart-LED-RGBWW-Downlight 301 /cookbook/relay.html https://devices.esphome.io/devices/Generic-Relay 301 diff --git a/changelog/v1.14.0.rst b/changelog/v1.14.0.rst index 842e4a4e3a..fdca211e64 100644 --- a/changelog/v1.14.0.rst +++ b/changelog/v1.14.0.rst @@ -276,7 +276,7 @@ Notable Changes & New Features generated using automated scripts. This is a big step towards making the API more flexible, for example cross-device communication (:esphomepr:`633`). - New class :apiclass:`api::CustomAPIDevice` to declare user-defined services straight from custom components. - See the updated :doc:`custom component guide `. + See the updated custom component guide. - :ref:`Sensors ` have a new ``force_update`` option (:esphomepr:`783`). - Add GPIO Switch :ref:`interlock_wait_time ` (:esphomepr:`777`). - Add a configurable priority for WiFi network selection (:esphomepr:`658`, :doc:`docs `). diff --git a/components/binary_sensor/custom.rst b/components/binary_sensor/custom.rst deleted file mode 100644 index 40d56a2499..0000000000 --- a/components/binary_sensor/custom.rst +++ /dev/null @@ -1,87 +0,0 @@ -Custom Binary Sensor -==================== - -.. seo:: - :description: Instructions for setting up Custom C++ binary sensors with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -This component can be used to create custom binary sensors in ESPHome using the C++ (Arduino) API. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here and binary -sensors are very similar to sensors internally. - -The example below is an example of a custom binary sensor; this custom sensor is essentially the -same as the gpio binary sensor. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomBinarySensor : public PollingComponent, public BinarySensor { - public: - // constructor - MyCustomBinarySensor() : PollingComponent(15000) {} - - void setup() override { - // This will be called by App.setup() - pinMode(5, INPUT); - } - void update() override { - // This will be called every "update_interval" milliseconds. - - // Publish an OFF state - bool state = digitalRead(5); - publish_state(state); - } - }; - -(Store this file in your configuration directory, for example ``my_binary_sensor.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_binary_sensor.h - - binary_sensor: - - platform: custom - lambda: |- - auto my_custom_sensor = new MyCustomBinarySensor(); - App.register_component(my_custom_sensor); - return {my_custom_sensor}; - - binary_sensors: - name: "My Custom Binary Sensor" - -Configuration variables: - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - binary sensor(s). -- **binary_sensors** (**Required**, list): A list of binary sensors to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Binary Sensor `. - -See :apiclass:`BinarySensor ` - -See Also --------- - -- :ghedit:`Edit` diff --git a/components/climate/custom.rst b/components/climate/custom.rst deleted file mode 100644 index 6fece0e1b9..0000000000 --- a/components/climate/custom.rst +++ /dev/null @@ -1,105 +0,0 @@ -Custom Climate -============== - -.. seo:: - :description: Instructions for setting up Custom C++ climate components with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -This component can be used to create custom climate devices in ESPHome using the C++ (Arduino) API. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here. - -The example below is an example of a custom climate device - all climate devices must override -two methods (:apiclass:`Climate `): - -- ``traits``: This should return a :apiclass:`ClimateTraits ` object - representing the capabilities of the climate device. -- ``control``: This receives a :apiclass:`ClimateCall ` object that contains - the command the user tried to set. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomClimate : public Component, public Climate { - public: - void setup() override { - // This will be called by App.setup() - } - void control(const ClimateCall &call) override { - if (call.get_mode().has_value()) { - // User requested mode change - ClimateMode mode = *call.get_mode(); - // Send mode to hardware - // ... - - // Publish updated state - this->mode = mode; - this->publish_state(); - } - if (call.get_target_temperature().has_value()) { - // User requested target temperature change - float temp = *call.get_target_temperature(); - // Send target temp to climate - // ... - } - } - ClimateTraits traits() override { - // The capabilities of the climate device - auto traits = climate::ClimateTraits(); - traits.set_supports_current_temperature(true); - traits.set_supported_modes({climate::CLIMATE_MODE_HEAT_COOL}); - return traits; - } - }; - -(Store this file in your configuration directory, for example ``my_climate.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_climate.h - - climate: - - platform: custom - lambda: |- - auto my_custom_climate = new MyCustomClimate(); - App.register_component(my_custom_climate); - return {my_custom_climate}; - - climates: - - name: "My Custom Climate" - -Configuration variables: - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - climate(s). -- **climates** (**Required**, list): A list of climates to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Climate `. - -See :apiclass:`Climate ` - -See Also --------- - -- :ghedit:`Edit` diff --git a/components/cover/custom.rst b/components/cover/custom.rst deleted file mode 100644 index 413333769d..0000000000 --- a/components/cover/custom.rst +++ /dev/null @@ -1,103 +0,0 @@ -Custom Cover -============ - -.. seo:: - :description: Instructions for setting up Custom C++ covers with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -This component can be used to create custom covers in ESPHome using the C++ (Arduino) API. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here. - -The example below is an example of a custom cover - all covers must override two methods: - -- ``get_traits``: This should return a :apiclass:`CoverTraits ` object - representing the capabilities of the cover. -- ``control``: This receives a :apiclass:`CoverCall ` object that contains - the command the user tried to set. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomCover : public Component, public Cover { - public: - void setup() override { - // This will be called by App.setup() - pinMode(5, INPUT); - } - CoverTraits get_traits() override { - auto traits = CoverTraits(); - traits.set_is_assumed_state(false); - traits.set_supports_position(true); - traits.set_supports_tilt(false); - traits.set_supports_stop(true); - return traits; - } - void control(const CoverCall &call) override { - // This will be called every time the user requests a state change. - if (call.get_position().has_value()) { - float pos = *call.get_position(); - // Write pos (range 0-1) to cover - // ... - - // Publish new state - this->position = pos; - this->publish_state(); - } - if (call.get_stop()) { - // User requested cover stop - } - } - }; - -(Store this file in your configuration directory, for example ``my_cover.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_cover.h - - cover: - - platform: custom - lambda: |- - auto my_custom_cover = new MyCustomCover(); - App.register_component(my_custom_cover); - return {my_custom_cover}; - - covers: - - name: "My Custom Cover" - -Configuration variables: - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - cover(s). -- **covers** (**Required**, list): A list of covers to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Cover `. - -See :apiclass:`Cover ` - -See Also --------- - -- :ghedit:`Edit` diff --git a/components/esphome.rst b/components/esphome.rst index f08aeb797b..285b4f9cf6 100644 --- a/components/esphome.rst +++ b/components/esphome.rst @@ -45,9 +45,9 @@ Advanced options: as default one in case it is mounted to it. - **platformio_options** (*Optional*, mapping): Additional options to pass over to PlatformIO in the platformio.ini file. See :ref:`esphome-platformio_options`. -- **includes** (*Optional*, list of files): A list of C/C++ files to include in the main (auto-generated) sketch file - for custom components. The paths in this list are relative to the directory where the YAML configuration file - is in. See :ref:`esphome-includes`. +- **includes** (*Optional*, list of files): A list of C/C++ files to include in the (auto-generated) ``main`` file. + The paths in this list are relative to the directory where the YAML configuration file is located. See + :ref:`esphome-includes`. - **libraries** (*Optional*, list of libraries): A list of libraries to include in the project. See :ref:`esphome-libraries`. - **comment** (*Optional*, string): Additional text information about this node. Only for display in UI. @@ -221,9 +221,8 @@ This option behaves differently depending on what the included file is pointing ``libraries`` ------------- -With the ``libraries`` option it is possible to include libraries in the PlatformIO project. These libraries will then -be compiled into the resulting firmware, and can be used in code from :ref:`lambdas ` and from -custom components. +The ``libraries`` option allows you to include libraries in the PlatformIO project. These libraries will then be +compiled into the resulting firmware and may be used by :ref:`lambdas `. .. code-block:: yaml diff --git a/components/light/custom.rst b/components/light/custom.rst deleted file mode 100644 index 748d6855f6..0000000000 --- a/components/light/custom.rst +++ /dev/null @@ -1,94 +0,0 @@ -Custom Light Output -=================== - -.. seo:: - :description: Instructions for setting up Custom C++ lights with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -This component can be used to create custom lights in ESPHome using the C++ (Arduino) API. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here. - -All internal stuff (like effects, transitions etc) is handled by the light core -and cannot be overridden. Light outputs are only responsible for displaying some state -when asked to do so. - -The example below is an example of a custom light output. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomLightOutput : public Component, public LightOutput { - public: - void setup() override { - // This will be called by App.setup() - pinMode(5, INPUT); - } - LightTraits get_traits() override { - // return the traits this light supports - auto traits = LightTraits(); - traits.set_supported_color_modes({ColorMode::RGB, ColorMode::BRIGHTNESS}); - return traits; - } - - void write_state(LightState *state) override { - // This will be called by the light to get a new state to be written. - float red, green, blue; - // use any of the provided current_values methods - state->current_values_as_rgb(&red, &green, &blue); - // Write red, green and blue to HW - // ... - } - }; - -(Store this file in your configuration directory, for example ``my_light.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_light.h - - light: - - platform: custom - lambda: |- - auto light_out = new MyCustomLightOutput(); - App.register_component(light_out); - return {light_out}; - - lights: - - name: "My Custom Light" - -Configuration variables: - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - light output(s). -- **lights** (**Required**, list): A list of lights to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Light `. - -See :apiclass:`Light ` - -See Also --------- - -- :ghedit:`Edit` diff --git a/components/output/custom.rst b/components/output/custom.rst deleted file mode 100644 index 631e61627c..0000000000 --- a/components/output/custom.rst +++ /dev/null @@ -1,110 +0,0 @@ -Custom Output -============= - -.. seo:: - :description: Instructions for setting up Custom C++ outputs with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -This component can be used to create custom binary and float :doc:`outputs ` -in ESPHome using the C++ (Arduino) API. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here. - -The example below is an example of a custom float output; this custom output is essentially the -same as the :doc:`ESP8266 software PWM output `. - -.. code-block:: cpp - - #include "esphome.h" - using namespace esphome; - - class MyCustomFloatOutput : public Component, public FloatOutput { - public: - void setup() override { - // This will be called by App.setup() - pinMode(5, OUTPUT); - } - - void write_state(float state) override { - // state is the amount this output should be on, from 0.0 to 1.0 - // we need to convert it to an integer first - int value = state * 1024; - analogWrite(5, value); - } - }; - - // Custom binary output, for exposing binary states - class MyCustomBinaryOutput : public Component, public BinaryOutput { - public: - void setup() override { - // This will be called by App.setup() - pinMode(5, OUTPUT); - } - - void write_state(bool state) override { - digitalWrite(5, state); - } - }; - -(Store this file in your configuration directory, for example ``my_output.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_output.h - - output: - - platform: custom - type: float - lambda: |- - auto my_custom_float_output = new MyCustomFloatOutput(); - App.register_component(my_custom_float_output); - return {my_custom_float_output}; - - outputs: - id: custom_float - - - platform: custom - type: binary - lambda: |- - auto my_custom_binary_output = new MyCustomBinaryOutput(); - App.register_component(my_custom_binary_output); - return {my_custom_binary_output}; - - outputs: - id: custom_binary - -Configuration variables: - -- **type** (**Required**, string): The type of output. One of ``binary`` and ``float``. -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - output(s). -- **outputs** (**Required**, list): A list of outputs to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Output `. - -See :apiclass:`output::BinaryOutput` and :apiclass:`output::FloatOutput`. - -See Also --------- - -- :ghedit:`Edit` diff --git a/components/sensor/custom.rst b/components/sensor/custom.rst deleted file mode 100644 index 21d4edb6fd..0000000000 --- a/components/sensor/custom.rst +++ /dev/null @@ -1,446 +0,0 @@ -Custom Sensor Component -======================= - -.. seo:: - :description: Instructions for setting up Custom C++ sensors with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -So, you just set up ESPHome for your ESP32/ESP8266, but sadly ESPHome is missing a sensor component -you'd really like to have 😕. It's pretty much impossible to support every single sensor, as there are simply too many. -That's why ESPHome has a really simple API for you to create your own **custom sensors** 🎉 - -In this guide, we will go through creating a custom sensor component for the -`BMP180 `__ pressure sensor (we will only do the pressure part, -temperature is more or less the same). During this guide, you will learn how to 1. define a custom sensor -ESPHome can use 2. go over how to register the sensor so that it will be shown inside Home Assistant and -3. leverage an existing Arduino library for the BMP180 with ESPHome. - -.. note:: - - Since the creation of this guide, the BMP180 has been officially supported by the :doc:`BMP085 component - `. The code still applies though. - -This guide will require at least a bit of knowledge of C++, so be prepared for that. If you've already written -code for an Arduino, you have already written C++ code :) (Arduino uses a slightly customized version of C++). -If you have any problems, I'm here to help: https://discord.gg/KhAMKrd - -Step 1: Custom Sensor Definition --------------------------------- - -To create your own custom sensor, you just have to create your own C++ class. If you've never heard of that -before, don't worry, at the end of this guide you can just copy the example source code and modify it to your needs -- learning the intricacies of C++ classes won't be required. - -Before you can create your own custom sensors, let's first take a look at the basics: How sensors (and components) -are structured in the ESPHome ecosystem. - -In ESPHome, a **sensor** is some hardware device (like a BMP180) that periodically -sends out numbers, for example a temperature sensor that periodically publishes its temperature **state**. - -Another important abstraction in ESPHome is the concept of a **component**. In ESPHome, -a **component** is an object with a *lifecycle* managed by the :apiclass:`Application` class. -What does this mean? Well if you've coded in Arduino before you might know the two special methods -``setup()`` and ``loop()``. ``setup()`` is called one time when the node boots up and ``loop()`` is called -very often and this is where you can do things like read out sensors etc. - -Components have something similar to that: They also have ``setup()`` and ``loop()`` methods which will be -called by the application kind of like the Arduino functions. - -So, let's now take a look at some code: This is an example of a custom component class (called ``MyCustomSensor`` here): - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomSensor : public Component, public Sensor { - public: - void setup() override { - // This will be called by App.setup() - } - void loop() override { - // This will be called by App.loop() - } - }; - -In the first two lines, we're importing ESPHome so you can use the APIs via the ``#include`` -statement. - -Let's now also take a closer look at this line, which you might not be too used to when writing Arduino code: - -.. code-block:: cpp - - class MyCustomSensor : public Component, public Sensor { - -What this line is essentially saying is that we're defining our own class that's called ``MyCustomSensor`` -which is also a subclass of :apiclass:`Component` and :apiclass:`Sensor `. -As described before, these two "parent" classes have special semantics that we will make use of. - -We *could* go implement our own sensor code now by replacing the contents of ``setup()`` and ``loop()``. -In ``setup()`` we would initialize the sensor and in ``loop()`` we would read out the sensor and publish -the latest values. - -However, there's a small problem with that approach: ``loop()`` gets called very often (about 60 times per second). -If we would publish a new state each time that method is called we would quickly make the node unresponsive. - -So lets fix this, we will use an alternative class to :apiclass:`Component`: :apiclass:`PollingComponent`. -This class is for situations where you have something that should get called repeatedly with some **update interval**. -In the code above, we can simply replace :apiclass:`Component` by :apiclass:`PollingComponent` and -``loop()`` by a special method ``update()`` which will be called with an interval we can specify. - -.. code-block:: cpp - - class MyCustomSensor : public PollingComponent, public Sensor { - public: - // constructor - MyCustomSensor() : PollingComponent(15000) {} - - void setup() override { - // This will be called by App.setup() - } - void update() override { - // This will be called every "update_interval" milliseconds. - } - }; - - -Our code has slightly changed, as explained above we're now inheriting from :apiclass:`PollingComponent` instead of -just :apiclass:`Component`. Additionally, we now have a new line: the constructor. You also don't really need to -know much about constructors here, so to simplify let's just say this is where we "initialize" the custom sensor. - -In this constructor we're telling the compiler that we want :apiclass:`PollingComponent` to be instantiated with an -*update interval* of 15s, or 15000 milliseconds (ESPHome uses milliseconds internally). - -Let's also now make our sensor actually publish values in the ``update()`` method: - -.. code-block:: cpp - - // class MyCustomSensor ... - // ... previous code - void update() override { - publish_state(42.0); - } - }; - -Every time ``update`` is called we will now **publish** a new value to the frontend. -The rest of ESPHome will then take care of processing this value and ultimately publishing it -to the outside world (for example using MQTT). - -One last thing. Some sensors, such as the BMP180 were are going to explain later, require some other component before they can be used. Remember how we talked about the ``setup()`` method? Well just like when writing in the Arduino IDE, components need to be set up in the right order. For that ESPHome introduces another method in the :apiclass:`Component` class. - -.. code-block:: cpp - - float get_setup_priority() const override { return esphome::setup_priority::HARDWARE; } - -Where HARDWARE can be any of: - -.. code-block:: cpp - - /// For communication buses like i2c/spi - extern const float BUS; - /// For components that represent GPIO pins like PCF8573 - extern const float IO; - /// For components that deal with hardware and are very important like GPIO switch - extern const float HARDWARE; - /// For components that import data from directly connected sensors like DHT. - extern const float DATA; - /// Alias for DATA (here for compatibility reasons) - extern const float HARDWARE_LATE; - /// For components that use data from sensors like displays - extern const float PROCESSOR; - extern const float WIFI; - /// For components that should be initialized after WiFi is connected. - extern const float AFTER_WIFI; - /// For components that should be initialized after a data connection (API/MQTT) is connected. - extern const float AFTER_CONNECTION; - /// For components that should be initialized at the very end of the setup process. - extern const float LATE; - -Now don't let the wording confuse you. The ``get_setup_priority()`` method is an override. Instead of fetching the setup priority setup for us, it instead fetches the setup priority for esphome, while being defined by us. The BMP180 would for instance need to be setup with a priority of IO or lower. A serial streaming (TCP) server would require a working WIFI setup and therefore get AFTER_WIFI. - -This finalizes our example as: - -.. code-block:: cpp - - class MyCustomSensor : public PollingComponent, public Sensor { - public: - // constructor - MyCustomSensor() : PollingComponent(15000) {} - - float get_setup_priority() const override { return esphome::setup_priority::XXXX; } - - void setup() override { - // This will be called by App.setup() - } - void update() override { - // This will be called every "update_interval" milliseconds. - } - }; - -Step 2: Registering the custom sensor -------------------------------------- - -Now we have our Custom Sensor set up, but unfortunately it doesn't do much right now. -Actually ... it does nothing because it's never included nor instantiated. -First, create a new file called ``my_custom_sensor.h`` in your configuration directory and copy the source code -from above into that file. - -Then in the YAML config, *include* that file in the top-level ``esphome`` section like this: - -.. code-block:: yaml - - esphome: - # ... [Other options] - includes: - - my_custom_sensor.h - -Next, create a new ``custom`` sensor platform entry like this: - -.. code-block:: yaml - - # Example configuration entry - sensor: - - platform: custom - lambda: |- - auto my_sensor = new MyCustomSensor(); - App.register_component(my_sensor); - return {my_sensor}; - - sensors: - name: "My Custom Sensor" - -Let's break this down: - -- First, we specify a :ref:`lambda ` that will be used to **instantiate** our sensor class. This will - be called on boot to register our sensor in ESPHome. -- In this lambda, we're first creating a new instance of our custom class (``new MyCustomSensor()``) and then - assigning it to a variable called ``my_sensor``. Note: This uses a feature in the C++ standard, ``auto``, to make our - lives easier. We could also have written ``MyCustomSensor *my_sensor = new MyCustomSensor()`` -- Next, as our custom class inherits from Component, we need to **register** it - otherwise ESPHome will not know - about it and won't call our ``setup()`` and ``update`` methods! -- Finally, we ``return`` the custom sensor - don't worry about the curly braces ``{}``, we'll cover that later. -- After that, we just let ESPHome know about our newly created sensor too using the ``sensors:`` block. Additionally, - here we're also assigning the sensor a name. - -Now all that's left to do is upload the code and let it run :) - -If you have Home Assistant MQTT discovery setup, it will even automatically show up in the frontend 🎉 - -.. figure:: images/custom-ui.png - :align: center - :width: 60% - -Step 3: BMP180 support ----------------------- - -Let's finally make this custom sensor useful by adding the BMP180 aspect into it! Sure, printing ``42`` is a nice number -but it won't help with home automation :D - -A great feature of ESPHome is that you don't need to code everything yourself. You can use any existing Arduino -library to do the work for you! Now for this example we'll -use the `Adafruit BMP085 Library `__ -library to implement support for the BMP085 sensor. But you can find other libraries too on the -`PlatformIO library index `__ - -First we'll need to add the library to our project dependencies. To do so, put ``Adafruit BMP085 Library`` -in your global ``libraries``: - -.. code-block:: yaml - - esphome: - includes: - - my_custom_sensor.h - libraries: - - "Adafruit BMP085 Library" - -Next, include the library at the top of your custom sensor file you created previously: - -.. code-block:: cpp - - #include "esphome.h" - #include "Adafruit_BMP085.h" - - // ... - -Then update the sensor for BMP180 support: - -.. code-block:: cpp - - // ... - - class MyCustomSensor : public PollingComponent, public Sensor { - public: - Adafruit_BMP085 bmp; - - MyCustomSensor() : PollingComponent(15000) { } - - void setup() override { - bmp.begin(); - } - - void update() override { - int pressure = bmp.readPressure(); // library returns value in in Pa, which equals 1/100 hPa - publish_state(pressure / 100.0); // convert to hPa - } - }; - - // ... - -There's not too much going on there. First, we define the variable ``bmp`` of type ``Adafruit_BMP085`` -inside our class as a class member. This is the object the Adafruit library exposes and through which -we will communicate with the sensor. - -In our custom ``setup()`` function we're *initializing* the library (using ``.begin()``) and in -``update()`` we're reading the pressure and publishing it using ``publish_state``. - -For ESPHome we can use the previous YAML. So now if you upload the firmware, you'll see the sensor -reporting actual pressure values! Hooray 🎉! - -Step 4: Additional Overrides ----------------------------- - -There's a slight problem with our code: It does print the values fine, **but** if you look in Home Assistant -you'll see a) the value has no **unit** attached to it and b) the value will be rounded to the next integer. -This is because ESPHome doesn't know these infos, it's only passed a floating point value after all. - -We *could* fix that in our custom sensor class (by overriding the ``unit_of_measurement`` and ``accuracy_decimals`` -methods), but here we have the full power of ESPHome, so let's use that: - -.. code-block:: yaml - - # Example configuration entry - sensor: - - platform: custom - lambda: |- - auto my_sensor = new MyCustomSensor(); - App.register_component(my_sensor); - return {my_sensor}; - - sensors: - name: "My Custom Sensor" - unit_of_measurement: hPa - accuracy_decimals: 2 - - -Bonus: Sensors With Multiple Output Values ------------------------------------------- - -The ``Sensor`` class doesn't fit every use-case. Sometimes, (as with the BMP180), -a sensor can expose multiple values (temperature *and* pressure, for example). - -Doing so in ESPHome is a bit more difficult. Basically, we will have to change our sensor -model to have a **component** that reads out the values and then multiple **sensors** that represent -the individual sensor measurements. - -Let's look at what that could look like in code: - -.. code-block:: cpp - - class MyCustomSensor : public PollingComponent { - public: - Adafruit_BMP085 bmp; - Sensor *temperature_sensor = new Sensor(); - Sensor *pressure_sensor = new Sensor(); - - MyCustomSensor() : PollingComponent(15000) { } - - void setup() override { - bmp.begin(); - } - - void update() override { - // This is the actual sensor reading logic. - float temperature = bmp.readTemperature(); - temperature_sensor->publish_state(temperature); - - int pressure = bmp.readPressure(); - pressure_sensor->publish_state(pressure / 100.0); - } - }; - -The code here has changed a bit: - -- Because the values are no longer published by our custom class, ``MyCustomSensor`` no longer inherits - from ``Sensor``. -- The class has two new members: ``temperature_sensor`` and ``pressure_sensor``. These will be used to - publish the values. -- In our ``update()`` method we're now reading out the temperature *and* pressure. These values are then - published with the temperature and pressure sensor instances we declared before. - - -Our YAML configuration needs an update too: - -.. code-block:: yaml - - # Example configuration entry - sensor: - - platform: custom - lambda: |- - auto my_sensor = new MyCustomSensor(); - App.register_component(my_sensor); - return {my_sensor->temperature_sensor, my_sensor->pressure_sensor}; - - sensors: - - name: "My Custom Temperature Sensor" - unit_of_measurement: °C - accuracy_decimals: 1 - - name: "My Custom Pressure Sensor" - unit_of_measurement: hPa - accuracy_decimals: 2 - -In ``lambda`` the return statement has changed: Because we have *two* sensors now we must tell ESPHome -about both of them. We do this by returning them as an array of values in the curly braces. - -``sensors:`` has also changed a bit: Now that we have multiple sensors, each of them needs an entry here. - -Note that the number of arguments you put in the curly braces *must* match the number of sensors you define in the YAML -``sensors:`` block - *and* they must be in the same order. - -Configuration variables: -************************ - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - sensor(s). -- **sensors** (**Required**, list): A list of sensors to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Sensor `. - -Logging in Custom Components ----------------------------- - -It is possible to log inside of custom components too. You can use the provided ``ESP_LOGx`` -functions for this. - -.. code-block:: cpp - - ESP_LOGD("custom", "This is a custom debug message"); - // Levels: - // - ERROR: ESP_LOGE - // - WARNING: ESP_LOGW - // - INFO: ESP_LOGI - // - DEBUG: ESP_LOGD - // - VERBOSE: ESP_LOGV - // - VERY_VERBOSE: ESP_LOGVV - - ESP_LOGD("custom", "The value of sensor is: %f", this->state); - -See :ref:`display-printf` for learning about how to use formatting in log strings. - -See Also --------- - -- :ghedit:`Edit` diff --git a/components/sensor/misc/custom-empty.h b/components/sensor/misc/custom-empty.h deleted file mode 100644 index 0444c2984f..0000000000 --- a/components/sensor/misc/custom-empty.h +++ /dev/null @@ -1,15 +0,0 @@ -#include "esphome.h" - -using namespace esphome; - -class MyCustomSensor : public PollingComponent, public Sensor { - public: - MyCustomSensor() : PollingComponent(15000) {} - - void setup() override { - // This will be called by App.setup() - } - void update() override { - publish_state(42.0); - } -}; diff --git a/components/switch/custom.rst b/components/switch/custom.rst deleted file mode 100644 index 984bc5f7f6..0000000000 --- a/components/switch/custom.rst +++ /dev/null @@ -1,85 +0,0 @@ -Custom Switch -============= - -.. seo:: - :description: Instructions for setting up Custom C++ switches with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -This component can be used to create custom switches in ESPHome using the C++ (Arduino) API. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here. - -The example below is an example of a custom switch; this custom switch is essentially the -same as the gpio switch implementation. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomSwitch : public Component, public Switch { - public: - void setup() override { - // This will be called by App.setup() - pinMode(5, INPUT); - } - void write_state(bool state) override { - // This will be called every time the user requests a state change. - - digitalWrite(5, state); - - // Acknowledge new state by publishing it - publish_state(state); - } - }; - -(Store this file in your configuration directory, for example ``my_switch.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_switch.h - - switch: - - platform: custom - lambda: |- - auto my_custom_switch = new MyCustomSwitch(); - App.register_component(my_custom_switch); - return {my_custom_switch}; - - switches: - name: "My Custom Switches" - id: my_custom_switch - -Configuration variables: - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - switch(es). -- **switches** (**Required**, list): A list of switches to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Switch `. - -See :apiclass:`Switch ` - -See Also --------- - -- :ghedit:`Edit` diff --git a/components/text_sensor/custom.rst b/components/text_sensor/custom.rst deleted file mode 100644 index 0823d708f5..0000000000 --- a/components/text_sensor/custom.rst +++ /dev/null @@ -1,84 +0,0 @@ -Custom Text Sensor -================== - -.. seo:: - :description: Instructions for setting up Custom C++ text sensors with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -This component can be used to create custom text sensors in ESPHome using the C++ (Arduino) API. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here and text -sensors are very similar to sensors internally. - -The example below is an example of a custom text sensor which constantly publishes -the message "Hello World!". - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomTextSensor : public PollingComponent, public TextSensor { - public: - // constructor - MyCustomTextSensor() : PollingComponent(15000) {} - - void setup() override { - // This will be called by App.setup() - } - void update() override { - // This will be called every "update_interval" milliseconds. - // Publish state - publish_state("Hello World!"); - } - }; - -(Store this file in your configuration directory, for example ``my_text_sensor.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_text_sensor.h - - text_sensor: - - platform: custom - lambda: |- - auto my_custom_sensor = new MyCustomTextSensor(); - App.register_component(my_custom_sensor); - return {my_custom_sensor}; - - text_sensors: - name: "My Custom Text Sensor" - -Configuration variables: - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - text sensor(s). -- **text_sensors** (**Required**, list): A list of text sensors to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. - - - All options from :ref:`Text Sensor `. - -See Also --------- - -- :doc:`/components/text_sensor/index` -- :apiclass:`API Reference ` -- :ghedit:`Edit` diff --git a/cookbook/lambda_magic.rst b/cookbook/lambda_magic.rst index 7ba5ab2865..e8da7198f7 100644 --- a/cookbook/lambda_magic.rst +++ b/cookbook/lambda_magic.rst @@ -6,7 +6,7 @@ Lambda Magic :image: language-cpp.svg Here are a couple recipes for various interesting things you can do with :ref:`Lambdas ` in ESPHome. -These things don't need external or custom components, and show how powerful :ref:`Lambda ` usage can be. +These don't require external components and demonstrate how powerful :ref:`Lambdas ` can be. .. _lambda_magic_pages: @@ -99,135 +99,6 @@ You can send such UDP commands from ESPHome using a Lambda in a script. Tested on both `arduino` and `esp-idf` platforms. -.. _lambda_magic_uart_text_sensor: - -Custom UART Text Sensor ------------------------ - -Lots of devices communicate using the UART protocol. If you want to read -lines from uart to a Text Sensor you can do so using this code example. - -With this you can use automations or lambda to set switch or sensor states. - -.. code-block:: cpp - - #include "esphome.h" - - class UartReadLineSensor : public Component, public UARTDevice, public TextSensor { - public: - UartReadLineSensor(UARTComponent *parent) : UARTDevice(parent) {} - - void setup() override { - // nothing to do here - } - - int readline(int readch, char *buffer, int len) - { - static int pos = 0; - int rpos; - - if (readch > 0) { - switch (readch) { - case '\n': - case '\r': // Return on CR or newline - buffer[pos] = 0; // Just to be sure, set last character 0 - rpos = pos; - pos = 0; // Reset position index ready for next time - return rpos; - default: - if ((pos < len-1) && ( readch < 127 )) { // Filter on <127 to make sure it is a character - buffer[pos++] = readch; - buffer[pos] = 0; - } - else - { - buffer[pos] = 0; // Just to be sure, set last character 0 - rpos = pos; - pos = 0; // Reset position index ready for next time - return rpos; - } - } - } - // No end of line has been found, so return -1. - return -1; - } - - void loop() override { - const int max_line_length = 80; - static char buffer[max_line_length]; - while (available()) { - if(readline(read(), buffer, max_line_length) > 0) { - publish_state(buffer); - } - } - } - }; - -(Store this file in your configuration directory, for example ``uart_read_line_sensor.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - uart_read_line_sensor.h - - logger: - level: VERBOSE #makes uart stream available in esphome logstream - baud_rate: 0 #disable logging over uart - - uart: - id: uart_bus - tx_pin: GPIOXX - rx_pin: GPIOXX - baud_rate: 9600 - - text_sensor: - - platform: custom - lambda: |- - auto my_custom_sensor = new UartReadLineSensor(id(uart_bus)); - App.register_component(my_custom_sensor); - return {my_custom_sensor}; - text_sensors: - id: "uart_readline" - -For more details see :doc:`/custom/uart` and :doc:`/components/uart`. - -.. _lambda_magic_uart_switch: - -Custom UART Switch ------------------- - -Here is an example switch using the uart text sensor above to set switch state. - -Here we use interval to request status from the device. The response will be stored in uart text sensor. -Then the switch uses the text sensor state to publish its own state. - -.. code-block:: yaml - - switch: - - platform: template - name: "Switch" - lambda: |- - if (id(uart_readline).state == "*POW=ON#") { - return true; - } else if(id(uart_readline).state == "*POW=OFF#") { - return false; - } else { - return {}; - } - turn_on_action: - - uart.write: "\r*pow=on#\r" - turn_off_action: - - uart.write: "\r*pow=off#\r" - - interval: - - interval: 10s - then: - - uart.write: "\r*pow=?#\r" - .. _lambda_magic_rf_queues: Delaying Remote Transmissions diff --git a/custom/custom_component.rst b/custom/custom_component.rst deleted file mode 100644 index 012c0132ef..0000000000 --- a/custom/custom_component.rst +++ /dev/null @@ -1,198 +0,0 @@ -Generic Custom Component -======================== - -.. seo:: - :description: Instructions for setting up Custom C++ components with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - - -This component can be used to create generic custom components in ESPHome -using the C++ (Arduino) API. This component should be used in cases where -none of ESPHome's abstraction layers (for example the "sensor", "binary sensor", -"switch", etc concepts) work well for your component. - -Please first read :doc:`/components/sensor/custom` guide, the same principles apply here. - -The example below is an example of a custom component that can do anything you want really. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomComponent : public Component { - public: - void setup() override { - // This will be called once to set up the component - // think of it as the setup() call in Arduino - pinMode(5, INPUT); - pinMode(6, OUTPUT); - } - void loop() override { - // This will be called very often after setup time. - // think of it as the loop() call in Arduino - if (digitalRead(5)) { - digitalWrite(6, HIGH); - - // You can also log messages - ESP_LOGD("custom", "The GPIO pin 5 is HIGH!"); - } - } - }; - -(Store this file in your configuration directory, for example ``my_custom_component.h``) - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_custom_component.h - - custom_component: - - lambda: |- - auto my_custom = new MyCustomComponent(); - return {my_custom}; - components: - - id: my_custom_id - - -Configuration variables: - -- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the - binary sensor(s). -- **components** (*Optional*, list): A list of components to initialize. The length here - must equal the number of items in the ``return`` statement of the ``lambda``. This is useful - if you need to give an ``id`` to the component you created. - -See also :apiclass:`Component`. - -Native API Custom Component ---------------------------- - -If you want to communicate directly with Home Assistant via the :doc:`native API ` -you can use the :apiclass:`api::CustomAPIDevice` class to declare actions that can be performed from -Home Assistant, as well as performing actions in Home Assistant. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomComponent : public Component, public CustomAPIDevice { - public: - void setup() override { - // This will be called once to set up the component - // think of it as the setup() call in Arduino - pinMode(6, OUTPUT); - - // Declare a service "hello_world" - // - Service will be called "esphome._hello_world" in Home Assistant. - // - The service has no arguments - // - The function on_hello_world declared below will attached to the service. - register_service(&MyCustomComponent::on_hello_world, "hello_world"); - - // Declare a second service "start_washer_cycle" - // - Service will be called "esphome._start_washer_cycle" in Home Assistant. - // - The service has three arguments (type inferred from method definition): - // - cycle_duration: integer - // - silent: boolean - // - string_argument: string - // - The function start_washer_cycle declared below will attached to the service. - register_service(&MyCustomComponent::on_start_washer_cycle, "start_washer_cycle", - {"cycle_duration", "silent", "string_argument"}); - - // Subscribe to a Home Assistant state "sensor.temperature" - // - Each time the ESP connects or Home Assistant updates the state, the function - // on_state_changed will be called - // - The state is a string - if you want to use it as an int you must parse it manually - subscribe_homeassistant_state(&MyCustomComponent::on_state_changed, "sensor.temperature"); - } - void on_hello_world() { - ESP_LOGD("custom", "Hello World!"); - - if (is_connected()) { - // Example check to see if a client is connected - } - } - void on_start_washer_cycle(int cycle_duration, bool silent, std::string string_argument) { - ESP_LOGD("custom", "Starting washer cycle!"); - digitalWrite(8, HIGH); - // do something with arguments - - // Call a homeassistant service - call_homeassistant_service("homeassistant.service"); - } - void on_state_changed(std::string state) { - ESP_LOGD(TAG, "Temperature has changed to %s", state.c_str()); - } - }; - -See also :apiclass:`api::CustomAPIDevice`. - -MQTT Custom Component ---------------------- - -In many cases however components should communicate with other appliances using the network. -That's why there is :apiclass:`mqtt::CustomMQTTDevice`. It is a helper class to create -custom components that communicate using MQTT. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomComponent : public Component, public CustomMQTTDevice { - public: - void setup() override { - // This will be called once to set up the component - // think of it as the setup() call in Arduino - pinMode(6, OUTPUT); - - subscribe("the/topic", &MyCustomComponent::on_message); - - // also supports JSON messages - subscribe_json("the/json/topic", &MyCustomComponent::on_json_message); - } - void on_message(const std::string &payload) { - if (payload == "ON") { - digitalWrite(6, HIGH); - publish("the/other/topic", "Hello World!"); - } else { - digitalWrite(6, LOW); - publish("the/other/topic", 42); - } - } - void on_json_message(JsonObject root) { - if (!root.containsKey("key")) - return; - - int value = root["key"]; - // do something with Json Object - - // publish JSON using lambda syntax - publish_json("the/other/json/topic", [=](JsonObject root2) { - root2["key"] = "Hello World"; - }); - } - }; - -See also :apiclass:`mqtt::CustomMQTTDevice`. - -See Also --------- - -- :ghedit:`Edit` diff --git a/custom/i2c.rst b/custom/i2c.rst deleted file mode 100644 index cff3802110..0000000000 --- a/custom/i2c.rst +++ /dev/null @@ -1,111 +0,0 @@ -Custom I²C Device -================= - -.. seo:: - :description: Instructions for setting up Custom C++ I2C devices with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -Lots of devices communicate using the I²C protocol. If you want to integrate -a device into ESPHome that uses this protocol you can pretty much use almost -all Arduino-based code because the ``Wire`` library is also available in ESPHome. - -See the other custom component guides for how to register components and make -them publish values. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomComponent : public Component { - public: - void setup() override { - // Initialize the device here. Usually Wire.begin() will be called in here, - // though that call is unnecessary if you have an 'i2c:' entry in your config - - Wire.begin(); - } - void loop() override { - // Example: write the value 0x42 to register 0x78 of device with address 0x21 - Wire.beginTransmission(0x21); - Wire.write(0x78); - Wire.write(0x42); - Wire.endTransmission(); - } - }; - - -I²C Write ---------- -It may be useful to write to a register via I²C using a numerical input. For example, the following yaml code snippet captures a user-supplied numerical input in the range 1--255 from the dashboard: - -.. code-block:: yaml - - number: - - platform: template - name: "Input 1" - optimistic: true - min_value: 1 - max_value: 255 - initial_value: 20 - step: 1 - mode: box - id: input_1 - icon: "mdi:counter" - -We want to write this number to a ``REGISTER_ADDRESS`` on the slave device via I²C. The Arduino-based looping code shown above is modified following the guidance in :doc:`Custom Sensor Component `. - -.. code-block:: cpp - - #include "esphome.h" - - const uint16_t I2C_ADDRESS = 0x21; - const uint16_t REGISTER_ADDRESS = 0x78; - const uint16_t POLLING_PERIOD = 15000; //milliseconds - char temp = 20; //Initial value of the register - - class MyCustomComponent : public PollingComponent { - public: - MyCustomComponent() : PollingComponent(POLLING_PERIOD) {} - float get_setup_priority() const override { return esphome::setup_priority::BUS; } //Access I2C bus - - void setup() override { - //Add code here as needed - Wire.begin(); - } - - void update() override { - char register_value = id(input_1).state; //Read the number set on the dashboard - //Did the user change the input? - if(register_value != temp){ - Wire.beginTransmission(I2C_ADDRESS); - Wire.write(REGISTER_ADDRESS); - Wire.write(register_value); - Wire.endTransmission(); - temp = register_value; //Swap in the new value - } - } - }; - -The ``Component`` class has been replaced with ``PollingComponent`` and the free-running ``loop()`` is changed to the ``update()`` method with period set by ``POLLING_PERIOD``. The numerical value from the dashboard is accessed with its ``id`` tag and its state is set to the byte variable that we call ``register_value``. To prevent an I²C write on every iteration, the contents of the register are stored in ``temp`` and checked for a change. Configuring the hardware with ``get_setup_priority()`` is explained in :doc:`Step 1 `. - - - - -See Also --------- - -- :ghedit:`Edit` diff --git a/custom/index.rst b/custom/index.rst deleted file mode 100644 index 02337b727b..0000000000 --- a/custom/index.rst +++ /dev/null @@ -1,7 +0,0 @@ -Custom -====== - -.. toctree:: - :glob: - - * diff --git a/custom/spi.rst b/custom/spi.rst deleted file mode 100644 index a004dc76b9..0000000000 --- a/custom/spi.rst +++ /dev/null @@ -1,51 +0,0 @@ -Custom SPI Device -================= - -.. seo:: - :description: Instructions for setting up Custom C++ SPI devices with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -Lots of devices communicate using the SPI protocol. If you want to integrate -a device into ESPHome that uses this protocol you can pretty much use almost -all Arduino-based code because the ``SPI`` library is also available in ESPHome. - -See the other custom component guides for how to register components and make -them publish values. - -Please refer to the SPI library docs for more information. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomComponent : public Component { - public: - void setup() override { - SPI.pins(SCK_PIN, MISO_PIN, MOSI_PIN, CS_PIN); - SPI.begin(); - } - void loop() override { - SPI.beginTransaction(...) - - SPI.write(0x42); - } - }; - -See Also --------- - -- :ghedit:`Edit` diff --git a/custom/uart.rst b/custom/uart.rst deleted file mode 100644 index 6abfee7eb1..0000000000 --- a/custom/uart.rst +++ /dev/null @@ -1,74 +0,0 @@ -Custom UART Device -================== - -.. seo:: - :description: Instructions for setting up Custom C++ UART devices with ESPHome. - :image: language-cpp.svg - :keywords: C++, Custom - -.. warning:: - - :ref:`Custom Components are deprecated`, not recommended for new configurations and - will be removed from ESPHome in the ``2025.1.0`` release. Please look at creating a real ESPHome component and - "importing" it into your configuration with :doc:`/components/external_components`. - - You can find some basic documentation on creating your own components at :ref:`contributing_to_esphome`. - -.. warning:: - - While we try to keep the ESPHome YAML configuration options as stable as possible, the ESPHome API is less - stable. If something in the APIs needs to be changed in order for something else to work, we will do so. - -Lots of devices communicate using the UART protocol. If you want to integrate -a device into ESPHome that uses this protocol you can pretty much use almost -all Arduino-based code because ESPHome has a nice abstraction over the UART bus. - -See the other custom component guides for how to register components and make -them publish values. - -.. code-block:: cpp - - #include "esphome.h" - - class MyCustomComponent : public Component, public UARTDevice { - public: - MyCustomComponent(UARTComponent *parent) : UARTDevice(parent) {} - - void setup() override { - // nothing to do here - } - void loop() override { - // Use Arduino API to read data, for example - String line = readString(); - int i = parseInt(); - while (available()) { - char c = read(); - } - // etc - } - }; - -And in YAML: - -.. code-block:: yaml - - # Example configuration entry - esphome: - includes: - - my_custom_component.h - - uart: - id: uart_bus - tx_pin: GPIOXX - rx_pin: GPIOXX - baud_rate: 9600 - - custom_component: - - lambda: |- - auto my_custom = new MyCustomComponent(id(uart_bus)); - return {my_custom}; - -See Also --------- - -- :ghedit:`Edit` diff --git a/guides/contributing.rst b/guides/contributing.rst index 7b5c068ea4..313cae3d50 100644 --- a/guides/contributing.rst +++ b/guides/contributing.rst @@ -1042,14 +1042,14 @@ this can be a handy alternative to implementing a state machine. A Note About Custom Components ****************************** -*"I read that custom components are deprecated...so now what do I do???"* +*"I read that support for custom components was removed...so now what do I do???"* -ESPHome's "custom component" mechanism is a holdover from Home Assistant's feature by the same name. It existed before +ESPHome's "custom component" mechanism was a holdover from Home Assistant's feature by the same name. It existed before :doc:`/components/external_components` and offered a way to "hack in" support for devices which were not officially supported by ESPHome. -Why are Custom Components Deprecated? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Why were Custom Components Removed? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There are several reasons for this change. diff --git a/guides/diy.rst b/guides/diy.rst index c81637b0e3..7ebf2c35b3 100644 --- a/guides/diy.rst +++ b/guides/diy.rst @@ -6,7 +6,7 @@ DIY Examples :image: earth.svg This is a curated list of awesome creations with ESPHome containing various -custom components, blog posts, videos and sample configurations. It should serve as a means of +external components, blog posts, videos and sample configurations. It should serve as a means of finding inspiration for new projects and finding other ESPHome-enthusiasts on the web. This page purposefully has little moderation. Found something great or have something to share? @@ -16,7 +16,7 @@ unless it's truly exceptional, etc. .. warning:: - These configurations and custom components are *not officially maintained* by the + These configurations and external components are *not officially maintained* by the ESPHome team. If an API changes or there's a breaking change, it's up to the author to update the post. diff --git a/index.rst b/index.rst index 597150e48e..2e9933ac18 100644 --- a/index.rst +++ b/index.rst @@ -1169,28 +1169,6 @@ Miscellaneous Components Sun, components/sun, weather-sunny.svg, dark-invert Tuya MCU, components/tuya, tuya.png -Custom Components ------------------ - -**Note:** :ref:`Custom Components are deprecated` in favor of :doc:`components/external_components`! - -.. imgtable:: - - Generic Custom Component, custom/custom_component, language-cpp.svg, dark-invert - - Custom Binary Sensor, components/binary_sensor/custom, language-cpp.svg, dark-invert - Custom Climate, components/climate/custom, language-cpp.svg, dark-invert - Custom Cover, components/cover/custom, language-cpp.svg, dark-invert - Custom Light, components/light/custom, language-cpp.svg, dark-invert - Custom Output, components/output/custom, language-cpp.svg, dark-invert - Custom Sensor, components/sensor/custom, language-cpp.svg, dark-invert - Custom Switch, components/switch/custom, language-cpp.svg, dark-invert - Custom Text Sensor, components/text_sensor/custom, language-cpp.svg, dark-invert - - Custom I²C Component, custom/i2c, language-cpp.svg, dark-invert - Custom SPI Component, custom/spi, language-cpp.svg, dark-invert - Custom UART Component, custom/uart, language-cpp.svg, dark-invert - .. _cookbook: Cookbook @@ -1233,6 +1211,5 @@ documentation for others to copy. See :doc:`Contributing ` cookbook/index guides/index changelog/index - custom/index images/index projects/index diff --git a/schema_doc.py b/schema_doc.py index df83ae7748..d25a8fdf8c 100644 --- a/schema_doc.py +++ b/schema_doc.py @@ -159,9 +159,6 @@ def doctree_resolved(app, doctree, docname): "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": "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",