Add Tuya select (#3469)

This commit is contained in:
Maxim Ocheretianko 2022-05-15 22:49:40 +03:00 committed by GitHub
parent 0665acd190
commit f62d5d3b9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 140 additions and 0 deletions

View file

@ -222,6 +222,7 @@ esphome/components/tsl2591/* @wjcarpenter
esphome/components/tuya/binary_sensor/* @jesserockz esphome/components/tuya/binary_sensor/* @jesserockz
esphome/components/tuya/climate/* @jesserockz esphome/components/tuya/climate/* @jesserockz
esphome/components/tuya/number/* @frankiboy1 esphome/components/tuya/number/* @frankiboy1
esphome/components/tuya/select/* @bearpawmaxim
esphome/components/tuya/sensor/* @jesserockz esphome/components/tuya/sensor/* @jesserockz
esphome/components/tuya/switch/* @jesserockz esphome/components/tuya/switch/* @jesserockz
esphome/components/tuya/text_sensor/* @dentra esphome/components/tuya/text_sensor/* @dentra

View file

@ -0,0 +1,47 @@
from esphome.components import select
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_OPTIONS, CONF_OPTIMISTIC, CONF_ENUM_DATAPOINT
from .. import tuya_ns, CONF_TUYA_ID, Tuya
DEPENDENCIES = ["tuya"]
CODEOWNERS = ["@bearpawmaxim"]
TuyaSelect = tuya_ns.class_("TuyaSelect", select.Select, cg.Component)
def ensure_option_map(value):
cv.check_not_templatable(value)
option = cv.All(cv.int_range(0, 2**8 - 1))
mapping = cv.All(cv.string_strict)
options_map_schema = cv.Schema({option: mapping})
value = options_map_schema(value)
all_values = list(value.keys())
unique_values = set(value.keys())
if len(all_values) != len(unique_values):
raise cv.Invalid("Mapping values must be unique.")
return value
CONFIG_SCHEMA = select.SELECT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(TuyaSelect),
cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
cv.Required(CONF_ENUM_DATAPOINT): cv.uint8_t,
cv.Required(CONF_OPTIONS): ensure_option_map,
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
options_map = config[CONF_OPTIONS]
var = await select.new_select(config, options=list(options_map.values()))
await cg.register_component(var, config)
cg.add(var.set_select_mappings(list(options_map.keys())))
parent = await cg.get_variable(config[CONF_TUYA_ID])
cg.add(var.set_tuya_parent(parent))
cg.add(var.set_select_id(config[CONF_ENUM_DATAPOINT]))
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))

View file

@ -0,0 +1,52 @@
#include "esphome/core/log.h"
#include "tuya_select.h"
namespace esphome {
namespace tuya {
static const char *const TAG = "tuya.select";
void TuyaSelect::setup() {
this->parent_->register_listener(this->select_id_, [this](const TuyaDatapoint &datapoint) {
uint8_t enum_value = datapoint.value_enum;
ESP_LOGV(TAG, "MCU reported select %u value %u", this->select_id_, enum_value);
auto options = this->traits.get_options();
auto mappings = this->mappings_;
auto it = std::find(mappings.cbegin(), mappings.cend(), enum_value);
if (it == mappings.end()) {
ESP_LOGW(TAG, "Invalid value %u", enum_value);
return;
}
size_t mapping_idx = std::distance(mappings.cbegin(), it);
auto value = this->at(mapping_idx);
this->publish_state(value.value());
});
}
void TuyaSelect::control(const std::string &value) {
if (this->optimistic_)
this->publish_state(value);
auto idx = this->index_of(value);
if (idx.has_value()) {
uint8_t mapping = this->mappings_.at(idx.value());
ESP_LOGV(TAG, "Setting %u datapoint value to %u:%s", this->select_id_, mapping, value.c_str());
this->parent_->set_enum_datapoint_value(this->select_id_, mapping);
return;
}
ESP_LOGW(TAG, "Invalid value %s", value.c_str());
}
void TuyaSelect::dump_config() {
LOG_SELECT("", "Tuya Select", this);
ESP_LOGCONFIG(TAG, " Select has datapoint ID %u", this->select_id_);
ESP_LOGCONFIG(TAG, " Options are:");
auto options = this->traits.get_options();
for (auto i = 0; i < this->mappings_.size(); i++) {
ESP_LOGCONFIG(TAG, " %i: %s", this->mappings_.at(i), options.at(i).c_str());
}
}
} // namespace tuya
} // namespace esphome

View file

@ -0,0 +1,30 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/tuya/tuya.h"
#include "esphome/components/select/select.h"
namespace esphome {
namespace tuya {
class TuyaSelect : public select::Select, public Component {
public:
void setup() override;
void dump_config() override;
void set_tuya_parent(Tuya *parent) { this->parent_ = parent; }
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
void set_select_id(uint8_t select_id) { this->select_id_ = select_id; }
void set_select_mappings(std::vector<uint8_t> mappings) { this->mappings_ = std::move(mappings); }
protected:
void control(const std::string &value) override;
Tuya *parent_;
bool optimistic_ = false;
uint8_t select_id_;
std::vector<uint8_t> mappings_;
};
} // namespace tuya
} // namespace esphome

View file

@ -198,6 +198,7 @@ CONF_ENABLE_TIME = "enable_time"
CONF_ENERGY = "energy" CONF_ENERGY = "energy"
CONF_ENTITY_CATEGORY = "entity_category" CONF_ENTITY_CATEGORY = "entity_category"
CONF_ENTITY_ID = "entity_id" CONF_ENTITY_ID = "entity_id"
CONF_ENUM_DATAPOINT = "enum_datapoint"
CONF_ESP8266_DISABLE_SSL_SUPPORT = "esp8266_disable_ssl_support" CONF_ESP8266_DISABLE_SSL_SUPPORT = "esp8266_disable_ssl_support"
CONF_ESPHOME = "esphome" CONF_ESPHOME = "esphome"
CONF_ETHERNET = "ethernet" CONF_ETHERNET = "ethernet"

View file

@ -61,6 +61,15 @@ tuya:
number: 14 number: 14
inverted: true inverted: true
select:
- platform: tuya
id: tuya_select
enum_datapoint: 42
options:
0: Internal
1: Floor
2: Both
pipsolar: pipsolar:
id: inverter0 id: inverter0