#include "select_call.h" #include "select.h" #include "esphome/core/log.h" namespace esphome { namespace select { static const char *const TAG = "select"; SelectCall &SelectCall::set_option(const std::string &option) { return with_operation(SELECT_OP_SET).with_option(option); } SelectCall &SelectCall::set_index(size_t index) { return with_operation(SELECT_OP_SET_INDEX).with_index(index); } SelectCall &SelectCall::select_next(bool cycle) { return with_operation(SELECT_OP_NEXT).with_cycle(cycle); } SelectCall &SelectCall::select_previous(bool cycle) { return with_operation(SELECT_OP_PREVIOUS).with_cycle(cycle); } SelectCall &SelectCall::select_first() { return with_operation(SELECT_OP_FIRST); } SelectCall &SelectCall::select_last() { return with_operation(SELECT_OP_LAST); } SelectCall &SelectCall::with_operation(SelectOperation operation) { this->operation_ = operation; return *this; } SelectCall &SelectCall::with_cycle(bool cycle) { this->cycle_ = cycle; return *this; } SelectCall &SelectCall::with_option(const std::string &option) { this->option_ = option; return *this; } SelectCall &SelectCall::with_index(size_t index) { this->index_ = index; return *this; } void SelectCall::perform() { auto *parent = this->parent_; const auto *name = parent->get_name().c_str(); const auto &traits = parent->traits; auto options = traits.get_options(); if (this->operation_ == SELECT_OP_NONE) { ESP_LOGW(TAG, "'%s' - SelectCall performed without selecting an operation", name); return; } if (options.empty()) { ESP_LOGW(TAG, "'%s' - Cannot perform SelectCall, select has no options", name); return; } std::string target_value; if (this->operation_ == SELECT_OP_SET) { ESP_LOGD(TAG, "'%s' - Setting", name); if (!this->option_.has_value()) { ESP_LOGW(TAG, "'%s' - No option value set for SelectCall", name); return; } target_value = this->option_.value(); } else if (this->operation_ == SELECT_OP_SET_INDEX) { if (!this->index_.has_value()) { ESP_LOGW(TAG, "'%s' - No index value set for SelectCall", name); return; } if (this->index_.value() >= options.size()) { ESP_LOGW(TAG, "'%s' - Index value %zu out of bounds", name, this->index_.value()); return; } target_value = options[this->index_.value()]; } else if (this->operation_ == SELECT_OP_FIRST) { target_value = options.front(); } else if (this->operation_ == SELECT_OP_LAST) { target_value = options.back(); } else if (this->operation_ == SELECT_OP_NEXT || this->operation_ == SELECT_OP_PREVIOUS) { auto cycle = this->cycle_; ESP_LOGD(TAG, "'%s' - Selecting %s, with%s cycling", name, this->operation_ == SELECT_OP_NEXT ? "next" : "previous", cycle ? "" : "out"); if (!parent->has_state()) { target_value = this->operation_ == SELECT_OP_NEXT ? options.front() : options.back(); } else { auto index = parent->index_of(parent->state); if (index.has_value()) { auto size = options.size(); if (cycle) { auto use_index = (size + index.value() + (this->operation_ == SELECT_OP_NEXT ? +1 : -1)) % size; target_value = options[use_index]; } else { if (this->operation_ == SELECT_OP_PREVIOUS && index.value() > 0) { target_value = options[index.value() - 1]; } else if (this->operation_ == SELECT_OP_NEXT && index.value() < options.size() - 1) { target_value = options[index.value() + 1]; } else { return; } } } else { target_value = this->operation_ == SELECT_OP_NEXT ? options.front() : options.back(); } } } if (std::find(options.begin(), options.end(), target_value) == options.end()) { ESP_LOGW(TAG, "'%s' - Option %s is not a valid option", name, target_value.c_str()); return; } ESP_LOGD(TAG, "'%s' - Set selected option to: %s", name, target_value.c_str()); parent->control(target_value); } } // namespace select } // namespace esphome