Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
platform_cover_controls.h
Go to the documentation of this file.
1#pragma once
2
3/// @file platform_cover_controls.h
4/// @brief Generated per-cover auxiliary entities: the command button (favorite / ventilation),
5/// the silent-operation toggle, the travel speed select, the rain binary sensor and the battery
6/// sensors.
7/// @ingroup hioc_platforms
8///
9/// All are device-bound companions (DeviceBoundCompanion), generated alongside a `cover:` entity
10/// by cover.py when the device type supports them, and both act on an already-registered device
11/// rather than owning one. They live together here because they are the cover platform's small
12/// auxiliary surface, not full entity platforms of their own.
13
14#include <optional>
15#include <string>
16
17#include "esphome/components/binary_sensor/binary_sensor.h"
18#include "esphome/components/button/button.h"
19#include "esphome/components/select/select.h"
20#include "esphome/components/switch/switch.h"
21#include "esphome/components/text_sensor/text_sensor.h"
22#include "esphome/core/component.h"
23#include "hub_core.h"
26#include "proto_device_model.h"
27
28namespace esphome {
29namespace home_io_control {
30
31/// @brief Button entity that sends one non-positional cover command on press.
32///
33/// One class covers every companion the cover platform generates from NAMED_POSITIONS: codegen
34/// calls set_command() with CoverCommand::FAVORITE for the favorite/"My"-position button
35/// (position-capable device types), CoverCommand::VENT for the ventilation button (window-type
36/// devices — WINDOW_OPENER, VENTILATION_POINT — where the vent command moves the actuator to a
37/// predefined partially-open position suitable for air exchange), CoverCommand::PARTIAL for the
38/// Partial Position button (garage openers) and CoverCommand::PEDESTRIAN for the Pedestrian
39/// Position button (gate openers). The press path, the parent/device guards and the log wording
40/// are identical for all of them; only the command byte differs.
41/// \todo Confirm on a real gate opener that PEDESTRIAN (0xD807) moves the motor to that position
42/// (experimental; the button is disabled by default). PARTIAL (0xD809) runs a garage opener's
43/// stored partial position (issue #163).
44/// @ingroup hioc_platforms
45class IOHomeCoverCommandButton : public button::Button, public Component, public DeviceBoundCompanion {
46 public:
47 /// @brief Set which cover command a press sends.
48 /// @param command CoverCommand::FAVORITE for the favorite-position companion,
49 /// CoverCommand::VENT for the ventilation companion, CoverCommand::PARTIAL for the
50 /// partial companion, CoverCommand::PEDESTRIAN for the experimental pedestrian companion.
51 void set_command(CoverCommand command) { this->command_ = command; }
52
53 /// @brief Initialize the generated button.
54 void setup() override {}
55
56 /// @brief Dump button configuration to the log.
57 void dump_config() override;
58
59 /// @brief Get setup priority so the parent hub is available first.
60 /// @return setup_priority::DATA.
61 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
62
63 protected:
64 /// @brief Handle a Home Assistant button press by queueing this button's cover command, which
65 /// is then sent to the device via the authenticated exchange like any other cover command.
66 void press_action() override;
67
69};
70
71/// @brief Switch entity that selects a cover's travel profile at runtime.
72/// @ingroup hioc_platforms
73///
74/// ON sends position commands with the manufacturer app's "silent operation" extended block, which
75/// makes the motor travel more slowly (TravelSpeed::SILENT); OFF sends the normal payload
76/// (TravelSpeed::FAST). Only generated when the cover declares `silent:` in YAML, so a config that
77/// never mentions it gains no entity — the YAML value is the boot state and this switch moves it
78/// afterwards. IOHomeCoverTravelSpeedSelect is the three-way form of the same setting.
79///
80/// Device-bound like IOHomeCoverCommandButton rather than hub-level like
81/// IOHomeAcceptForeignPairingSwitch: the setting is per actuator. Nothing on the wire reports a
82/// device's current profile, so this reflects only what this hub has been told to send — there is
83/// no readback to reconcile against, and none is faked.
84class IOHomeCoverSilentSwitch : public switch_::Switch, public Component, public DeviceBoundCompanion {
85 public:
86 /// @brief Publish the boot state declared in YAML so Home Assistant starts in sync.
87 void setup() override;
88
89 /// @brief Dump switch configuration to the log.
90 void dump_config() override;
91
92 /// @brief Get setup priority so the parent hub is available first.
93 /// @return setup_priority::DATA.
94 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
95
96 protected:
97 /// @brief Apply the requested travel profile to the bound device.
98 /// @param state True for silent (slower) operation.
99 void write_state(bool state) override;
100};
101
102/// @brief Select entity that sets a cover's travel speed at runtime: `default`, `silent` or `fast`.
103/// @ingroup hioc_platforms
104///
105/// `default` sends the 6-byte execute frame a wall pad sends, which carries no speed profile and
106/// leaves the speed to the motor; `silent` and `fast` send the 8-byte frame with profile 0x05 or
107/// 0x06 (TravelSpeed). Only generated when the cover declares `travel_speed:` in YAML, which is its
108/// boot state; this select moves it afterwards. Like IOHomeCoverSilentSwitch it reflects only what
109/// this hub has been told to send: nothing on the wire reports a device's speed.
110class IOHomeCoverTravelSpeedSelect : public select::Select, public Component, public DeviceBoundCompanion {
111 public:
112 /// @brief Publish the boot state declared in YAML so Home Assistant starts in sync.
113 void setup() override;
114
115 /// @brief Dump select configuration to the log.
116 void dump_config() override;
117
118 /// @brief Get setup priority so the parent hub is available first.
119 /// @return setup_priority::DATA.
120 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
121
122 protected:
123 /// @brief Apply the selected travel speed to the bound device.
124 /// @param value "default", "silent" or "fast" (travel_speed_name()).
125 void control(const std::string &value) override;
126};
127
128/// @brief Binary sensor that reports whether the window currently limits its own opening for rain.
129/// @ingroup hioc_platforms
130///
131/// ON when the device's minimum limitation read at least the rain threshold, OFF when it read
132/// below it. Only generated when the cover declares `rain_sensor_poll_interval:`, which is also what
133/// schedules the poll that feeds it. It has no state until the first answered poll, and loses it
134/// again after several unanswered polls: "off" always means a device said so. Independent of the
135/// Active Issue sensor, which reports what the last move or a clamped command implied.
136class IOHomeRainBinarySensor : public binary_sensor::BinarySensor, public Component, public DeviceBoundCompanion {
137 public:
138 /// @brief Subscribe to the device's updates and publish what is already known.
139 void setup() override;
140
141 /// @brief Dump sensor configuration to the log.
142 void dump_config() override;
143
144 /// @brief Get setup priority so the parent hub is available first.
145 /// @return setup_priority::DATA.
146 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
147
148 protected:
149 /// @brief Publish a rain state: true for RAIN, false for DRY, no state for UNKNOWN.
151};
152
153/// @brief Sensor publishing the raw sun value a device answers its sun level poll with.
154/// @ingroup hioc_platforms
155///
156/// Only generated when the cover declares `sun_level_poll_interval:`, which also schedules the poll
157/// that feeds it (a subscription to EVENT_LOCAL_SENSOR, ADR 0064). Publishes the number as the device
158/// sends it, with no unit: 0 at night, rising with sun on the panel. No state until the first
159/// answered poll, and again after several unanswered polls.
160/// \todo Unit and scale unknown; confirmed on one Somfy RS100 Solar io only (issue #156).
162 public:
163 /// @brief Subscribe to the device's updates and publish what is already known.
164 void setup() override;
165
166 /// @brief Dump sensor configuration to the log.
167 void dump_config() override;
168
169 protected:
170 std::optional<uint16_t> published_; ///< Last value handed to publish_state(); avoids re-publishing on every update.
171 bool published_once_{false}; ///< True once anything (a value or "unknown") was published.
172};
173
174/// @brief Sensor (`device_class: battery`, %) publishing the level a device answers its battery level
175/// poll with.
176/// @ingroup hioc_platforms
177///
178/// Only generated when the cover declares `battery_level_poll_interval:`, which also schedules the
179/// poll that feeds it (a subscription to EVENT_BATTERY_LEVEL_CHANGE, ADR 0064). Independent of the
180/// `battery: true` entities, which read the coarse level from status replies at no radio cost.
181/// \todo Percent rests on one captured value (100); confirmed on one Somfy RS100 Solar io only.
183 public:
184 /// @brief Subscribe to the device's updates and publish what is already known.
185 void setup() override;
186
187 /// @brief Dump sensor configuration to the log.
188 void dump_config() override;
189
190 protected:
191 std::optional<uint16_t> published_; ///< Last value handed to publish_state(); avoids re-publishing on every update.
192 bool published_once_{false}; ///< True once anything (a value or "unknown") was published.
193};
194
195/// @brief Binary sensor (`device_class: battery`) that is ON while the device reports a low battery.
196/// @ingroup hioc_platforms
197///
198/// Home Assistant's own low-battery convention, so generic battery tooling (low-battery
199/// notification blueprints, battery views) picks it up without per-entity setup. Generated with
200/// IOHomeBatteryTextSensor when the cover declares `battery: true`. It reads IoDevice::battery,
201/// which only status replies update: the boot poll, the settle polls after a move, and the
202/// device's own status updates. No state while the device reports no battery; the first status
203/// that shows none logs one INFO line, so a mains device with the key set explains itself.
204class IOHomeBatteryLowBinarySensor : public binary_sensor::BinarySensor, public Component, public DeviceBoundCompanion {
205 public:
206 /// @brief Subscribe to the device's updates and publish what is already known.
207 void setup() override;
208
209 /// @brief Dump sensor configuration to the log.
210 void dump_config() override;
211
212 /// @brief Get setup priority so the parent hub is available first.
213 /// @return setup_priority::DATA.
214 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
215
216 protected:
217 /// @brief Publish from a device record: ON for LOW_CHARGE, OFF for NORMAL/FULL, no state otherwise.
218 void publish_battery_(const IoDevice &dev);
219
220 bool logged_not_reported_{false}; ///< The "reports no battery" INFO line was written once already.
221};
222
223/// @brief Diagnostic text sensor naming the device's coarse battery level: "full", "normal" or "low".
224/// @ingroup hioc_platforms
225///
226/// Disabled by default: IOHomeBatteryLowBinarySensor is the entity automations should use. This
227/// one shows all three levels, which is useful while it is still open whether a device ever reports
228/// anything but "full". Publishes nothing while the device reports no battery.
229class IOHomeBatteryTextSensor : public text_sensor::TextSensor, public Component, public DeviceBoundCompanion {
230 public:
231 /// @brief Subscribe to the device's updates and publish what is already known.
232 void setup() override;
233
234 /// @brief Dump sensor configuration to the log.
235 void dump_config() override;
236
237 /// @brief Get setup priority so the parent hub is available first.
238 /// @return setup_priority::DATA.
239 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
240};
241
242} // namespace home_io_control
243} // namespace esphome
Mixin holding the parent + device-id binding shared by per-device entities that are not full entity p...
Sensor (device_class: battery, %) publishing the level a device answers its battery level poll with.
void setup() override
Subscribe to the device's updates and publish what is already known.
std::optional< uint16_t > published_
Last value handed to publish_state(); avoids re-publishing on every update.
bool published_once_
True once anything (a value or "unknown") was published.
void dump_config() override
Dump sensor configuration to the log.
Binary sensor (device_class: battery) that is ON while the device reports a low battery.
void setup() override
Subscribe to the device's updates and publish what is already known.
void dump_config() override
Dump sensor configuration to the log.
void publish_battery_(const IoDevice &dev)
Publish from a device record: ON for LOW_CHARGE, OFF for NORMAL/FULL, no state otherwise.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
bool logged_not_reported_
The "reports no battery" INFO line was written once already.
Diagnostic text sensor naming the device's coarse battery level: "full", "normal" or "low".
void setup() override
Subscribe to the device's updates and publish what is already known.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void dump_config() override
Dump sensor configuration to the log.
Shared base for the numeric per-device diagnostic companions.
Button entity that sends one non-positional cover command on press.
void setup() override
Initialize the generated button.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void set_command(CoverCommand command)
Set which cover command a press sends.
void press_action() override
Handle a Home Assistant button press by queueing this button's cover command, which is then sent to t...
void dump_config() override
Dump button configuration to the log.
Switch entity that selects a cover's travel profile at runtime.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void write_state(bool state) override
Apply the requested travel profile to the bound device.
void setup() override
Publish the boot state declared in YAML so Home Assistant starts in sync.
void dump_config() override
Dump switch configuration to the log.
Select entity that sets a cover's travel speed at runtime: default, silent or fast.
void dump_config() override
Dump select configuration to the log.
void control(const std::string &value) override
Apply the selected travel speed to the bound device.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void setup() override
Publish the boot state declared in YAML so Home Assistant starts in sync.
Binary sensor that reports whether the window currently limits its own opening for rain.
void dump_config() override
Dump sensor configuration to the log.
void publish_rain_state_(RainSensorState state)
Publish a rain state: true for RAIN, false for DRY, no state for UNKNOWN.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void setup() override
Subscribe to the device's updates and publish what is already known.
Sensor publishing the raw sun value a device answers its sun level poll with.
void dump_config() override
Dump sensor configuration to the log.
std::optional< uint16_t > published_
Last value handed to publish_state(); avoids re-publishing on every update.
void setup() override
Subscribe to the device's updates and publish what is already known.
bool published_once_
True once anything (a value or "unknown") was published.
IO-Homecontrol ESPHome component — protocol controller.
RainSensorState
What the hub's latest minimum-limitation read says about a rain-protection limit.
CoverCommand
Named device commands for cover-type actuators.
@ FAVORITE
Move to stored favorite/"My" position.
The auto-generated per-device diagnostic companion sensors.
Shared device-binding mixins for IO-Homecontrol entity platforms.
IO-Homecontrol device-type model, capabilities and runtime device state.
Runtime state of a paired IO‑Homecontrol device.