Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
operation_queue.cpp
Go to the documentation of this file.
1/// @file operation_queue.cpp
2/// @brief OperationQueue implementation.
3/// @ingroup hioc_hub
4
5#include "operation_queue.h"
6
7#include <algorithm>
8
9namespace esphome {
10namespace home_io_control {
11
15
16void OperationQueue::push_control_(PendingOperation op) {
17 queue_.erase(std::remove_if(queue_.begin(), queue_.end(),
18 [&op](const PendingOperation &existing) {
19 return existing.type == PendingOperationType::REQUEST_STATUS &&
20 existing.device_id == op.device_id;
21 }),
22 queue_.end());
23 auto it =
24 std::find_if(queue_.begin(), queue_.end(), [](const PendingOperation &o) { return is_background_op(o.type); });
25 queue_.insert(it, std::move(op));
26}
27
28bool OperationQueue::enqueue_set_position(const std::string &device_id, uint8_t position) {
29 for (auto &op : queue_) {
30 if (op.type == PendingOperationType::SET_TILT && op.device_id == device_id) {
31 // SET_TILT stores tilt in op.position (the only field available on standalone tilt ops).
32 uint8_t const pending_tilt = op.position;
34 op.position = position;
35 op.tilt = pending_tilt;
36 return true;
37 }
38 }
39 push_control_({PendingOperationType::SET_POSITION, device_id, position});
40 return false;
41}
42
43bool OperationQueue::enqueue_set_tilt(const std::string &device_id, uint8_t tilt_percent) {
44 for (auto &op : queue_) {
45 if (op.type == PendingOperationType::SET_POSITION && op.device_id == device_id) {
47 op.tilt = tilt_percent;
48 // op.position already holds the correct position from the original SET_POSITION enqueue.
49 return true;
50 }
51 }
52 push_control_({PendingOperationType::SET_TILT, device_id, tilt_percent});
53 return false;
54}
55
56void OperationQueue::enqueue_set_position_and_tilt(const std::string &device_id, uint8_t position,
57 uint8_t tilt_percent) {
58 push_control_({PendingOperationType::SET_POSITION_AND_TILT, device_id, position, tilt_percent});
59}
60
61void OperationQueue::enqueue_device_command(const std::string &device_id, CoverCommand cmd) {
64 op.device_id = device_id;
65 op.command = cmd;
66 push_control_(std::move(op));
67}
68
69void OperationQueue::enqueue_set_light_position(const std::string &device_id, uint8_t position) {
70 push_control_({PendingOperationType::SET_LIGHT_STATE, device_id, position});
71}
72
73void OperationQueue::enqueue_set_light_state(const std::string &device_id, bool on) {
75}
76
77void OperationQueue::enqueue_set_lock_state(const std::string &device_id, bool locked) {
78 push_control_({PendingOperationType::SET_LOCK_STATE, device_id,
80}
81
82void OperationQueue::enqueue_set_switch_state(const std::string &device_id, bool on) {
83 push_control_(
85}
86
87bool OperationQueue::enqueue_request_status(const std::string &device_id) {
88 for (const auto &op : queue_) {
89 if (op.type == PendingOperationType::REQUEST_STATUS && op.device_id == device_id)
90 return false;
91 }
92 queue_.push_back({PendingOperationType::REQUEST_STATUS, device_id, 0});
93 return true;
94}
95
96bool OperationQueue::enqueue_request_name(const std::string &device_id) {
97 for (const auto &op : queue_) {
98 if (op.type == PendingOperationType::REQUEST_NAME && op.device_id == device_id)
99 return false;
100 }
101 queue_.push_back({PendingOperationType::REQUEST_NAME, device_id, 0});
102 return true;
103}
104
106 for (const auto &op : queue_) {
108 return false;
109 }
110 queue_.erase(std::remove_if(queue_.begin(), queue_.end(),
111 [](const PendingOperation &op) {
112 return op.type == PendingOperationType::REQUEST_STATUS ||
113 op.type == PendingOperationType::REQUEST_NAME;
114 }),
115 queue_.end());
116 queue_.push_front({PendingOperationType::DISCOVER_AND_PAIR, {}, 0});
117 return true;
118}
119
120std::optional<PendingOperation> OperationQueue::pop() {
121 if (queue_.empty())
122 return std::nullopt;
123 PendingOperation op = std::move(queue_.front());
124 queue_.pop_front();
125 return op;
126}
127
128bool OperationQueue::empty() const { return queue_.empty(); }
129
130std::size_t OperationQueue::size() const { return queue_.size(); }
131
132const PendingOperation &OperationQueue::front() const { return queue_.front(); }
133
134const PendingOperation &OperationQueue::back() const { return queue_.back(); }
135
136const PendingOperation &OperationQueue::operator[](std::size_t index) const { return queue_[index]; }
137
138std::deque<PendingOperation>::const_iterator OperationQueue::begin() const { return queue_.cbegin(); }
139
140std::deque<PendingOperation>::const_iterator OperationQueue::end() const { return queue_.cend(); }
141
142} // namespace home_io_control
143} // namespace esphome
std::deque< PendingOperation >::const_iterator begin() const
const PendingOperation & front() const
void enqueue_set_lock_state(const std::string &device_id, bool locked)
void enqueue_set_position_and_tilt(const std::string &device_id, uint8_t position, uint8_t tilt_percent)
Enqueue SET_POSITION_AND_TILT directly (no coalescing needed).
std::optional< PendingOperation > pop()
void enqueue_device_command(const std::string &device_id, CoverCommand cmd)
bool enqueue_request_status(const std::string &device_id)
Enqueue REQUEST_STATUS, suppressing duplicates.
bool enqueue_request_name(const std::string &device_id)
Enqueue REQUEST_NAME, suppressing duplicates.
void enqueue_set_switch_state(const std::string &device_id, bool on)
bool enqueue_discover_and_pair()
Enqueue DISCOVER_AND_PAIR with elevated priority.
static bool is_background_op(PendingOperationType t)
True for background poll types (REQUEST_STATUS, REQUEST_NAME) that yield to control operations.
std::deque< PendingOperation >::const_iterator end() const
bool enqueue_set_position(const std::string &device_id, uint8_t position)
Enqueue SET_POSITION, or coalesce with a pending SET_TILT into SET_POSITION_AND_TILT.
const PendingOperation & back() const
void enqueue_set_light_state(const std::string &device_id, bool on)
void enqueue_set_light_position(const std::string &device_id, uint8_t position)
Enqueue SET_LIGHT_STATE with an arbitrary IO position (0-100), for dimmable lights.
const PendingOperation & operator[](std::size_t index) const
bool enqueue_set_tilt(const std::string &device_id, uint8_t tilt_percent)
Enqueue SET_TILT, or coalesce with a pending SET_POSITION into SET_POSITION_AND_TILT.
PendingOperationType
Discriminator for entries in the pending-operation deque.
@ SET_LOCK_STATE
set_lock_state call (locked/unlocked).
@ SET_TILT
set_device_tilt call (tilt percentage 0–100).
@ SET_POSITION_AND_TILT
Combined set_device_position_and_tilt call.
@ SET_LIGHT_STATE
set_light_state call (binary on/off).
@ SET_SWITCH_STATE
set_switch_state call (binary on/off).
@ REQUEST_NAME
request_device_name call (poll for stored device name).
@ DISCOVER_AND_PAIR
discover_and_pair call (starts 3-phase pairing flow).
@ REQUEST_STATUS
request_device_status call (poll for current position).
@ DEVICE_COMMAND
Named device command (STOP, FAVORITE, VENT).
@ SET_POSITION
set_device_position call (position 0–100 or special values).
CoverCommand
Named device commands for cover-type actuators.
static constexpr uint8_t BINARY_ENTITY_ON_POSITION
Position value written for binary ON commands (light on, switch on, lock unlock).
static constexpr uint8_t BINARY_ENTITY_OFF_POSITION
Position value written for binary OFF commands (light off, switch off, lock lock).
Pending-operation queue with per-type coalescing and deduplication.
A single queued operation to be dispatched from loop().
CoverCommand command
Named command for DEVICE_COMMAND operations.
std::string device_id
Target device ID (hex string, e.g., "123ABC").
uint8_t tilt
Tilt value for SET_POSITION_AND_TILT (0–100).
uint8_t position
Position/tilt value (0–100) or binary state (ON=0, OFF=100).
PendingOperationType type
Operation type (determines which handler to invoke).