mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
Add support for Tuya ceiling fan controllers (#989)
* Add support for Tuya ceiling fan controllers
This commit is contained in:
parent
aff4f1e9e2
commit
66083c5e97
4 changed files with 167 additions and 3 deletions
39
esphome/components/tuya/fan/__init__.py
Normal file
39
esphome/components/tuya/fan/__init__.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
from esphome.components import fan
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.const import CONF_OUTPUT_ID
|
||||||
|
from .. import tuya_ns, CONF_TUYA_ID, Tuya
|
||||||
|
|
||||||
|
DEPENDENCIES = ['tuya']
|
||||||
|
|
||||||
|
CONF_SPEED_DATAPOINT = "speed_datapoint"
|
||||||
|
CONF_SWITCH_DATAPOINT = "switch_datapoint"
|
||||||
|
CONF_OSCILLATION_DATAPOINT = "oscillation_datapoint"
|
||||||
|
|
||||||
|
TuyaFan = tuya_ns.class_('TuyaFan', cg.Component)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(fan.FAN_SCHEMA.extend({
|
||||||
|
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(TuyaFan),
|
||||||
|
cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
|
||||||
|
cv.Optional(CONF_OSCILLATION_DATAPOINT): cv.uint8_t,
|
||||||
|
cv.Optional(CONF_SPEED_DATAPOINT): cv.uint8_t,
|
||||||
|
cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t,
|
||||||
|
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(
|
||||||
|
CONF_SPEED_DATAPOINT, CONF_SWITCH_DATAPOINT))
|
||||||
|
|
||||||
|
|
||||||
|
def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
||||||
|
yield cg.register_component(var, config)
|
||||||
|
|
||||||
|
paren = yield cg.get_variable(config[CONF_TUYA_ID])
|
||||||
|
fan_ = yield fan.create_fan_state(config)
|
||||||
|
cg.add(var.set_tuya_parent(paren))
|
||||||
|
cg.add(var.set_fan(fan_))
|
||||||
|
|
||||||
|
if CONF_SPEED_DATAPOINT in config:
|
||||||
|
cg.add(var.set_speed_id(config[CONF_SPEED_DATAPOINT]))
|
||||||
|
if CONF_SWITCH_DATAPOINT in config:
|
||||||
|
cg.add(var.set_switch_id(config[CONF_SWITCH_DATAPOINT]))
|
||||||
|
if CONF_OSCILLATION_DATAPOINT in config:
|
||||||
|
cg.add(var.set_oscillation_id(config[CONF_OSCILLATION_DATAPOINT]))
|
90
esphome/components/tuya/fan/tuya_fan.cpp
Normal file
90
esphome/components/tuya/fan/tuya_fan.cpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "tuya_fan.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tuya {
|
||||||
|
|
||||||
|
static const char *TAG = "tuya.fan";
|
||||||
|
|
||||||
|
void TuyaFan::setup() {
|
||||||
|
auto traits = fan::FanTraits(this->oscillation_id_.has_value(), this->speed_id_.has_value());
|
||||||
|
this->fan_->set_traits(traits);
|
||||||
|
|
||||||
|
if (this->speed_id_.has_value()) {
|
||||||
|
this->parent_->register_listener(*this->speed_id_, [this](TuyaDatapoint datapoint) {
|
||||||
|
auto call = this->fan_->make_call();
|
||||||
|
if (datapoint.value_enum == 0x0)
|
||||||
|
call.set_speed(fan::FAN_SPEED_LOW);
|
||||||
|
else if (datapoint.value_enum == 0x1)
|
||||||
|
call.set_speed(fan::FAN_SPEED_MEDIUM);
|
||||||
|
else if (datapoint.value_enum == 0x2)
|
||||||
|
call.set_speed(fan::FAN_SPEED_HIGH);
|
||||||
|
else
|
||||||
|
ESP_LOGCONFIG(TAG, "Speed has invalid value %d", datapoint.value_enum);
|
||||||
|
ESP_LOGD(TAG, "MCU reported speed of: %d", datapoint.value_enum);
|
||||||
|
call.perform();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this->switch_id_.has_value()) {
|
||||||
|
this->parent_->register_listener(*this->switch_id_, [this](TuyaDatapoint datapoint) {
|
||||||
|
auto call = this->fan_->make_call();
|
||||||
|
call.set_state(datapoint.value_bool);
|
||||||
|
call.perform();
|
||||||
|
ESP_LOGD(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this->oscillation_id_.has_value()) {
|
||||||
|
this->parent_->register_listener(*this->oscillation_id_, [this](TuyaDatapoint datapoint) {
|
||||||
|
auto call = this->fan_->make_call();
|
||||||
|
call.set_oscillating(datapoint.value_bool);
|
||||||
|
call.perform();
|
||||||
|
ESP_LOGD(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this->fan_->add_on_state_callback([this]() { this->write_state(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void TuyaFan::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Tuya Fan:");
|
||||||
|
if (this->speed_id_.has_value())
|
||||||
|
ESP_LOGCONFIG(TAG, " Speed has datapoint ID %u", *this->speed_id_);
|
||||||
|
if (this->switch_id_.has_value())
|
||||||
|
ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_);
|
||||||
|
if (this->oscillation_id_.has_value())
|
||||||
|
ESP_LOGCONFIG(TAG, " Oscillation has datapoint ID %u", *this->oscillation_id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TuyaFan::write_state() {
|
||||||
|
if (this->switch_id_.has_value()) {
|
||||||
|
TuyaDatapoint datapoint{};
|
||||||
|
datapoint.id = *this->switch_id_;
|
||||||
|
datapoint.type = TuyaDatapointType::BOOLEAN;
|
||||||
|
datapoint.value_bool = this->fan_->state;
|
||||||
|
this->parent_->set_datapoint_value(datapoint);
|
||||||
|
ESP_LOGD(TAG, "Setting switch: %s", ONOFF(this->fan_->state));
|
||||||
|
}
|
||||||
|
if (this->oscillation_id_.has_value()) {
|
||||||
|
TuyaDatapoint datapoint{};
|
||||||
|
datapoint.id = *this->oscillation_id_;
|
||||||
|
datapoint.type = TuyaDatapointType::BOOLEAN;
|
||||||
|
datapoint.value_bool = this->fan_->oscillating;
|
||||||
|
this->parent_->set_datapoint_value(datapoint);
|
||||||
|
ESP_LOGD(TAG, "Setting oscillating: %s", ONOFF(this->fan_->oscillating));
|
||||||
|
}
|
||||||
|
if (this->speed_id_.has_value()) {
|
||||||
|
TuyaDatapoint datapoint{};
|
||||||
|
datapoint.id = *this->speed_id_;
|
||||||
|
datapoint.type = TuyaDatapointType::ENUM;
|
||||||
|
if (this->fan_->speed == fan::FAN_SPEED_LOW)
|
||||||
|
datapoint.value_enum = 0;
|
||||||
|
if (this->fan_->speed == fan::FAN_SPEED_MEDIUM)
|
||||||
|
datapoint.value_enum = 1;
|
||||||
|
if (this->fan_->speed == fan::FAN_SPEED_HIGH)
|
||||||
|
datapoint.value_enum = 2;
|
||||||
|
ESP_LOGD(TAG, "Setting speed: %d", datapoint.value_enum);
|
||||||
|
this->parent_->set_datapoint_value(datapoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tuya
|
||||||
|
} // namespace esphome
|
34
esphome/components/tuya/fan/tuya_fan.h
Normal file
34
esphome/components/tuya/fan/tuya_fan.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/tuya/tuya.h"
|
||||||
|
#include "esphome/components/fan/fan_state.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tuya {
|
||||||
|
|
||||||
|
class TuyaFan : public Component {
|
||||||
|
public:
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
void set_speed_id(uint8_t speed_id) { this->speed_id_ = speed_id; }
|
||||||
|
void set_switch_id(uint8_t switch_id) { this->switch_id_ = switch_id; }
|
||||||
|
void set_oscillation_id(uint8_t oscillation_id) { this->oscillation_id_ = oscillation_id; }
|
||||||
|
void set_fan(fan::FanState *fan) { this->fan_ = fan; }
|
||||||
|
void set_tuya_parent(Tuya *parent) { this->parent_ = parent; }
|
||||||
|
void write_state();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void update_speed_(uint32_t value);
|
||||||
|
void update_switch_(uint32_t value);
|
||||||
|
void update_oscillation_(uint32_t value);
|
||||||
|
|
||||||
|
Tuya *parent_;
|
||||||
|
optional<uint8_t> speed_id_{};
|
||||||
|
optional<uint8_t> switch_id_{};
|
||||||
|
optional<uint8_t> oscillation_id_{};
|
||||||
|
fan::FanState *fan_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tuya
|
||||||
|
} // namespace esphome
|
|
@ -12,10 +12,10 @@ CONF_SWITCH_DATAPOINT = "switch_datapoint"
|
||||||
|
|
||||||
TuyaLight = tuya_ns.class_('TuyaLight', light.LightOutput, cg.Component)
|
TuyaLight = tuya_ns.class_('TuyaLight', light.LightOutput, cg.Component)
|
||||||
|
|
||||||
CONFIG_SCHEMA = light.BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend({
|
CONFIG_SCHEMA = cv.All(light.BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend({
|
||||||
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(TuyaLight),
|
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(TuyaLight),
|
||||||
cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
|
cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
|
||||||
cv.Required(CONF_DIMMER_DATAPOINT): cv.uint8_t,
|
cv.Optional(CONF_DIMMER_DATAPOINT): cv.uint8_t,
|
||||||
cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t,
|
cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t,
|
||||||
cv.Optional(CONF_MIN_VALUE): cv.int_,
|
cv.Optional(CONF_MIN_VALUE): cv.int_,
|
||||||
cv.Optional(CONF_MAX_VALUE): cv.int_,
|
cv.Optional(CONF_MAX_VALUE): cv.int_,
|
||||||
|
@ -24,7 +24,8 @@ CONFIG_SCHEMA = light.BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend({
|
||||||
# The Tuya MCU handles transitions and gamma correction on its own.
|
# The Tuya MCU handles transitions and gamma correction on its own.
|
||||||
cv.Optional(CONF_GAMMA_CORRECT, default=1.0): cv.positive_float,
|
cv.Optional(CONF_GAMMA_CORRECT, default=1.0): cv.positive_float,
|
||||||
cv.Optional(CONF_DEFAULT_TRANSITION_LENGTH, default='0s'): cv.positive_time_period_milliseconds,
|
cv.Optional(CONF_DEFAULT_TRANSITION_LENGTH, default='0s'): cv.positive_time_period_milliseconds,
|
||||||
}).extend(cv.COMPONENT_SCHEMA)
|
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_DIMMER_DATAPOINT,
|
||||||
|
CONF_SWITCH_DATAPOINT))
|
||||||
|
|
||||||
|
|
||||||
def to_code(config):
|
def to_code(config):
|
||||||
|
|
Loading…
Reference in a new issue