7#include "esphome/core/log.h"
12static const char *
const TAG =
"home_io_control.cover";
17constexpr float IO_POSITION_CLOSED = 100.0F;
18constexpr float IO_POSITION_OPEN = 0.0F;
29cover::CoverOperation operation_toward(
bool invert,
float from_io_position,
float to_io_position) {
30 if (from_io_position == UNKNOWN_POSITION || to_io_position == UNKNOWN_POSITION ||
31 from_io_position == to_io_position) {
32 return cover::COVER_OPERATION_IDLE;
34 const bool opening = invert ? (to_io_position > from_io_position) : (to_io_position < from_io_position);
35 return opening ? cover::COVER_OPERATION_OPENING : cover::COVER_OPERATION_CLOSING;
41cover::CoverOperation operation_toward_end(
bool invert,
float to_io_position) {
42 const float closed_position = invert ? IO_POSITION_OPEN : IO_POSITION_CLOSED;
43 const float open_position = invert ? IO_POSITION_CLOSED : IO_POSITION_OPEN;
44 if (to_io_position == closed_position)
45 return cover::COVER_OPERATION_CLOSING;
46 if (to_io_position == open_position)
47 return cover::COVER_OPERATION_OPENING;
48 return cover::COVER_OPERATION_IDLE;
65cover::CoverOperation operation_with_withheld_position(
bool invert,
float previous_io_position,
float target,
66 bool own_command, cover::CoverOperation shown) {
67 if (previous_io_position != target)
68 return operation_toward(invert, previous_io_position, target);
69 const cover::CoverOperation toward_end = operation_toward_end(invert, target);
70 return own_command || toward_end == shown ? toward_end : cover::COVER_OPERATION_IDLE;
93 auto traits = cover::CoverTraits();
99 traits.set_supports_position(levels);
100 traits.set_supports_stop(
true);
102 traits.set_is_assumed_state(!levels);
120 return dev !=
nullptr && dev->
inverted;
133 if (call.get_stop()) {
139 const auto &tilt_opt = call.get_tilt();
140 const auto &position_opt = call.get_position();
152 if (position_opt.has_value() && tilt_opt.has_value() && this->supports_tilt()) {
153 float const ha_pos = *position_opt;
163 if (tilt_opt.has_value()) {
173 if (position_opt.has_value()) {
174 float const ha_pos = *position_opt;
194 const cover::CoverOperation previous_operation = this->current_operation;
207 const float closed_position = invert ? IO_POSITION_OPEN : IO_POSITION_CLOSED;
208 this->position = dev.
position == closed_position ? cover::COVER_CLOSED : cover::COVER_OPEN;
209 }
else if (dev.
position != UNKNOWN_POSITION) {
218 this->position = ha_pos;
227 this->current_operation = cover::COVER_OPERATION_IDLE;
228 }
else if (eff_target != UNKNOWN_POSITION && dev.
position != UNKNOWN_POSITION && eff_target != dev.
position) {
230 this->current_operation = operation_toward(invert, dev.
position, eff_target);
231 }
else if (eff_target != UNKNOWN_POSITION && dev.
position == UNKNOWN_POSITION) {
238 this->current_operation = operation_with_withheld_position(
239 invert, previous_io_position, eff_target, dev.
optimistic.
target != UNKNOWN_POSITION, previous_operation);
240 }
else if (dev.
position != UNKNOWN_POSITION) {
249 if (dev.
position != UNKNOWN_POSITION) {
255 this->publish_state();
259 LOG_COVER(
"",
"IO-Homecontrol Cover",
this);
260 ESP_LOGCONFIG(
TAG,
" Device ID: %s", this->
device_id_.c_str());
void log_poll_interval_config_(const char *tag) const
Emit the shared two-branch poll-interval line for dump_config().
void register_device_binding_(Component *self, DeviceCapabilityClass entity_class, std::optional< bool > invert_override, std::function< void(const std::string &, const IoDevice &)> on_update, bool dimmable=false)
Perform the shared setup() registration ritual.
IOHomeControlComponent * parent_
DeviceFeatures device_features_(DeviceCapabilityClass entity_class) const
What this entity's device can do: the registered device's features, or, before it is registered,...
virtual bool apply_optimistic_stop(const std::string &device_id)
Predict that a device has stopped (e.g.
virtual void queue_set_device_tilt(const std::string &device_id, uint8_t tilt_percent)
Queue an async tilt update; returns immediately, executed in loop().
virtual IoDevice * get_device(const std::string &device_id)
Retrieve a device by ID; returns nullptr if not found.
virtual void set_device_rain_poll_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the periodic rain sensor poll (a read of its minimum limitation).
virtual void set_device_status_refresh_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the status refresh at rest: a status read whenever the device has not re...
virtual void queue_set_device_position_and_tilt(const std::string &device_id, uint8_t position, uint8_t tilt_percent)
Queue an async combined position+tilt update; returns immediately, executed in loop().
virtual bool queue_device_command(const std::string &device_id, CoverCommand cmd)
Queue an async named command (STOP, FAVORITE, VENT, PARTIAL, PEDESTRIAN, FORCE_OPEN); returns immedia...
virtual bool apply_optimistic_tilt(const std::string &device_id, float tilt_percent)
Set an optimistic slat angle ahead of a confirming status poll, and notify.
virtual void set_device_sun_poll_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the periodic sun level poll (a subscription to EVENT_LOCAL_SENSOR,...
virtual void queue_set_device_position(const std::string &device_id, uint8_t position)
Queue an async position update; returns immediately, executed in loop().
virtual bool apply_optimistic_target(const std::string &device_id, float target_io_position)
Set an optimistic target position ahead of a confirming poll/response, and notify.
virtual void set_device_battery_level_poll_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the periodic battery level poll (a subscription to EVENT_BATTERY_LEVEL_C...
uint32_t rain_sensor_poll_interval_ms_
0 = not opted in; no rain poll is scheduled.
cover::CoverOperation infer_operation_from_position_delta_(bool invert, float current_io_position) const
Infer HA movement direction from successive IO positions when the protocol target is unknown.
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.
uint32_t status_refresh_interval_ms_
0 = not opted in; no status refresh is scheduled.
bool supports_intermediate_positions() const
Query whether this device takes intermediate positions (a slider) or only open / close / stop.
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).
uint32_t battery_level_poll_interval_ms_
0 = not opted in; no battery level poll is scheduled.
uint32_t sun_level_poll_interval_ms_
0 = not opted in; no sun level poll is scheduled.
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).
Conversions and renderers shared by the hub and its Home Assistant entities.
uint8_t round_percent(float fraction)
Convert a 0.0-1.0 HA fraction (position, tilt, or brightness) to a 0-100 IO percent.
float whole_percent(float io_percent)
Round an IO percent (0-100) to a whole number, for publishing to HA.
static constexpr const char * TAG
float effective_target(const IoDevice &dev)
The main-position target a consumer should act on: the prediction when one stands,...
@ STOP
Stop movement immediately.
constexpr bool has_feature(DeviceFeatures set, DeviceFeatures bit)
True when every bit of bit is set in set.
bool effective_is_stopped(const IoDevice &dev)
Whether a consumer should treat the device as at rest, prediction first.
float effective_tilt(const IoDevice &dev)
The slat angle a consumer should act on, prediction first.
@ COVER
Position‑controlled cover (shutter/blind/awning).
static const char *const TAG
Runtime state of a paired IO‑Homecontrol device.
OptimisticState optimistic
Hub-side predictions; see OptimisticState. Never observation.
bool inverted
True if open/close positions are swapped (e.g., horizontal awning).
float position
Current position: 0=open, 100=closed, or UNKNOWN_POSITION.
float target
Predicted main-position target, or UNKNOWN_POSITION.