Generic Custom Component ======================== .. seo:: :description: Instructions for setting up Custom C++ components with ESPHome. :image: language-cpp.svg :keywords: C++, Custom .. warning:: Custom components are deprecated, not recommended for new configurations and will be removed from ESPHome in a future 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 services that can be executed from Home Assistant, as well as starting services 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`