Add new TuyaLightPlus

Start re-arranging folders
This commit is contained in:
ChNussbaum 2020-09-28 22:22:53 -05:00
parent fc5873c2cf
commit 97f56631f0
26 changed files with 523 additions and 32 deletions

View File

@ -1,29 +0,0 @@
substitutions:
device_id:
device_name:
platform:
board:
ip_address: !secret _ip
ota_pwd: !secret _ota_pwd
api_pwd: !secret _api_pwd
ap_wifi_pwd: !secret _ap_wifi_pwd
esphome:
<<: !include common/esphome.yaml
<<: !include common/common.yaml
<<: !include common/logger/logger_none.yaml
binary_sensor:
- !include common/binary_sensor/status.yaml
sensor:
- !include common/sensor/uptime.yaml
- !include common/sensor/wifi.yaml
switch:
- !include common/switch/restart.yaml
text_sensor:
- !include common/text_sensor/version.yaml
- !include common/text_sensor/wifi.yaml

View File

@ -1,3 +1,5 @@
name: ${device_id}
platform: ${platform}
board: ${board}
board: ${board}
arduino_version: latest
build_path: build/${device_id}

View File

@ -0,0 +1,3 @@
platform: homeassistant
id: day_night
entity_id: input_boolean.day_night

View File

@ -0,0 +1,2 @@
platform: status
name: ${device_name} Status

View File

@ -0,0 +1,7 @@
platform: "tuya"
id: tuya_light
name: ${device_name}
dimmer_datapoint: 2
switch_datapoint: 1
min_value: 0
max_value: 1000

View File

@ -0,0 +1,2 @@
logger:
level: DEBUG

View File

@ -0,0 +1,3 @@
logger:
level: DEBUG
baud_rate: 0

View File

@ -0,0 +1,2 @@
logger:
level: INFO

View File

@ -0,0 +1,3 @@
logger:
level: NONE
baud_rate: 0

View File

@ -0,0 +1,2 @@
platform: uptime
name: ${device_name} Uptime

View File

@ -0,0 +1,2 @@
platform: wifi_signal
name: ${device_name} WiFi Signal

View File

@ -0,0 +1,3 @@
platform: restart
id: reboot
name: Restart ${device_name}

View File

@ -0,0 +1,2 @@
platform: version
name: ${device_name} Version

View File

@ -0,0 +1,4 @@
platform: wifi_info
ip_address:
name: ${device_name} IP Address
icon: mdi:ip-network

View File

@ -0,0 +1,3 @@
rx_pin: GPIO3
tx_pin: GPIO1
baud_rate: 9600

3
core/api.yaml Normal file
View File

@ -0,0 +1,3 @@
api:
password: ${api_pwd}

View File

@ -0,0 +1,60 @@
esphome:
<<: !include esphome.yaml
includes:
- ../custom/tuya_light_plus.h
on_boot:
priority: -100
then:
- script.execute: startup
<<: !include ../components/logger/logger_none.yaml
<<: !include wifi_api_ota.yaml
binary_sensor:
- !include ../components/binary_sensor/status.yaml
light:
# We need this dummy light to get the base tuya_light code to get pulled in to the build folder
- platform: "tuya"
id: dummy_light
switch_datapoint: 255
- 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_on_stays_on(${double_tap_on_stays_on});
App.register_component(TuyaLight);
return {TuyaLight};
lights:
- id: tuya_light
name: ${device_name}
gamma_correct: 1.0
default_transition_length: 0s
sensor:
- !include ../components/sensor/uptime.yaml
- !include ../components/sensor/wifi.yaml
switch:
- !include ../components/switch/restart.yaml
text_sensor:
- !include ../components/text_sensor/version.yaml
- !include ../components/text_sensor/wifi.yaml
tuya:
uart:
- !include ../components/uart/tuya.yaml

5
core/esphome.yaml Normal file
View File

@ -0,0 +1,5 @@
name: ${device_id}
platform: ${platform}
board: ${board}
arduino_version: latest
build_path: ../build/${device_id}

2
core/ota.yaml Normal file
View File

@ -0,0 +1,2 @@
ota:
password: ${ota_pwd}

1
core/secrets.yaml Normal file
View File

@ -0,0 +1 @@
<<: !include ../secrets.yaml

14
core/wifi.yaml Normal file
View File

@ -0,0 +1,14 @@
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
power_save_mode: none
manual_ip:
static_ip: ${ip_address}
subnet: !secret ip_subnet
gateway: !secret ip_gateway
ap:
ssid: ${device_id}
password: ${ap_wifi_pwd}
captive_portal:

3
core/wifi_api_ota.yaml Normal file
View File

@ -0,0 +1,3 @@
<<: !include wifi.yaml
<<: !include api.yaml
<<: !include ota.yaml

340
custom/tuya_light_plus.h Normal file
View File

@ -0,0 +1,340 @@
#include "esphome.h"
class TuyaLightPlus : public tuya::TuyaLight, public CustomAPIDevice
{
public:
void setup() override;
void loop() override;
void write_state(light::LightState *state) override;
void set_day_default_brightness(float brightness) { day_default_brightness_ = brightness; }
void set_night_default_brightness(float brightness) { night_default_brightness_ = brightness; }
void set_day_auto_off_minutes(uint32_t minutes) { day_auto_off_time_ = minutes * 60 * 1000; }
void set_night_auto_off_minutes(uint32_t minutes) { night_auto_off_time_ = minutes * 60 * 1000; }
void set_api_server(api::APIServer *api_server) { 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_off_callback(const std::function<void()> &func);
void add_double_tap_on_callback(const std::function<void()> &func);
void set_double_tap_on_stays_on(bool stays_on) { double_tap_on_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) { current_auto_off_time_ = minutes * 60 * 1000; }
protected:
float tuya_level_to_brightness(uint32_t level) { return float(level) / max_value_; }
uint32_t brightness_to_tuya_level(float brightness) { return static_cast<uint32_t>(brightness * max_value_); }
bool is_on() { return state_->current_values.is_on(); }
float brightness_pct() { return static_cast<uint32_t>(state_->current_values.get_brightness() * 100); }
void on_day_night_changed(std::string state);
void handle_tuya_datapoint(esphome::tuya::TuyaDatapoint datapoint);
void set_tuya_state(bool state);
void set_tuya_level(uint32_t level);
void update_tuya_level();
void update_current_state(bool state);
void update_current_brightness(float brightness);
void update_linked_lights();
void set_default_auto_off_time(int time) { default_auto_off_time_ = time; current_auto_off_time_ = time; }
float day_default_brightness_ = 1;
float night_default_brightness_ = .03;
float default_brightness_ = 1;
uint32_t day_auto_off_time_;
uint32_t night_auto_off_time_;
uint32_t default_auto_off_time_;
uint32_t current_auto_off_time_;
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_off_ = false;
std::vector<std::function<void()>> double_tap_off_callbacks_;
bool has_double_tap_on_ = false;
std::vector<std::function<void()>> double_tap_on_callbacks_;
bool double_tap_on_stays_on_ = true;
unsigned long state_changed_at_;
bool is_software_state_change_;
bool is_reported_state_change_;
unsigned long double_tap_off_timeout_;
bool was_double_tapped_off_;
unsigned long double_tap_on_timeout_;
bool was_double_tapped_on_;
};
void TuyaLightPlus::setup()
{
parent_->register_listener(*switch_id_, [this](esphome::tuya::TuyaDatapoint datapoint) { handle_tuya_datapoint(datapoint); });
parent_->register_listener(*dimmer_id_, [this](esphome::tuya::TuyaDatapoint datapoint) { handle_tuya_datapoint(datapoint); });
register_service(&TuyaLightPlus::set_auto_off_minutes, "set_auto_off_minutes", {"minutes"});
register_service(&TuyaLightPlus::set_default_brightness, "set_default_brightness", {"brightness"});
}
void TuyaLightPlus::loop()
{
if (double_tap_off_timeout_ != 0 && millis() > double_tap_off_timeout_)
{
double_tap_off_timeout_ = 0;
}
if (was_double_tapped_off_)
{
was_double_tapped_off_ = false;
for (auto &callback : this->double_tap_off_callbacks_)
{
callback();
}
}
if (double_tap_on_timeout_ != 0 && millis() > double_tap_on_timeout_)
{
if (!is_on())
{
is_software_state_change_ = true;
set_tuya_state(true);
}
double_tap_on_timeout_ = 0;
}
if (was_double_tapped_on_)
{
was_double_tapped_on_ = false;
for (auto &callback : this->double_tap_on_callbacks_)
{
callback();
}
}
if (current_auto_off_time_ != 0 && is_on() && millis() >= state_changed_at_ + current_auto_off_time_)
{
set_tuya_state(false);
}
}
void TuyaLightPlus::write_state(light::LightState *state)
{
if (!is_reported_state_change_) {
is_software_state_change_ = true;
}
else
{
is_reported_state_change_ = false;
}
TuyaLight::write_state(state);
}
void TuyaLightPlus::set_day_night_sensor(const std::string day_night_sensor)
{
if (day_night_sensor != "")
{
subscribe_homeassistant_state(&TuyaLightPlus::on_day_night_changed, day_night_sensor);
}
}
void TuyaLightPlus::set_linked_lights(const std::string linked_lights)
{
if (linked_lights != "")
{
has_linked_lights_ = true;
linked_lights_turn_on_action_ = new api::HomeAssistantServiceCallAction<>(api_server_, false);
linked_lights_turn_on_action_->set_service("light.turn_on");
linked_lights_turn_on_action_->add_data("entity_id", linked_lights);
linked_lights_turn_on_action_->add_variable("brightness_pct", [=]() { return brightness_pct(); });
linked_lights_turn_on_action_->add_data_template("brightness_pct", "{{ brightness_pct }}");
linked_lights_turn_off_action_ = new api::HomeAssistantServiceCallAction<>(api_server_, false);
linked_lights_turn_off_action_->set_service("light.turn_off");
linked_lights_turn_off_action_->add_data("entity_id", linked_lights);
}
}
void TuyaLightPlus::add_double_tap_off_callback(const std::function<void()> &func)
{
has_double_tap_off_ = true;
this->double_tap_off_callbacks_.push_back(func);
}
void TuyaLightPlus::add_double_tap_on_callback(const std::function<void()> &func)
{
has_double_tap_on_ = true;
this->double_tap_on_callbacks_.push_back(func);
}
void TuyaLightPlus::add_double_tap_callback(const std::function<void()> &func)
{
add_double_tap_on_callback(func);
add_double_tap_off_callback(func);
}
void TuyaLightPlus::set_default_brightness(float brightness)
{
default_brightness_ = brightness > 1 ? 1 : brightness;
update_tuya_level();
}
void TuyaLightPlus::on_day_night_changed(std::string state)
{
if (state == "Day")
{
set_default_brightness(day_default_brightness_);
set_default_auto_off_time(day_auto_off_time_);
}
else if (state == "Night")
{
set_default_brightness(night_default_brightness_);
set_default_auto_off_time(night_auto_off_time_);
}
}
void TuyaLightPlus::handle_tuya_datapoint(esphome::tuya::TuyaDatapoint datapoint)
{
if (datapoint.id == *switch_id_)
{
bool new_state = datapoint.value_bool;
if (!is_software_state_change_)
{
if (has_double_tap_off_)
{
if (is_on() and !new_state)
{
double_tap_off_timeout_ = millis() + 400;
}
else if (new_state && double_tap_off_timeout_ >= millis())
{
set_tuya_state(false);
new_state = false;
double_tap_off_timeout_ = 0;
was_double_tapped_off_ = true;
}
}
if (has_double_tap_on_)
{
if (!is_on() && new_state)
{
if (double_tap_on_timeout_ == 0)
{
set_tuya_state(false);
new_state = false;
double_tap_on_timeout_ = millis() + 400;
update_tuya_level();
}
else
{
double_tap_on_timeout_ = 0;
if (!double_tap_on_stays_on_)
{
set_tuya_state(false);
new_state = false;
}
was_double_tapped_on_ = true;
}
}
}
}
is_software_state_change_ = false;
if (new_state != is_on())
{
is_reported_state_change_ = true;
update_current_state(new_state);
}
}
else if (datapoint.id == *dimmer_id_)
{
is_reported_state_change_ = true;
update_current_brightness(tuya_level_to_brightness(datapoint.value_uint));
}
}
void TuyaLightPlus::set_tuya_state(bool state)
{
is_software_state_change_ = true;
esphome::tuya::TuyaDatapoint datapoint{};
datapoint.id = *switch_id_;
datapoint.type = esphome::tuya::TuyaDatapointType::BOOLEAN;
datapoint.value_bool = state;
parent_->set_datapoint_value(datapoint);
}
void TuyaLightPlus::set_tuya_level(uint32_t level)
{
esphome::tuya::TuyaDatapoint datapoint{};
datapoint.id = *dimmer_id_;
datapoint.type = esphome::tuya::TuyaDatapointType::INTEGER;
datapoint.value_uint = std::max(level, min_value_);
parent_->set_datapoint_value(datapoint);
}
void TuyaLightPlus::update_tuya_level()
{
if (!is_on())
{
if (double_tap_off_timeout_ != 0)
{
set_tuya_level(1);
}
else if (has_double_tap_on_ && double_tap_on_timeout_ == 0)
{
set_tuya_level(1);
}
else
{
set_tuya_level(brightness_to_tuya_level(default_brightness_));
}
}
}
void TuyaLightPlus::update_current_state(bool state)
{
state_changed_at_ = millis();
auto call = state_->make_call();
call.set_state(state);
call.perform();
update_linked_lights();
update_tuya_level();
current_auto_off_time_ = default_auto_off_time_;
}
void TuyaLightPlus::update_current_brightness(float brightness)
{
if (is_on())
{
auto call = state_->make_call();
call.set_brightness(brightness);
call.perform();
update_linked_lights();
}
}
void TuyaLightPlus::update_linked_lights()
{
if (has_linked_lights_)
{
if (is_on())
{
linked_lights_turn_on_action_->play();
}
else
{
linked_lights_turn_off_action_->play();
}
}
}
TuyaLightPlus *TuyaLight;

10
devices/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Gitignore settings for ESPHome
# This is an example and may include too much for your use-case.
# You can modify this file to suit your needs.
/.esphome/
**/.pioenvs/
**/.piolibdeps/
**/lib/
**/src/
**/platformio.ini
/secrets.yaml

View File

@ -9,7 +9,16 @@ substitutions:
ap_wifi_pwd: !secret front_lights_ap_wifi_pwd
day_brightness: "1"
night_brightness: "1"
night_auto_off_time: 15min
day_auto_off_minutes: "30"
night_auto_off_minutes: "15"
linked_lights: ""
double_tap_on_stays_on: "true"
script:
- id: startup
then:
- lambda: |-
TuyaLight->add_double_tap_on_callback([]() { TuyaLight->set_auto_off_minutes(0); });
<<: !include ../core/device_tuya_dimmer.yaml
<<: !include common/device_tuya_dimmer.yaml

View File

@ -0,0 +1,33 @@
substitutions:
device_id: scripture_of_the_day_1
device_name: Scripture of the Day #1
platform: ESP8266
board: nodemcuv2
ip_address: !secret master_bath_humidity_temp_sensor_ip
ota_pwd: !secret master_bath_humidity_temp_sensor_ota_pwd
api_pwd: !secret master_bath_humidity_temp_sensor_api_pwd
ap_wifi_pwd: !secret master_bath_humidity_temp_sensor_ap_wifi_pwd
esphome:
<<: !include ../core/esphome.yaml
on_boot:
priority: -100
then:
- http_request.get:
url: "https://beta.ourmanna.com/api/v1/get/?format=json&order=random"
verify_ssl: false
- lambda: |-
auto json = http_request_httprequestcomponent->get_string();
<<: !include ../components/logger/logger_debug.yaml
<<: !include ../core/wifi_api_ota.yaml
http_request:
text_sensor:
- platform: template
id: scripture
- platform: template
id: reference