Break the Tuya set_datapoint_value method into separate methods per datapoint type (#2059)

Co-authored-by: Chris Nussbaum <chris.nussbaum@protolabs.com>
Co-authored-by: Trevor North <trevor@freedisc.co.uk>
This commit is contained in:
Chris Nussbaum 2021-08-10 14:44:31 -05:00 committed by GitHub
parent 1771e673d2
commit 6144ce1fe0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 42 deletions

View file

@ -54,14 +54,14 @@ void TuyaClimate::control(const climate::ClimateCall &call) {
if (call.get_mode().has_value()) { if (call.get_mode().has_value()) {
const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF; const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF;
ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state)); ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state));
this->parent_->set_datapoint_value(*this->switch_id_, switch_state); this->parent_->set_boolean_datapoint_value(*this->switch_id_, switch_state);
} }
if (call.get_target_temperature().has_value()) { if (call.get_target_temperature().has_value()) {
const float target_temperature = *call.get_target_temperature(); const float target_temperature = *call.get_target_temperature();
ESP_LOGV(TAG, "Setting target temperature: %.1f", target_temperature); ESP_LOGV(TAG, "Setting target temperature: %.1f", target_temperature);
this->parent_->set_datapoint_value(*this->target_temperature_id_, this->parent_->set_integer_datapoint_value(*this->target_temperature_id_,
(int) (target_temperature / this->target_temperature_multiplier_)); (int) (target_temperature / this->target_temperature_multiplier_));
} }
} }

View file

@ -67,20 +67,20 @@ void TuyaFan::dump_config() {
void TuyaFan::write_state() { void TuyaFan::write_state() {
if (this->switch_id_.has_value()) { if (this->switch_id_.has_value()) {
ESP_LOGV(TAG, "Setting switch: %s", ONOFF(this->fan_->state)); ESP_LOGV(TAG, "Setting switch: %s", ONOFF(this->fan_->state));
this->parent_->set_datapoint_value(*this->switch_id_, this->fan_->state); this->parent_->set_boolean_datapoint_value(*this->switch_id_, this->fan_->state);
} }
if (this->oscillation_id_.has_value()) { if (this->oscillation_id_.has_value()) {
ESP_LOGV(TAG, "Setting oscillating: %s", ONOFF(this->fan_->oscillating)); ESP_LOGV(TAG, "Setting oscillating: %s", ONOFF(this->fan_->oscillating));
this->parent_->set_datapoint_value(*this->oscillation_id_, this->fan_->oscillating); this->parent_->set_boolean_datapoint_value(*this->oscillation_id_, this->fan_->oscillating);
} }
if (this->direction_id_.has_value()) { if (this->direction_id_.has_value()) {
bool enable = this->fan_->direction == fan::FAN_DIRECTION_REVERSE; bool enable = this->fan_->direction == fan::FAN_DIRECTION_REVERSE;
ESP_LOGV(TAG, "Setting reverse direction: %s", ONOFF(enable)); ESP_LOGV(TAG, "Setting reverse direction: %s", ONOFF(enable));
this->parent_->set_datapoint_value(*this->direction_id_, enable); this->parent_->set_boolean_datapoint_value(*this->direction_id_, enable);
} }
if (this->speed_id_.has_value()) { if (this->speed_id_.has_value()) {
ESP_LOGV(TAG, "Setting speed: %d", this->fan_->speed); ESP_LOGV(TAG, "Setting speed: %d", this->fan_->speed);
this->parent_->set_datapoint_value(*this->speed_id_, this->fan_->speed - 1); this->parent_->set_integer_datapoint_value(*this->speed_id_, this->fan_->speed - 1);
} }
} }

View file

@ -31,7 +31,7 @@ void TuyaLight::setup() {
}); });
} }
if (min_value_datapoint_id_.has_value()) { if (min_value_datapoint_id_.has_value()) {
parent_->set_datapoint_value(*this->min_value_datapoint_id_, this->min_value_); parent_->set_integer_datapoint_value(*this->min_value_datapoint_id_, this->min_value_);
} }
} }
@ -66,9 +66,9 @@ void TuyaLight::write_state(light::LightState *state) {
if (brightness == 0.0f) { if (brightness == 0.0f) {
// turning off, first try via switch (if exists), then dimmer // turning off, first try via switch (if exists), then dimmer
if (switch_id_.has_value()) { if (switch_id_.has_value()) {
parent_->set_datapoint_value(*this->switch_id_, false); parent_->set_boolean_datapoint_value(*this->switch_id_, false);
} else if (dimmer_id_.has_value()) { } else if (dimmer_id_.has_value()) {
parent_->set_datapoint_value(*this->dimmer_id_, 0); parent_->set_integer_datapoint_value(*this->dimmer_id_, 0);
} }
return; return;
} }
@ -78,17 +78,17 @@ void TuyaLight::write_state(light::LightState *state) {
static_cast<uint32_t>(this->color_temperature_max_value_ * static_cast<uint32_t>(this->color_temperature_max_value_ *
(state->current_values.get_color_temperature() - this->cold_white_temperature_) / (state->current_values.get_color_temperature() - this->cold_white_temperature_) /
(this->warm_white_temperature_ - this->cold_white_temperature_)); (this->warm_white_temperature_ - this->cold_white_temperature_));
parent_->set_datapoint_value(*this->color_temperature_id_, color_temp_int); parent_->set_integer_datapoint_value(*this->color_temperature_id_, color_temp_int);
} }
auto brightness_int = static_cast<uint32_t>(brightness * this->max_value_); auto brightness_int = static_cast<uint32_t>(brightness * this->max_value_);
brightness_int = std::max(brightness_int, this->min_value_); brightness_int = std::max(brightness_int, this->min_value_);
if (this->dimmer_id_.has_value()) { if (this->dimmer_id_.has_value()) {
parent_->set_datapoint_value(*this->dimmer_id_, brightness_int); parent_->set_integer_datapoint_value(*this->dimmer_id_, brightness_int);
} }
if (this->switch_id_.has_value()) { if (this->switch_id_.has_value()) {
parent_->set_datapoint_value(*this->switch_id_, true); parent_->set_boolean_datapoint_value(*this->switch_id_, true);
} }
} }

View file

@ -15,7 +15,7 @@ void TuyaSwitch::setup() {
void TuyaSwitch::write_state(bool state) { void TuyaSwitch::write_state(bool state) {
ESP_LOGV(TAG, "Setting switch %u: %s", this->switch_id_, ONOFF(state)); ESP_LOGV(TAG, "Setting switch %u: %s", this->switch_id_, ONOFF(state));
this->parent_->set_datapoint_value(this->switch_id_, state); this->parent_->set_boolean_datapoint_value(this->switch_id_, state);
this->publish_state(state); this->publish_state(state);
} }

View file

@ -437,42 +437,38 @@ void Tuya::send_local_time_() {
} }
#endif #endif
void Tuya::set_datapoint_value(uint8_t datapoint_id, uint32_t value) { void Tuya::set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value) {
ESP_LOGD(TAG, "Setting datapoint %u to %u", datapoint_id, value); ESP_LOGD(TAG, "Setting datapoint %u to %s", datapoint_id, hexencode(value).c_str());
optional<TuyaDatapoint> datapoint = this->get_datapoint_(datapoint_id); optional<TuyaDatapoint> datapoint = this->get_datapoint_(datapoint_id);
if (!datapoint.has_value()) { if (!datapoint.has_value()) {
ESP_LOGE(TAG, "Attempt to set unknown datapoint %u", datapoint_id); ESP_LOGW(TAG, "Setting unknown datapoint %u", datapoint_id);
} else if (datapoint->type != TuyaDatapointType::RAW) {
ESP_LOGE(TAG, "Attempt to set datapoint %u with incorrect type", datapoint_id);
return; return;
} } else if (datapoint->value_raw == value) {
if (datapoint->value_uint == value) {
ESP_LOGV(TAG, "Not sending unchanged value"); ESP_LOGV(TAG, "Not sending unchanged value");
return; return;
} }
this->send_datapoint_command_(datapoint_id, TuyaDatapointType::RAW, value);
std::vector<uint8_t> data;
switch (datapoint->len) {
case 4:
data.push_back(value >> 24);
data.push_back(value >> 16);
case 2:
data.push_back(value >> 8);
case 1:
data.push_back(value >> 0);
break;
default:
ESP_LOGE(TAG, "Unexpected datapoint length %zu", datapoint->len);
return;
}
this->send_datapoint_command_(datapoint->id, datapoint->type, data);
} }
void Tuya::set_datapoint_value(uint8_t datapoint_id, const std::string &value) { void Tuya::set_boolean_datapoint_value(uint8_t datapoint_id, bool value) {
this->set_numeric_datapoint_value_(datapoint_id, TuyaDatapointType::BOOLEAN, value, 1);
}
void Tuya::set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value) {
this->set_numeric_datapoint_value_(datapoint_id, TuyaDatapointType::INTEGER, value, 4);
}
void Tuya::set_string_datapoint_value(uint8_t datapoint_id, const std::string &value) {
ESP_LOGD(TAG, "Setting datapoint %u to %s", datapoint_id, value.c_str()); ESP_LOGD(TAG, "Setting datapoint %u to %s", datapoint_id, value.c_str());
optional<TuyaDatapoint> datapoint = this->get_datapoint_(datapoint_id); optional<TuyaDatapoint> datapoint = this->get_datapoint_(datapoint_id);
if (!datapoint.has_value()) { if (!datapoint.has_value()) {
ESP_LOGE(TAG, "Attempt to set unknown datapoint %u", datapoint_id); ESP_LOGW(TAG, "Setting unknown datapoint %u", datapoint_id);
} } else if (datapoint->type != TuyaDatapointType::STRING) {
if (datapoint->value_string == value) { ESP_LOGE(TAG, "Attempt to set datapoint %u with incorrect type", datapoint_id);
return;
} else if (datapoint->value_string == value) {
ESP_LOGV(TAG, "Not sending unchanged value"); ESP_LOGV(TAG, "Not sending unchanged value");
return; return;
} }
@ -483,6 +479,14 @@ void Tuya::set_datapoint_value(uint8_t datapoint_id, const std::string &value) {
this->send_datapoint_command_(datapoint->id, datapoint->type, data); this->send_datapoint_command_(datapoint->id, datapoint->type, data);
} }
void Tuya::set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value) {
this->set_numeric_datapoint_value_(datapoint_id, TuyaDatapointType::ENUM, value, 1);
}
void Tuya::set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length) {
this->set_numeric_datapoint_value_(datapoint_id, TuyaDatapointType::BITMASK, value, length);
}
optional<TuyaDatapoint> Tuya::get_datapoint_(uint8_t datapoint_id) { optional<TuyaDatapoint> Tuya::get_datapoint_(uint8_t datapoint_id) {
for (auto &datapoint : this->datapoints_) for (auto &datapoint : this->datapoints_)
if (datapoint.id == datapoint_id) if (datapoint.id == datapoint_id)
@ -490,6 +494,37 @@ optional<TuyaDatapoint> Tuya::get_datapoint_(uint8_t datapoint_id) {
return {}; return {};
} }
void Tuya::set_numeric_datapoint_value_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, const uint32_t value,
uint8_t length) {
ESP_LOGD(TAG, "Setting datapoint %u to %u", datapoint_id, value);
optional<TuyaDatapoint> datapoint = this->get_datapoint_(datapoint_id);
if (!datapoint.has_value()) {
ESP_LOGW(TAG, "Setting unknown datapoint %u", datapoint_id);
} else if (datapoint->type != datapoint_type) {
ESP_LOGE(TAG, "Attempt to set datapoint %u with incorrect type", datapoint_id);
return;
} else if (datapoint->value_uint == value) {
ESP_LOGV(TAG, "Not sending unchanged value");
return;
}
std::vector<uint8_t> data;
switch (length) {
case 4:
data.push_back(value >> 24);
data.push_back(value >> 16);
case 2:
data.push_back(value >> 8);
case 1:
data.push_back(value >> 0);
break;
default:
ESP_LOGE(TAG, "Unexpected datapoint length %u", length);
return;
}
this->send_datapoint_command_(datapoint_id, datapoint_type, data);
}
void Tuya::send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data) { void Tuya::send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data) {
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer;
buffer.push_back(datapoint_id); buffer.push_back(datapoint_id);

View file

@ -17,7 +17,7 @@ enum class TuyaDatapointType : uint8_t {
INTEGER = 0x02, // 4 byte INTEGER = 0x02, // 4 byte
STRING = 0x03, // variable length STRING = 0x03, // variable length
ENUM = 0x04, // 1 byte ENUM = 0x04, // 1 byte
BITMASK = 0x05, // 2 bytes BITMASK = 0x05, // 1/2/4 bytes
}; };
struct TuyaDatapoint { struct TuyaDatapoint {
@ -75,8 +75,12 @@ class Tuya : public Component, public uart::UARTDevice {
void loop() override; void loop() override;
void dump_config() override; void dump_config() override;
void register_listener(uint8_t datapoint_id, const std::function<void(TuyaDatapoint)> &func); void register_listener(uint8_t datapoint_id, const std::function<void(TuyaDatapoint)> &func);
void set_datapoint_value(uint8_t datapoint_id, uint32_t value); void set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value);
void set_datapoint_value(uint8_t datapoint_id, const std::string &value); void set_boolean_datapoint_value(uint8_t datapoint_id, bool value);
void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value);
void set_string_datapoint_value(uint8_t datapoint_id, const std::string &value);
void set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value);
void set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length);
#ifdef USE_TIME #ifdef USE_TIME
void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; } void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; }
#endif #endif
@ -95,6 +99,8 @@ class Tuya : public Component, public uart::UARTDevice {
void process_command_queue_(); void process_command_queue_();
void send_command_(const TuyaCommand &command); void send_command_(const TuyaCommand &command);
void send_empty_command_(TuyaCommandType command); void send_empty_command_(TuyaCommandType command);
void set_numeric_datapoint_value_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, uint32_t value,
uint8_t length);
void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data); void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data);
void send_wifi_status_(); void send_wifi_status_();