mirror of
https://github.com/nuttytree/ESPHome-Devices.git
synced 2024-08-30 18:12:19 +00:00
Rewrite the Tuya dimmer as fan component (#11)
This commit is contained in:
parent
85a65d6307
commit
c7ef8cb8d5
10
README.md
10
README.md
@ -16,6 +16,9 @@ This is a copy of the standard Tuya component with a couple of fixes/tweaks that
|
||||
### Tuya Light Plus
|
||||
This an enhanced version of the standard [Tuya](https://esphome.io/components/light/tuya.html) light component that adds a bunch of extra features. I use this component with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) but it will likely work with other Tuya dimmers. More details on features and how to use this component are available [here](./components/tuya_light_plus/README.md).
|
||||
|
||||
### Tuya Dimmer as Fan
|
||||
This a modified version of the Tuya fan component I use with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) (but it will likely work with other Tuya dimmers) to control bathroom fans. The major change from the standard Tuya fan component (other than removing options for speed, oscillation, and direction) is adding a function to always change the dimmer back to the maximum "brightness" effectively making this only an on/off device. Details on how to use this component are available [here](./components/tuya_dimmer_as_fan/README.md).
|
||||
|
||||
|
||||
## Misc Devices
|
||||
### [Basement Bathroom Sensor](./devices/basement_bathroom_sensor.yaml)
|
||||
@ -82,10 +85,7 @@ All of my dimmers are using my custom [Tuya Light Plus](./components/tuya_light_
|
||||
* [Master Bathroom Lights](./devices/master_bath_lights_1.yaml)/[Master Bathroom Lights 2](./devices/master_bath_lights_2.yaml)
|
||||
* [Office Light](./devices/office_light.yaml)
|
||||
|
||||
## Dimmer Switches as On/Off Switches
|
||||
## Dimmer Switches as On/Off Fan Switches
|
||||
### [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1)
|
||||
I tried to find an on/off switch that looked/felt like the Feit dimmers but didn't find anything so I decided to use the Feit dimmers as switches.
|
||||
|
||||
#### Fans
|
||||
I created a custom [tuya_dimmer_as_binary_fan_output.h](./custom/tuya_dimmer_as_binary_fan_output.h) component that prevents the dimmer from being dimmed (always changes it right back to 100%) and can report the change in on/off status back to a fan component.
|
||||
I tried to find an on/off switch that looked/felt like the Feit dimmers to use for controlling bathroom fans but didn't find anything so I decided to use the Feit dimmers. I don't want the fans "dimmable" so I created a custom [Tuya Dimmer as Fan](./components/tuya_dimmer_as_fan/README.md) component that changes the "brightness" back to the maximum value if changed at the switch.
|
||||
* [Master Bath Fan](./devices/master_bath_fan.yaml)
|
39
components/tuya_dimmer_as_fan/README.md
Normal file
39
components/tuya_dimmer_as_fan/README.md
Normal file
@ -0,0 +1,39 @@
|
||||
# Tuya Light Plus Component
|
||||
## Overview
|
||||
This a modified version of the Tuya fan component I use with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) (but it will likely work with other Tuya dimmers) to control bathroom fans. The major change from the standard Tuya fan component (other than removing options for speed, oscillation, and direction) is adding a function to always change the dimmer back to the maximum "brightness" effectively making this only an on/off device.
|
||||
|
||||
|
||||
## Setup
|
||||
Using the [External Components](https://esphome.io/components/external_components.html) feature in ESPHome you can add this component to your devices directly from my GitHub repo. Note currently this component requires pulling in my custom version of the Tuya component as well to prevent communication issues between the ESP8266 and the Tuya MCU.
|
||||
```yaml
|
||||
external_components:
|
||||
- source: github://nuttytree/esphome
|
||||
components: [ tuya, tuya_dimmer_as_fan ]
|
||||
```
|
||||
|
||||
Like the standard Tuya fan component you need to have the [UART](https://esphome.io/components/uart.html) and [Tuya](https://esphome.io/components/tuya.html) components.
|
||||
```yaml
|
||||
uart:
|
||||
rx_pin: GPIO3
|
||||
tx_pin: GPIO1
|
||||
baud_rate: 9600
|
||||
|
||||
tuya:
|
||||
```
|
||||
|
||||
Add and configure the Tuya Dimmer as Fan component
|
||||
```yaml
|
||||
fan:
|
||||
- platform: tuya_dimmer_as_fan
|
||||
name: my_fan
|
||||
switch_datapoint: 1
|
||||
dimmer_datapoint: 2
|
||||
dimmer_max_value: 1000
|
||||
```
|
||||
|
||||
## Configuration Variables
|
||||
* id (Optional, ID): Manually specify the ID used for code generation.
|
||||
* name (Required, string): The name of the light.
|
||||
* switch_datapoint (Required, int): The datapoint id number of the power switch.
|
||||
* dimmer_datapoint (Required, int): The datapoint id number of the dimmer value.
|
||||
* dimmer_max_value (Optional, int, default 255): The highest dimmer value allowed.
|
0
components/tuya_dimmer_as_fan/__init__.py
Normal file
0
components/tuya_dimmer_as_fan/__init__.py
Normal file
40
components/tuya_dimmer_as_fan/fan.py
Normal file
40
components/tuya_dimmer_as_fan/fan.py
Normal file
@ -0,0 +1,40 @@
|
||||
from esphome.components import fan
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import CONF_OUTPUT_ID, CONF_SWITCH_DATAPOINT
|
||||
from esphome.components.tuya import CONF_TUYA_ID, Tuya
|
||||
|
||||
DEPENDENCIES = ["tuya"]
|
||||
|
||||
CONF_DIMMER_DATAPOINT = "dimmer_datapoint"
|
||||
CONF_MAX_VALUE = "dimmer_max_value"
|
||||
|
||||
tuya_ns = cg.esphome_ns.namespace("tuya")
|
||||
TuyaFan = tuya_ns.class_("TuyaDimmerAsFan", 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.Required(CONF_SWITCH_DATAPOINT): cv.uint8_t,
|
||||
cv.Required(CONF_DIMMER_DATAPOINT): cv.uint8_t,
|
||||
cv.Optional(CONF_MAX_VALUE): cv.int_,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
parent = await cg.get_variable(config[CONF_TUYA_ID])
|
||||
state = await fan.create_fan_state(config)
|
||||
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_OUTPUT_ID], parent, state
|
||||
)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_switch_id(config[CONF_SWITCH_DATAPOINT]))
|
||||
cg.add(var.set_dimmer_id(config[CONF_DIMMER_DATAPOINT]))
|
||||
if CONF_MAX_VALUE in config:
|
||||
cg.add(var.set_dimmer_max_value(config[CONF_MAX_VALUE]))
|
40
components/tuya_dimmer_as_fan/tuya_dimmer_as_fan.cpp
Normal file
40
components/tuya_dimmer_as_fan/tuya_dimmer_as_fan.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/fan/fan_helpers.h"
|
||||
#include "tuya_dimmer_as_fan.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace tuya {
|
||||
|
||||
static const char *const TAG = "tuya.fan";
|
||||
|
||||
void TuyaDimmerAsFan::setup() {
|
||||
auto traits = fan::FanTraits(false, false, false, 1);
|
||||
this->fan_->set_traits(traits);
|
||||
|
||||
this->parent_->register_listener(*this->switch_id_, [this](const TuyaDatapoint &datapoint) {
|
||||
auto call = this->fan_->make_call();
|
||||
call.set_state(datapoint.value_bool);
|
||||
call.perform();
|
||||
});
|
||||
|
||||
this->parent_->register_listener(*this->dimmer_id_, [this](const TuyaDatapoint &datapoint) {
|
||||
if (datapoint.value_int != this->dimmer_max_value_)
|
||||
{
|
||||
this->parent_->set_datapoint_value(*this->dimmer_id_, this->dimmer_max_value_);
|
||||
}
|
||||
});
|
||||
|
||||
this->fan_->add_on_state_callback([this]() { this->parent_->set_datapoint_value(*this->switch_id_, this->fan_->state); });
|
||||
|
||||
// Make sure we start at the max value
|
||||
this->parent_->set_datapoint_value(*this->dimmer_id_, this->dimmer_max_value_);
|
||||
}
|
||||
|
||||
void TuyaDimmerAsFan::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Tuya Dimmer as Fan:");
|
||||
ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_);
|
||||
ESP_LOGCONFIG(TAG, " Dimmer has datapoint ID %u", *this->dimmer_id_);
|
||||
}
|
||||
|
||||
} // namespace tuya
|
||||
} // namespace esphome
|
28
components/tuya_dimmer_as_fan/tuya_dimmer_as_fan.h
Normal file
28
components/tuya_dimmer_as_fan/tuya_dimmer_as_fan.h
Normal file
@ -0,0 +1,28 @@
|
||||
#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 TuyaDimmerAsFan : public Component {
|
||||
public:
|
||||
TuyaDimmerAsFan(Tuya *parent, fan::FanState *fan) : parent_(parent), fan_(fan) {}
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void set_switch_id(uint8_t switch_id) { this->switch_id_ = switch_id; }
|
||||
void set_dimmer_id(uint8_t dimmer_id) { this->dimmer_id_ = dimmer_id; }
|
||||
void set_dimmer_max_value(uint32_t max_value) { this->dimmer_max_value_ = max_value; }
|
||||
|
||||
protected:
|
||||
Tuya *parent_;
|
||||
optional<uint8_t> switch_id_{};
|
||||
optional<uint8_t> dimmer_id_{};
|
||||
uint32_t dimmer_max_value_ = 255;
|
||||
fan::FanState *fan_;
|
||||
};
|
||||
|
||||
} // namespace tuya
|
||||
} // namespace esphome
|
@ -1,64 +0,0 @@
|
||||
#include "esphome.h"
|
||||
|
||||
using namespace esphome;
|
||||
|
||||
class TuyaDimmerBinaryFanOutput : public Component, public output::BinaryOutput
|
||||
{
|
||||
public:
|
||||
void setup() override;
|
||||
|
||||
void set_dimmer_id(uint8_t dimmer_id) { this->dimmer_id_ = dimmer_id; }
|
||||
void set_switch_id(uint8_t switch_id) { this->switch_id_ = switch_id; }
|
||||
void set_tuya_parent(tuya::Tuya *parent) { this->parent_ = parent; }
|
||||
void set_max_value(uint32_t max_value) { max_value_ = max_value; }
|
||||
void set_fan(fan::FanState *fan) { fan_ = fan; }
|
||||
|
||||
protected:
|
||||
void write_state(bool state) override;
|
||||
void handle_tuya_datapoint(tuya::TuyaDatapoint datapoint);
|
||||
|
||||
tuya::Tuya *parent_;
|
||||
optional<uint8_t> dimmer_id_{};
|
||||
optional<uint8_t> switch_id_{};
|
||||
uint32_t max_value_ = 1000;
|
||||
fan::FanState *fan_;
|
||||
};
|
||||
|
||||
void TuyaDimmerBinaryFanOutput::setup()
|
||||
{
|
||||
parent_->register_listener(*switch_id_, [this](tuya::TuyaDatapoint datapoint) { handle_tuya_datapoint(datapoint); });
|
||||
|
||||
parent_->register_listener(*dimmer_id_, [this](tuya::TuyaDatapoint datapoint) { handle_tuya_datapoint(datapoint); });
|
||||
}
|
||||
|
||||
void TuyaDimmerBinaryFanOutput::write_state(bool state)
|
||||
{
|
||||
tuya::TuyaDatapoint datapoint{};
|
||||
datapoint.id = *switch_id_;
|
||||
datapoint.type = tuya::TuyaDatapointType::BOOLEAN;
|
||||
datapoint.value_bool = state;
|
||||
parent_->set_datapoint_value(datapoint);
|
||||
}
|
||||
|
||||
void TuyaDimmerBinaryFanOutput::handle_tuya_datapoint(tuya::TuyaDatapoint datapoint)
|
||||
{
|
||||
if (datapoint.id == *switch_id_)
|
||||
{
|
||||
auto call = fan_->make_call();
|
||||
call.set_state(datapoint.value_bool);
|
||||
call.perform();
|
||||
}
|
||||
else if (datapoint.id == *dimmer_id_)
|
||||
{
|
||||
if (datapoint.value_uint < max_value_)
|
||||
{
|
||||
tuya::TuyaDatapoint datapoint{};
|
||||
datapoint.id = *dimmer_id_;
|
||||
datapoint.type = tuya::TuyaDatapointType::INTEGER;
|
||||
datapoint.value_uint = max_value_;
|
||||
parent_->set_datapoint_value(datapoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TuyaDimmerBinaryFanOutput *TuyaFanOutput;
|
@ -1,392 +0,0 @@
|
||||
#include "esphome.h"
|
||||
|
||||
using namespace esphome;
|
||||
|
||||
#define DOUBLE_TAP_TIMEOUT 300
|
||||
|
||||
static const char* TAG = "NuttyTuyaLight";
|
||||
|
||||
class TuyaLightPlus : public Component, public light::LightOutput, public api::CustomAPIDevice
|
||||
{
|
||||
public:
|
||||
void setup() override;
|
||||
void set_dimmer_id(uint8_t dimmer_id) { this->dimmer_id_ = dimmer_id; }
|
||||
void set_switch_id(uint8_t switch_id) { this->switch_id_ = switch_id; }
|
||||
void set_tuya_parent(tuya::Tuya *parent) { this->parent_ = parent; }
|
||||
void set_min_value(uint32_t min_value) { this->min_value_ = min_value; }
|
||||
void set_max_value(uint32_t max_value) { this->max_value_ = max_value; }
|
||||
light::LightTraits get_traits() override;
|
||||
void setup_state(light::LightState *state) override;
|
||||
void write_state(light::LightState *state) override;
|
||||
void loop() override;
|
||||
|
||||
void set_day_default_brightness(float brightness) { this->day_default_brightness_ = brightness; }
|
||||
void set_night_default_brightness(float brightness) { this->night_default_brightness_ = brightness; }
|
||||
void set_day_auto_off_minutes(uint32_t minutes) { this->day_auto_off_time_ = minutes * 60 * 1000; }
|
||||
void set_night_auto_off_minutes(uint32_t minutes) { this->night_auto_off_time_ = minutes * 60 * 1000; }
|
||||
void set_api_server(api::APIServer *api_server) { this->api_server_ = api_server; };
|
||||
void set_day_night_sensor(const std::string day_night_sensor);
|
||||
void set_linked_lights(const std::string linked_lights);
|
||||
void add_double_tap_while_on_callback(const std::function<void()> &func);
|
||||
void add_double_tap_while_off_callback(const std::function<void()> &func);
|
||||
void set_double_tap_while_off_stays_on(bool stays_on) { this->double_tap_while_off_stays_on_ = stays_on; }
|
||||
void add_double_tap_callback(const std::function<void()> &func);
|
||||
|
||||
void set_default_brightness(float brightness);
|
||||
void set_auto_off_minutes(int minutes) { this->current_auto_off_time_ = minutes * 60 * 1000; }
|
||||
|
||||
protected:
|
||||
float tuya_level_to_brightness(uint32_t level) { return static_cast<float>(level) / static_cast<float>(this->max_value_); }
|
||||
uint32_t brightness_to_tuya_level(float brightness) { return static_cast<uint32_t>(brightness * this->max_value_); }
|
||||
float brightness_pct() { return static_cast<uint32_t>(this->state_->current_values.get_brightness() * 100); }
|
||||
void on_day_night_changed(std::string state);
|
||||
void handle_tuya_datapoint(tuya::TuyaDatapoint datapoint);
|
||||
void set_tuya_state(bool state);
|
||||
void set_tuya_level(uint32_t level);
|
||||
void update_linked_lights();
|
||||
void set_default_auto_off_time(int time) { this->default_auto_off_time_ = time; this->current_auto_off_time_ = time; }
|
||||
|
||||
tuya::Tuya *parent_;
|
||||
optional<uint8_t> dimmer_id_{};
|
||||
optional<uint8_t> switch_id_{};
|
||||
uint32_t min_value_ = 0;
|
||||
uint32_t max_value_ = 255;
|
||||
light::LightState *state_{nullptr};
|
||||
|
||||
float day_default_brightness_ = 1;
|
||||
float night_default_brightness_ = .03;
|
||||
float default_brightness_ = 1;
|
||||
uint32_t day_auto_off_time_ = 0;
|
||||
uint32_t night_auto_off_time_ = 0;
|
||||
uint32_t default_auto_off_time_ = 0;
|
||||
uint32_t current_auto_off_time_ = 0;
|
||||
bool has_linked_lights_;
|
||||
api::APIServer *api_server_;
|
||||
api::HomeAssistantServiceCallAction<> *linked_lights_turn_on_action_;
|
||||
api::HomeAssistantServiceCallAction<> *linked_lights_turn_off_action_;
|
||||
bool has_double_tap_while_on_ = false;
|
||||
std::vector<std::function<void()>> double_tap_while_on_callbacks_;
|
||||
bool has_double_tap_while_off_ = false;
|
||||
std::vector<std::function<void()>> double_tap_while_off_callbacks_;
|
||||
bool double_tap_while_off_stays_on_ = true;
|
||||
|
||||
bool tuya_state_;
|
||||
unsigned long state_changed_at_ = 0;
|
||||
unsigned long double_tap_while_on_timeout_ = 0;
|
||||
bool was_double_tapped_while_on_;
|
||||
unsigned long double_tap_while_off_timeout_ = 0;
|
||||
bool was_double_tapped_while_off_;
|
||||
};
|
||||
|
||||
void TuyaLightPlus::setup()
|
||||
{
|
||||
this->parent_->register_listener(*this->switch_id_, [this](tuya::TuyaDatapoint datapoint) { this->handle_tuya_datapoint(datapoint); });
|
||||
|
||||
this->parent_->register_listener(*this->dimmer_id_, [this](tuya::TuyaDatapoint datapoint) { this->handle_tuya_datapoint(datapoint); });
|
||||
|
||||
this->register_service(&TuyaLightPlus::set_auto_off_minutes, "set_auto_off_minutes", {"minutes"});
|
||||
|
||||
this->register_service(&TuyaLightPlus::set_default_brightness, "set_default_brightness", {"brightness"});
|
||||
}
|
||||
|
||||
light::LightTraits TuyaLightPlus::get_traits() {
|
||||
auto traits = light::LightTraits();
|
||||
traits.set_supports_brightness(this->dimmer_id_.has_value());
|
||||
return traits;
|
||||
}
|
||||
|
||||
void TuyaLightPlus::setup_state(light::LightState *state)
|
||||
{
|
||||
this->state_ = state;
|
||||
this->tuya_state_ = this->state_->current_values.is_on();
|
||||
}
|
||||
|
||||
void TuyaLightPlus::write_state(light::LightState *state)
|
||||
{
|
||||
float brightness;
|
||||
state->current_values_as_brightness(&brightness);
|
||||
|
||||
if (brightness == 0.0f)
|
||||
{
|
||||
this->set_tuya_state(false);
|
||||
}
|
||||
else if (this->tuya_state_)
|
||||
{
|
||||
// The light is already on so just set the brightness
|
||||
this->set_tuya_level(this->brightness_to_tuya_level(brightness));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the light is currently off only turn it on, we will set the brightness in the datapoint handler
|
||||
this->set_tuya_state(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::loop()
|
||||
{
|
||||
// Double tap while on timed out
|
||||
if (this->double_tap_while_on_timeout_ != 0 && millis() > this->double_tap_while_on_timeout_)
|
||||
{
|
||||
this->double_tap_while_on_timeout_ = 0;
|
||||
}
|
||||
|
||||
// Handle double tap while on callbacks
|
||||
if (this->was_double_tapped_while_on_)
|
||||
{
|
||||
this->was_double_tapped_while_on_ = false;
|
||||
for (auto &callback : this->double_tap_while_on_callbacks_)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
// Double tap while off timed out, turn the light on
|
||||
if (this->double_tap_while_off_timeout_ != 0 && millis() > this->double_tap_while_off_timeout_)
|
||||
{
|
||||
this->double_tap_while_off_timeout_ = 0;
|
||||
this->set_tuya_state(true);
|
||||
}
|
||||
|
||||
// Handle double tap while off callbacks
|
||||
if (this->was_double_tapped_while_off_)
|
||||
{
|
||||
this->was_double_tapped_while_off_ = false;
|
||||
for (auto &callback : this->double_tap_while_off_callbacks_)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle auto turn off
|
||||
if (this->current_auto_off_time_ != 0 && this->tuya_state_ && millis() >= this->state_changed_at_ + this->current_auto_off_time_)
|
||||
{
|
||||
this->set_tuya_state(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::set_day_night_sensor(const std::string day_night_sensor)
|
||||
{
|
||||
if (day_night_sensor != "")
|
||||
{
|
||||
this->subscribe_homeassistant_state(&TuyaLightPlus::on_day_night_changed, day_night_sensor);
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::set_linked_lights(const std::string linked_lights)
|
||||
{
|
||||
if (linked_lights != "")
|
||||
{
|
||||
this->has_linked_lights_ = true;
|
||||
|
||||
this->linked_lights_turn_on_action_ = new api::HomeAssistantServiceCallAction<>(this->api_server_, false);
|
||||
this->linked_lights_turn_on_action_->set_service("light.turn_on");
|
||||
this->linked_lights_turn_on_action_->add_data("entity_id", linked_lights);
|
||||
this->linked_lights_turn_on_action_->add_variable("brightness_pct", [=]() { return this->brightness_pct(); });
|
||||
this->linked_lights_turn_on_action_->add_data_template("brightness_pct", "{{ brightness_pct }}");
|
||||
|
||||
this->linked_lights_turn_off_action_ = new api::HomeAssistantServiceCallAction<>(this->api_server_, false);
|
||||
this->linked_lights_turn_off_action_->set_service("light.turn_off");
|
||||
this->linked_lights_turn_off_action_->add_data("entity_id", linked_lights);
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::add_double_tap_while_on_callback(const std::function<void()> &func)
|
||||
{
|
||||
this->has_double_tap_while_on_ = true;
|
||||
this->double_tap_while_on_callbacks_.push_back(func);
|
||||
}
|
||||
|
||||
void TuyaLightPlus::add_double_tap_while_off_callback(const std::function<void()> &func)
|
||||
{
|
||||
this->has_double_tap_while_off_ = true;
|
||||
this->double_tap_while_off_callbacks_.push_back(func);
|
||||
}
|
||||
|
||||
void TuyaLightPlus::add_double_tap_callback(const std::function<void()> &func)
|
||||
{
|
||||
this->add_double_tap_while_off_callback(func);
|
||||
this->add_double_tap_while_on_callback(func);
|
||||
}
|
||||
|
||||
void TuyaLightPlus::set_default_brightness(float brightness)
|
||||
{
|
||||
this->default_brightness_ = brightness > 1 ? 1 : brightness;
|
||||
|
||||
// If the light is off update the brightness in the state and publish so regardless of how the light is turned on the brightness will be the default
|
||||
if (!this->tuya_state_)
|
||||
{
|
||||
this->state_->current_values.set_brightness(this->default_brightness_);
|
||||
this->state_->remote_values = this->state_->current_values;
|
||||
this->state_->publish_state();
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::on_day_night_changed(std::string state)
|
||||
{
|
||||
if (state == "Day")
|
||||
{
|
||||
this->set_default_brightness(day_default_brightness_);
|
||||
this->set_default_auto_off_time(day_auto_off_time_);
|
||||
}
|
||||
else if (state == "Night")
|
||||
{
|
||||
this->set_default_brightness(night_default_brightness_);
|
||||
this->set_default_auto_off_time(night_auto_off_time_);
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::handle_tuya_datapoint(tuya::TuyaDatapoint datapoint)
|
||||
{
|
||||
ESP_LOGD(TAG, "Received Datapoint:");
|
||||
if (datapoint.id == *this->switch_id_)
|
||||
{
|
||||
ESP_LOGD(TAG, " Type: Switch");
|
||||
|
||||
// Light turned on
|
||||
if (datapoint.value_bool)
|
||||
{
|
||||
ESP_LOGD(TAG, " State: On");
|
||||
|
||||
// Turned on with the physical button
|
||||
if (!this->tuya_state_)
|
||||
{
|
||||
ESP_LOGD(TAG, "Turned on at device");
|
||||
|
||||
if (this->has_double_tap_while_on_)
|
||||
{
|
||||
// We are in a double tap while on timeout period so this is a double tap
|
||||
if (this->double_tap_while_on_timeout_ != 0)
|
||||
{
|
||||
// Double tap while on always stays off otherwise it results in weird flashing behavior
|
||||
this->set_tuya_state(false);
|
||||
this->double_tap_while_on_timeout_ = 0;
|
||||
this->was_double_tapped_while_on_ = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this->has_double_tap_while_off_)
|
||||
{
|
||||
// We are not in a double tap while off timeout period
|
||||
if (this->double_tap_while_off_timeout_ == 0)
|
||||
{
|
||||
// Turn the light back off and wait to see if we get a double tap
|
||||
this->set_tuya_state(false);
|
||||
this->double_tap_while_off_timeout_ = millis() + DOUBLE_TAP_TIMEOUT;
|
||||
return;
|
||||
}
|
||||
// We are in a double tap while off timeout period so this is a double tap
|
||||
else
|
||||
{
|
||||
this->double_tap_while_off_timeout_ = 0;
|
||||
this->was_double_tapped_while_off_ = true;
|
||||
|
||||
// If double tap while off triggers an event but does not turn on the light then turn it back off
|
||||
if (!this->double_tap_while_off_stays_on_)
|
||||
{
|
||||
this->set_tuya_state(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We got through all the double tap logic and the light is still on so update the Tuya state
|
||||
ESP_LOGD(TAG, "Updating Tuya state to on");
|
||||
this->tuya_state_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the brightness to the correct level (it currently is at 0)
|
||||
this->set_tuya_level(this->brightness_to_tuya_level(this->state_->current_values.get_brightness()));
|
||||
}
|
||||
}
|
||||
// Light turned off
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, " State: Off");
|
||||
|
||||
// Turned off with physical button
|
||||
if (this->tuya_state_)
|
||||
{
|
||||
ESP_LOGD(TAG, "Turned off at device");
|
||||
|
||||
if (has_double_tap_while_on_)
|
||||
{
|
||||
// Start the double tap while on timeout
|
||||
this->double_tap_while_on_timeout_ = millis() + DOUBLE_TAP_TIMEOUT;
|
||||
}
|
||||
|
||||
// Update the Tuya state
|
||||
ESP_LOGD(TAG, "Updating Tuya state to off");
|
||||
this->tuya_state_ = false;
|
||||
}
|
||||
|
||||
// Set the Tuya level to 0 to prevent flashes during double taps
|
||||
ESP_LOGD(TAG, "Updating Tuya level to 0");
|
||||
this->set_tuya_level(0);
|
||||
|
||||
// Set the current brightness to the default so that it will turn on at the default brightness
|
||||
ESP_LOGD(TAG, "Updating brightness state to default");
|
||||
this->state_->current_values.set_brightness(this->default_brightness_);
|
||||
}
|
||||
|
||||
// Update the current values state
|
||||
ESP_LOGD(TAG, "Updating state to new value");
|
||||
this->state_->current_values.set_state(this->tuya_state_);
|
||||
}
|
||||
else if (datapoint.id == *this->dimmer_id_)
|
||||
{
|
||||
ESP_LOGD(TAG, " Type: Brightness");
|
||||
ESP_LOGD(TAG, " Value: %u", datapoint.value_uint);
|
||||
|
||||
// Only react to dimmer level changes if the light is on
|
||||
if(this->tuya_state_)
|
||||
{
|
||||
this->state_->current_values.set_brightness(tuya_level_to_brightness(datapoint.value_uint));
|
||||
}
|
||||
}
|
||||
|
||||
// Update state changed at time
|
||||
this->state_changed_at_ = millis();
|
||||
|
||||
// If the remote values do not reflect the current values update and publish the values
|
||||
if (this->state_->current_values.get_state() != this->state_->remote_values.get_state()
|
||||
|| this->state_->current_values.get_brightness() != this->state_->remote_values.get_brightness())
|
||||
{
|
||||
ESP_LOGD(TAG, "Publishing new state");
|
||||
this->state_->remote_values = this->state_->current_values;
|
||||
this->state_->publish_state();
|
||||
}
|
||||
|
||||
// Update any linked lights
|
||||
ESP_LOGD(TAG, "Updating linked lights");
|
||||
this->update_linked_lights();
|
||||
}
|
||||
|
||||
void TuyaLightPlus::set_tuya_state(bool state)
|
||||
{
|
||||
this->tuya_state_ = state;
|
||||
|
||||
this->parent_->set_datapoint_value(*this->switch_id_, state);
|
||||
}
|
||||
|
||||
void TuyaLightPlus::set_tuya_level(uint32_t level)
|
||||
{
|
||||
this->parent_->set_datapoint_value(*this->dimmer_id_, std::max(level, this->min_value_));
|
||||
}
|
||||
|
||||
void TuyaLightPlus::update_linked_lights()
|
||||
{
|
||||
if (this->has_linked_lights_)
|
||||
{
|
||||
if (this->state_->current_values.is_on())
|
||||
{
|
||||
this->linked_lights_turn_on_action_->play();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->linked_lights_turn_off_action_->play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TuyaLightPlus *TuyaLight;
|
@ -3,7 +3,6 @@ substitutions:
|
||||
board: esp01_1m
|
||||
|
||||
external_components:
|
||||
# - source: github://nuttytree/esphome@more-tuya-reliability-improvements
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
|
@ -2,34 +2,23 @@ substitutions:
|
||||
platform: ESP8266
|
||||
board: esp01_1m
|
||||
|
||||
esphome:
|
||||
includes:
|
||||
- ../custom/tuya_dimmer_as_binary_fan_output.h
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ tuya, tuya_dimmer_as_fan ]
|
||||
|
||||
packages:
|
||||
base: !include device_base.yaml
|
||||
logger: !include logger/logger_no_serial.yaml
|
||||
uart: !include uart/tuya.yaml
|
||||
|
||||
fan:
|
||||
- platform: binary
|
||||
id: the_fan
|
||||
output: tuya_fan_output
|
||||
name: ${device_name}
|
||||
|
||||
tuya:
|
||||
|
||||
output:
|
||||
- platform: custom
|
||||
type: binary
|
||||
lambda: |-
|
||||
TuyaFanOutput = new TuyaDimmerBinaryFanOutput();
|
||||
TuyaFanOutput->set_switch_id(1);
|
||||
TuyaFanOutput->set_dimmer_id(2);
|
||||
TuyaFanOutput->set_max_value(1000);
|
||||
TuyaFanOutput->set_tuya_parent(tuya_tuya);
|
||||
TuyaFanOutput->set_fan(the_fan);
|
||||
App.register_component(TuyaFanOutput);
|
||||
return {TuyaFanOutput};
|
||||
outputs:
|
||||
id: tuya_fan_output
|
||||
fan:
|
||||
- platform: tuya_dimmer_as_fan
|
||||
id: tuya_fan
|
||||
name: ${device_name}
|
||||
switch_datapoint: 1
|
||||
dimmer_datapoint: 2
|
||||
dimmer_max_value: 1000
|
||||
|
@ -1,51 +0,0 @@
|
||||
substitutions:
|
||||
platform: ESP8266
|
||||
board: esp01_1m
|
||||
log_level: verbose
|
||||
|
||||
esphome:
|
||||
includes:
|
||||
- ../custom/tuya_light_plus.h
|
||||
on_boot:
|
||||
priority: -100
|
||||
then:
|
||||
- script.execute: startup
|
||||
|
||||
external_components:
|
||||
# - source: github://nuttytree/esphome@more-tuya-reliability-improvements
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ tuya ]
|
||||
|
||||
packages:
|
||||
base: !include device_base.yaml
|
||||
logger: !include logger/logger_no_serial.yaml
|
||||
uart: !include uart/tuya.yaml
|
||||
|
||||
tuya:
|
||||
|
||||
light:
|
||||
- platform: custom
|
||||
lambda: |-
|
||||
TuyaLight = new TuyaLightPlus();
|
||||
TuyaLight->set_switch_id(1);
|
||||
TuyaLight->set_dimmer_id(2);
|
||||
TuyaLight->set_min_value(0);
|
||||
TuyaLight->set_max_value(1000);
|
||||
TuyaLight->set_tuya_parent(tuya_tuya);
|
||||
TuyaLight->set_day_night_sensor("sensor.day_night");
|
||||
TuyaLight->set_day_default_brightness(${day_brightness});
|
||||
TuyaLight->set_night_default_brightness(${night_brightness});
|
||||
TuyaLight->set_day_auto_off_minutes(${day_auto_off_minutes});
|
||||
TuyaLight->set_night_auto_off_minutes(${night_auto_off_minutes});
|
||||
TuyaLight->set_api_server(api_apiserver);
|
||||
TuyaLight->set_linked_lights("${linked_lights}");
|
||||
TuyaLight->set_double_tap_while_off_stays_on(${double_tap_while_off_stays_on});
|
||||
App.register_component(TuyaLight);
|
||||
return {TuyaLight};
|
||||
lights:
|
||||
- id: tuya_light
|
||||
name: ${device_name}
|
||||
gamma_correct: 1.0
|
||||
default_transition_length: 0s
|
Loading…
Reference in New Issue
Block a user