Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
platform_cover.cpp
Go to the documentation of this file.
1/// @file platform_cover.cpp
2/// @brief ESPHome cover entity for IO-Homecontrol devices.
3
4#include "platform_cover.h"
5#include "hub_internal.h"
6#include "esphome/core/log.h"
7
8namespace esphome {
9namespace home_io_control {
10
11static const char *const TAG = "home_io_control.cover";
12
14 // Register this device with the controller so it's included in the device map
15 const bool initial_invert = this->invert_explicit_ ? this->invert_ : default_inverted_for_type(this->device_type_);
16 this->parent_->add_device(this->device_id_, device_type_, subtype_, initial_invert);
17 this->parent_->set_device_status_poll_interval(this->device_id_, this->status_poll_interval_ms_);
18
19 // Subscribe to status updates from the controller
20 this->parent_->register_device_callback(
21 [this](const std::string &id, const IoDevice &dev) { this->on_device_update_(id, dev); });
22
23 // Request initial status after a short delay (give radio time to start hopping)
24 this->set_timeout("init_status", detail::INITIAL_STATUS_REQUEST_DELAY_MS,
25 [this]() { this->parent_->queue_request_device_status(this->device_id_); });
26}
27
28cover::CoverTraits IOHomeCover::get_traits() {
29 auto traits = cover::CoverTraits();
30 traits.set_supports_position(true); // Slider in HA UI
31 traits.set_supports_stop(true); // Stop button in HA UI
32 traits.set_supports_tilt(this->supports_tilt());
33 traits.set_is_assumed_state(false); // We hopefully get real feedback from the device
34 return traits;
35}
36
38 if (this->parent_ == nullptr)
39 return false;
40 const auto *dev = this->parent_->get_device(this->device_id_);
41 return dev != nullptr && device_supports_tilt(dev->type);
42}
43
45 if (this->invert_explicit_)
46 return this->invert_;
47 if (this->parent_ == nullptr)
48 return false;
49 const auto *dev = this->parent_->get_device(this->device_id_);
50 return dev != nullptr && dev->inverted;
51}
52
53void IOHomeCover::control(const cover::CoverCall &call) {
54 if (call.get_stop()) {
55 this->parent_->queue_set_device_position(this->device_id_, POS_STOP);
56 return;
57 }
58
59 const auto &tilt_opt = call.get_tilt();
60 if (tilt_opt.has_value()) {
61 auto const tilt = static_cast<uint8_t>(*tilt_opt * 100.0F);
62 this->parent_->queue_set_device_tilt(this->device_id_, tilt);
63 return;
64 }
65
66 const auto &position_opt = call.get_position();
67 if (position_opt.has_value()) {
68 float const ha_pos = *position_opt; // HA: 1.0 = fully open, 0.0 = fully closed
69 const bool invert = this->effective_invert_();
70
71 // Convert HA position (0.0-1.0) to IO position (0-100)
72 // Standard: HA 1.0 (open) → IO 0 (open), HA 0.0 (closed) → IO 100 (closed)
73 // Inverted: HA 1.0 (open) → IO 100, HA 0.0 (closed) → IO 0
74 // (used for devices like horizontal awnings where the IO convention is reversed)
75 uint8_t io_pos;
76 if (invert) {
77 io_pos = (uint8_t) (ha_pos * 100.0F);
78 } else {
79 io_pos = (uint8_t) ((1.0F - ha_pos) * 100.0F);
80 }
81
82 this->parent_->queue_set_device_position(this->device_id_, io_pos);
83 }
84}
85
86void IOHomeCover::on_device_update_(const std::string &id, const IoDevice &dev) {
87 if (id != this->device_id_)
88 return;
89
90 const bool invert = this->effective_invert_();
91
92 if (dev.position != UNKNOWN_POSITION) {
93 // Convert IO position (0-100) back to HA position (0.0-1.0)
94 float ha_pos;
95 if (invert) {
96 ha_pos = dev.position / 100.0F;
97 } else {
98 ha_pos = 1.0F - (dev.position / 100.0F);
99 }
100
101 this->position = ha_pos;
102 }
103
104 if (this->supports_tilt() && dev.tilt != UNKNOWN_POSITION) {
105 this->tilt = dev.tilt / 100.0F;
106 }
107
108 // Determine movement direction for the HA UI animation
109 if (dev.is_stopped) {
110 this->current_operation = cover::COVER_OPERATION_IDLE;
111 } else if (dev.target != UNKNOWN_POSITION && dev.position != UNKNOWN_POSITION) {
112 // Figure out if we're opening or closing based on target vs current position
113 if (invert) {
114 this->current_operation =
115 (dev.target > dev.position) ? cover::COVER_OPERATION_OPENING : cover::COVER_OPERATION_CLOSING;
116 } else {
117 // Standard: lower IO position = more open, so target < current = opening
118 this->current_operation =
119 (dev.target < dev.position) ? cover::COVER_OPERATION_OPENING : cover::COVER_OPERATION_CLOSING;
120 }
121 }
122
123 this->publish_state();
124}
125
127 LOG_COVER("", "IO-Homecontrol Cover", this);
128 ESP_LOGCONFIG(TAG, " Device ID: %s", this->device_id_.c_str());
129 ESP_LOGCONFIG(TAG, " Invert Position Override: %s", this->invert_explicit_ ? YESNO(this->invert_) : "AUTO");
130 if (this->status_poll_interval_ms_ == 0) {
131 ESP_LOGCONFIG(TAG, " Status Poll Interval: default single settle poll");
132 } else {
133 ESP_LOGCONFIG(TAG, " Status Poll Interval: %u ms", this->status_poll_interval_ms_);
134 }
135 ESP_LOGCONFIG(TAG, " Supports Tilt: %s", YESNO(this->supports_tilt()));
136}
137
138} // namespace home_io_control
139} // namespace esphome
bool supports_tilt() const
Query whether this device supports tilt (slat angle) control.
void on_device_update_(const std::string &id, const IoDevice &dev)
Callback invoked when the underlying device state changes.
bool effective_invert_() const
Resolve the current inversion mode.
cover::CoverTraits get_traits() override
Return the traits object describing this cover's capabilities.
void setup() override
Initialize the cover entity (register device, subscribe to updates, schedule initial status poll).
void dump_config() override
Dump configuration to log.
void control(const cover::CoverCall &call) override
Handle cover commands from Home Assistant (open/close/stop/set_position).
Internal helpers shared by the hub implementation .cpp files.
constexpr uint32_t INITIAL_STATUS_REQUEST_DELAY_MS
Delay before the first post-boot status request from an entity.
static constexpr float UNKNOWN_POSITION
Sentinel value meaning "position is not known yet".
bool default_inverted_for_type(DeviceType type)
Determine whether a device type has inverted position mapping by default.
static constexpr uint8_t POS_STOP
Position values in the IO protocol.
bool device_supports_tilt(DeviceType type)
Does this device type support tilt (slat angle) control?
static const char *const TAG
Definition hub_core.cpp:34
ESPHome cover entity for IO‑Homecontrol devices.
Runtime state of a paired IO‑Homecontrol device.
float target
Target position the device is moving toward.
float tilt
Current tilt: 0=closed, 100=open, or UNKNOWN_POSITION.
float position
Current position: 0=open, 100=closed, or UNKNOWN_POSITION.
bool is_stopped
True if device is not moving.