Skip to content

Commit 4f506a1

Browse files
kbx81jesserockz
andauthored
Add automations doc and favicon (#38)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
1 parent 25310bb commit 4f506a1

File tree

3 files changed

+166
-22
lines changed

3 files changed

+166
-22
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Implementing Automations
2+
3+
We have an example, minimal component which implements an Action, a Condition and a Trigger
4+
[here](https://github.com/esphome/starter-components/tree/main/components/empty_automation).
5+
6+
Let's take a closer look at this example.
7+
8+
## Python
9+
10+
In addition to the usual requisite imports, we have:
11+
12+
```python
13+
from esphome import automation
14+
```
15+
16+
This allows us to use some functions we'll need for validation and code generation later on.
17+
18+
```python
19+
empty_automation_ns = cg.esphome_ns.namespace("empty_automation")
20+
EmptyAutomation = empty_automation_ns.class_("EmptyAutomation", cg.Component)
21+
EmptyAutomationSetStateAction = empty_automation_ns.class_(
22+
"EmptyAutomationSetStateAction", automation.Action
23+
)
24+
EmptyAutomationCondition = empty_automation_ns.class_(
25+
"EmptyAutomationCondition", automation.Condition
26+
)
27+
StateTrigger = empty_automation_ns.class_(
28+
"StateTrigger", automation.Trigger.template(bool)
29+
)
30+
31+
```
32+
33+
This is some boilerplate code which allows ESPHome code generation to understand the namespace and class names that the
34+
component will use:
35+
36+
- The namespace and class for the component which will implement the automations
37+
- A class to be used to implement each automation:
38+
- Action
39+
- Condition
40+
- Trigger
41+
42+
```python
43+
CONFIG_SCHEMA = ...
44+
```
45+
46+
This defines the configuration schema for the component as discussed [here](index.md#configuration-validation).
47+
In particular, note that the schema includes:
48+
```python
49+
cv.Optional(CONF_ON_STATE): automation.validate_automation(...)
50+
```
51+
Of note:
52+
53+
- This allows the user to define an automation which will be triggered any time the component's "state" changes. In
54+
this case, the automation is called "on_state".
55+
- `cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger)` identifies the list of actions the component should
56+
"trigger" as appropriate.
57+
58+
In addition to `CONFIG_SCHEMA`, we define two additional schemas:
59+
60+
- `EMPTY_AUTOMATION_ACTION_SCHEMA`: Will be used to validate the action (`empty_automation.set_state`) when the user
61+
calls it.
62+
- `EMPTY_AUTOMATION_CONDITION_SCHEMA`: Will be used to validate the conditions when invoked by the user:
63+
either `empty_automation.component_off` or `empty_automation.component_on`.
64+
65+
After defining the various schemas we need for our component and its automations, we must register them so that they
66+
can be understood by the parser and codegen.
67+
68+
```python
69+
@automation.register_action(
70+
"empty_automation.set_state",
71+
EmptyAutomationSetStateAction,
72+
EMPTY_AUTOMATION_ACTION_SCHEMA,
73+
)
74+
# ...
75+
@automation.register_condition(
76+
"empty_automation.component_off",
77+
EmptyAutomationCondition,
78+
EMPTY_AUTOMATION_CONDITION_SCHEMA,
79+
)
80+
```
81+
82+
...registers the action and the condition. Note that each contains the name of the automation, the class that defines
83+
what the automation will do, and finally the schema used for validation.
84+
85+
In addition, note that each automation has a `to_code` function used for code generation:
86+
87+
```python
88+
async def empty_automation_set_state_to_code(...):
89+
# ...
90+
async def empty_automation_component_on_to_code(...):
91+
```
92+
93+
Finally, we have the `to_code` function for the component itself, just as discussed [here](index.md#code-generation).
94+
95+
## C++
96+
97+
The C++ class for this example component is quite simple.
98+
99+
```cpp
100+
class EmptyAutomation : public Component { ... };
101+
```
102+
103+
As mentioned [here](/contributing/code/#c), all components/platforms must inherit from either `Component` or
104+
`PollingComponent`; our example here is no different.
105+
106+
The component also also implements two additional methods:
107+
108+
- The `void set_state(bool state)` method simply allows setting the state of the component.
109+
- The `void add_on_state_callback(std::function<void(bool)> &&callback)` method allows adding the actions which will be
110+
triggered when the state of the component changes.
111+
112+
In addition to the component's class, additional classes which implement the various automations are defined in
113+
`automation.h`:
114+
115+
- `EmptyAutomationSetStateAction`
116+
- `EmptyAutomationCondition`
117+
- `StateTrigger`
118+
119+
```cpp
120+
template<typename... Ts> class EmptyAutomationSetStateAction : public Action<Ts...> {
121+
public:
122+
explicit EmptyAutomationSetStateAction(EmptyAutomation *ea) : ea_(ea) {}
123+
TEMPLATABLE_VALUE(bool, state)
124+
125+
void play(Ts... x) override {
126+
auto val = this->state_.value(x...);
127+
this->ea_->set_state(val);
128+
}
129+
130+
protected:
131+
EmptyAutomation *ea_;
132+
};
133+
134+
template<typename... Ts> class EmptyAutomationCondition : public Condition<Ts...> {
135+
public:
136+
EmptyAutomationCondition(EmptyAutomation *parent, bool state) : parent_(parent), state_(state) {}
137+
bool check(Ts... x) override { return this->parent_->state == this->state_; }
138+
139+
protected:
140+
EmptyAutomation *parent_;
141+
bool state_;
142+
};
143+
```
144+
145+
Actions and Conditions are implemented as template classes which are instantiated with pointers to their "parent" (the
146+
instance of the component on which they will act).
147+
148+
In this particular component:
149+
150+
- The action accepts a templatable value--the state--which the component will be set to when the action is called.
151+
- The condition accepts an additional parameter which determines whether it will test for the "off" or "on" state,
152+
allowing it to be reused for both conditions (`component_off` and `component_on`).
153+
154+
```cpp
155+
class StateTrigger : public Trigger<bool> {
156+
public:
157+
explicit StateTrigger(EmptyAutomation *parent) {
158+
parent->add_on_state_callback([this](bool state) { this->trigger(state); });
159+
}
160+
};
161+
```
162+
163+
Finally, `StateTrigger` is a simple class which does little more than call the trigger when it's instantiated.

docs/images/favicon.ico

48.1 KB
Binary file not shown.

mkdocs.yml

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edit_uri: edit/main/docs/
99
theme:
1010
name: material
1111
custom_dir: overrides
12+
favicon: images/favicon.ico
1213
features:
1314
- navigation.instant
1415
- navigation.path
@@ -24,6 +25,7 @@ theme:
2425
- content.code.annotate
2526
- content.tooltips
2627
- toc.follow
28+
logo: images/logo.svg
2729

2830
palette:
2931
# Palette toggle for light mode
@@ -78,28 +80,7 @@ nav:
7880
- I2C: architecture/components/i2c.md
7981
- SPI: architecture/components/spi.md
8082
- Serial (UART): architecture/components/uart.md
81-
- Alarm control panel: architecture/components/alarm_control_panel.md
82-
- Binary sensor: architecture/components/binary_sensor.md
83-
- Button: architecture/components/button.md
84-
- Climate: architecture/components/climate.md
85-
- Cover: architecture/components/cover.md
86-
- Display: architecture/components/display.md
87-
- Event: architecture/components/event.md
88-
- Fan: architecture/components/fan.md
89-
- Light: architecture/components/light.md
90-
- Lock: architecture/components/lock.md
91-
- Media player: architecture/components/media_player.md
92-
- Number: architecture/components/number.md
93-
- Output: architecture/components/output.md
94-
- Select: architecture/components/select.md
95-
- Sensor: architecture/components/sensor.md
96-
- Speaker: architecture/components/speaker.md
97-
- Switch: architecture/components/switch.md
98-
- Text: architecture/components/text.md
99-
- Text sensor: architecture/components/text_sensor.md
100-
- Time: architecture/components/time.md
101-
- Touchscreen: architecture/components/touchscreen.md
102-
- Valve: architecture/components/valve.md
83+
- Automations: architecture/components/automations.md
10384
- API:
10485
- Overview: architecture/api/index.md
10586
- Protocol Details: architecture/api/protocol_details.md

0 commit comments

Comments
 (0)