Add `invert_position_report` to `tuya.cover`

Some Tuya cover MCUs for blinds persistently report a % open value for
the cover position, placing them at odds with ESPHome and HA controls.

This patch adds `invert_position_report` which simply flips the sense
of the relative position when used by the `tuya.cover` component so it
can be matched to whatever the device does.

This has been tested with a chip-swapped Zemismart `ZM25TQ (TY-W)`
successfully and gets the controls working consistently when used as
`device_class: blind` cover.
This commit is contained in:
Will Rouesnel 2023-12-26 21:22:19 +11:00
parent 93ac765425
commit d26d47d8ee
No known key found for this signature in database
GPG Key ID: 72DC65802A1091C5
3 changed files with 13 additions and 3 deletions

View File

@ -16,6 +16,7 @@ CONF_DIRECTION_DATAPOINT = "direction_datapoint"
CONF_POSITION_DATAPOINT = "position_datapoint"
CONF_POSITION_REPORT_DATAPOINT = "position_report_datapoint"
CONF_INVERT_POSITION = "invert_position"
CONF_INVERT_POSITION_REPORT = "invert_position_report"
TuyaCover = tuya_ns.class_("TuyaCover", cover.Cover, cg.Component)
@ -47,6 +48,7 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_MIN_VALUE, default=0): cv.int_,
cv.Optional(CONF_MAX_VALUE, default=100): cv.int_,
cv.Optional(CONF_INVERT_POSITION, default=False): cv.boolean,
cv.Optional(CONF_INVERT_POSITION_REPORT, default=False): cv.boolean,
cv.Optional(CONF_RESTORE_MODE, default="RESTORE"): cv.enum(
RESTORE_MODES, upper=True
),
@ -71,6 +73,7 @@ async def to_code(config):
cg.add(var.set_min_value(config[CONF_MIN_VALUE]))
cg.add(var.set_max_value(config[CONF_MAX_VALUE]))
cg.add(var.set_invert_position(config[CONF_INVERT_POSITION]))
cg.add(var.set_invert_position_report(config[CONF_INVERT_POSITION_REPORT]))
cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
paren = await cg.get_variable(config[CONF_TUYA_ID])
cg.add(var.set_tuya_parent(paren))

View File

@ -51,7 +51,7 @@ void TuyaCover::setup() {
return;
}
auto pos = float(datapoint.value_uint - this->min_value_) / this->value_range_;
this->position = 1.0f - pos;
this->position = this->invert_position_report_ ? pos : 1.0f - pos;
this->publish_state();
});
}
@ -62,7 +62,7 @@ void TuyaCover::control(const cover::CoverCall &call) {
this->parent_->force_set_enum_datapoint_value(*this->control_id_, COMMAND_STOP);
} else {
auto pos = this->position;
pos = 1.0f - pos;
pos = this->invert_position_report_ ? pos : 1.0f - pos;
auto position_int = static_cast<uint32_t>(pos * this->value_range_);
position_int = position_int + this->min_value_;
@ -78,7 +78,7 @@ void TuyaCover::control(const cover::CoverCall &call) {
this->parent_->force_set_enum_datapoint_value(*this->control_id_, COMMAND_CLOSE);
}
} else {
pos = 1.0f - pos;
pos = this->invert_position_report_ ? pos : 1.0f - pos;
auto position_int = static_cast<uint32_t>(pos * this->value_range_);
position_int = position_int + this->min_value_;
@ -112,6 +112,11 @@ void TuyaCover::dump_config() {
ESP_LOGCONFIG(TAG, " Configured as Inverted, but direction_datapoint isn't configured");
}
}
if (this->invert_position_report_) {
ESP_LOGCONFIG(TAG, " Position Reporting Inverted");
} else {
ESP_LOGCONFIG(TAG, " Position Reporting Normal");
}
if (this->control_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Control has datapoint ID %u", *this->control_id_);
}

View File

@ -25,6 +25,7 @@ class TuyaCover : public cover::Cover, public Component {
void set_min_value(uint32_t min_value) { min_value_ = min_value; }
void set_max_value(uint32_t max_value) { max_value_ = max_value; }
void set_invert_position(bool invert_position) { invert_position_ = invert_position; }
void set_invert_position_report(bool invert_position_report) { invert_position_report_ = invert_position_report; }
void set_restore_mode(TuyaCoverRestoreMode restore_mode) { restore_mode_ = restore_mode; }
protected:
@ -42,6 +43,7 @@ class TuyaCover : public cover::Cover, public Component {
uint32_t max_value_;
uint32_t value_range_;
bool invert_position_;
bool invert_position_report_;
};
} // namespace tuya