2018-11-27 23:45:05 +01:00
|
|
|
Generic Custom Component
|
|
|
|
========================
|
|
|
|
|
2019-02-16 23:25:23 +01:00
|
|
|
This integration can be used to create generic custom components in ESPHome
|
2018-11-27 23:45:05 +01:00
|
|
|
using the C++ (Arduino) API. This integration should be used in cases where
|
2019-02-16 23:25:23 +01:00
|
|
|
none of ESPHome's abstraction layers (for example the "sensor", "binary sensor",
|
2018-11-27 23:45:05 +01:00
|
|
|
"switch", etc concepts) work well for your integration.
|
|
|
|
|
2019-02-07 13:54:45 +01:00
|
|
|
Please first read :doc:`/components/sensor/custom` guide, the same principles apply here.
|
2018-11-27 23:45:05 +01:00
|
|
|
|
|
|
|
The example below is an example of a custom component that can do anything you want really.
|
|
|
|
|
|
|
|
.. code-block:: cpp
|
|
|
|
|
2019-02-16 23:25:23 +01:00
|
|
|
#include "esphome.h"
|
2018-11-27 23:45:05 +01:00
|
|
|
|
|
|
|
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 {
|
2018-12-01 09:46:37 +01:00
|
|
|
// This will be called very often after setup time.
|
|
|
|
// think of it as the loop() call in Arduino
|
2018-11-27 23:45:05 +01:00
|
|
|
if (digitalRead(5)) {
|
|
|
|
digitalWrite(6, HIGH);
|
|
|
|
|
|
|
|
// You can also log messages
|
|
|
|
ESP_LOGD("custom", "The GPIO pin 5 is HIGH!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-11-02 20:49:48 +01:00
|
|
|
(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};
|
2022-11-09 19:56:08 +01:00
|
|
|
components:
|
|
|
|
- id: my_custom_id
|
|
|
|
|
2019-11-02 20:49:48 +01:00
|
|
|
|
|
|
|
Configuration variables:
|
|
|
|
|
|
|
|
- **lambda** (**Required**, :ref:`lambda <config-lambda>`): The lambda to run for instantiating the
|
|
|
|
binary sensor(s).
|
2021-02-20 22:02:46 +01:00
|
|
|
- **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.
|
2019-11-02 20:49:48 +01:00
|
|
|
|
|
|
|
See also :apiclass:`Component`.
|
|
|
|
|
|
|
|
Native API Custom Component
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
If you want to communicate directly with Home Assistant via the :doc:`native API </components/api>`
|
2023-09-17 21:20:13 +02:00
|
|
|
you can use the :apiclass:`api::CustomAPIDevice` class to declare services that can be executed from
|
2019-11-02 20:49:48 +01:00
|
|
|
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.<NODE_NAME>_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.<NODE_NAME>_start_washer_cycle" in Home Assistant.
|
|
|
|
// - The service has three arguments (type inferred from method definition):
|
|
|
|
// - cycle_duration: integer
|
|
|
|
// - silent: boolean
|
|
|
|
// - string_argument: string
|
2020-12-21 01:55:44 +01:00
|
|
|
// - The function start_washer_cycle declared below will attached to the service.
|
2019-11-02 20:49:48 +01:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-12-11 17:34:55 +01:00
|
|
|
See also :apiclass:`api::CustomAPIDevice`.
|
2019-11-02 20:49:48 +01:00
|
|
|
|
|
|
|
MQTT Custom Component
|
|
|
|
---------------------
|
|
|
|
|
2018-11-27 23:45:05 +01:00
|
|
|
In many cases however components should communicate with other appliances using the network.
|
2019-05-12 22:44:59 +02:00
|
|
|
That's why there is :apiclass:`mqtt::CustomMQTTDevice`. It is a helper class to create
|
2018-11-27 23:45:05 +01:00
|
|
|
custom components that communicate using MQTT.
|
|
|
|
|
|
|
|
.. code-block:: cpp
|
|
|
|
|
2019-02-16 23:25:23 +01:00
|
|
|
#include "esphome.h"
|
2018-11-27 23:45:05 +01:00
|
|
|
|
2019-05-12 22:44:59 +02:00
|
|
|
class MyCustomComponent : public Component, public CustomMQTTDevice {
|
2018-11-27 23:45:05 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2022-11-13 07:39:00 +01:00
|
|
|
void on_json_message(JsonObject root) {
|
2018-11-27 23:45:05 +01:00
|
|
|
if (!root.containsKey("key"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
int value = root["key"];
|
|
|
|
// do something with Json Object
|
|
|
|
|
|
|
|
// publish JSON using lambda syntax
|
2022-11-13 07:39:00 +01:00
|
|
|
publish_json("the/other/json/topic", [=](JsonObject root2) {
|
2018-11-27 23:45:05 +01:00
|
|
|
root2["key"] = "Hello World";
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-11-02 20:49:48 +01:00
|
|
|
See also :apiclass:`mqtt::CustomMQTTDevice`.
|
2018-11-27 23:45:05 +01:00
|
|
|
|
|
|
|
See Also
|
|
|
|
--------
|
|
|
|
|
2019-02-07 13:54:45 +01:00
|
|
|
- :ghedit:`Edit`
|