From 3457f49bdcab3cfeb7d482a2be80d5183008c229 Mon Sep 17 00:00:00 2001 From: ChNussbaum Date: Wed, 13 May 2020 16:36:37 -0500 Subject: [PATCH] Add a bunch of Feit Dimmers --- README.md | 25 ++++--- basement_stair_lights.yaml | 15 +++++ basement_stair_lights_2.yaml | 15 +++++ common/device_tuya_dimmer.yaml | 50 ++++++++++++++ computer_light.yaml | 15 +++++ family_room_light.yaml | 24 ++----- fire_pit_fountain.yaml | 10 +-- kitchen_table_light.yaml | 24 ++----- office_light.yaml | 24 ++----- tuya_light_control.h | 117 +++++++++++++++++++++++++++++++++ 10 files changed, 250 insertions(+), 69 deletions(-) create mode 100644 basement_stair_lights.yaml create mode 100644 basement_stair_lights_2.yaml create mode 100644 common/device_tuya_dimmer.yaml create mode 100644 computer_light.yaml create mode 100644 tuya_light_control.h diff --git a/README.md b/README.md index 6cf3b56..a9c2aea 100644 --- a/README.md +++ b/README.md @@ -40,13 +40,22 @@ > This switch will be installed in place of the switch that controls my [TREO LED Pool Lights](https://www.amazon.com/gp/product/B06XTRLM5M/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1). These lights have the option to select different colors by briefly turning them off and back on again and they do remember the last color when turned on again. The custom light component handles tracking the current color and exposes custom "effects" for each of the colors to [Home Assistant](https://www.home-assistant.io/). I went with the triple switch so that I could use the third button to control my [Patio Lights](#patio-lights) which otherwise do not have a physical switch. Note I have tested the code on a [WEMOS D1 Mini clone](https://www.amazon.com/gp/product/B076F52NQD/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) but I have not installed this on the switch yet or confirmed the timings actually work with the lights yet. ## Dimmer Switches -> I have been trying to find a dimmer switch I realy like to standardize on through out my home but haven't found it yet. These are the dimmers I have tried so far. - -> ### [Feit Dimmer](https://www.costco.com/feit-electric-smart-dimmer%2c-3-pack.product.100518151.html) -> I bought these as a 2 pack from Costco. The price is right, they seem to be a fairly solid device, and I was able to flash them using [Tuya-Convert](https://github.com/ct-Open-Source/tuya-convert). Things I don't like are the fact that you have to click repeatedly to change the brightness (can't hold to change) and all buttons are managed by the Tuya MCU so no ability to do things like double-taps or change the default brightness based on day/night mode. +> After trying several dimmers I finally decided to standardize on on the [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1). I bought the first couple of these at Costco for a better price than Amazon but Costco doesn't seem to carry them anymore. +> Things I like about these switches: +> > * Can be flashed using [Tuya-Convert](https://github.com/ct-Open-Source/tuya-convert) +> > * Have a solid feel to them +> > * They can be linked via a traveler wire (this works even when flashed with ESPHome and while not mentioned in the documentation you can link more than 2 switches this way) +> Things I don't like about these switches: +> > * Have to click repeatedly to change the brightness (can't hold to change) +> > * All buttons are managed by the Tuya MCU so no ability to do things like double-taps (although I may have a solution for this but haven't had a chance to do a POC) +> I have created a custom component for these that should work with most (if not all) Tuya dimmers which provides the following extra features: +> > * Resets the brightness level back to a default level when turned off so that it always comes on at the same level instead of the level it was at when turned off +> > * The default level is configurable as different levels when my house is in "Day" mode vs "Night" mode (based on a binary sensor in Home Assistant) +> > * Provides a service that I can dynamically change the current default brightness level +> > * Allows you to "link" another light in Home Assistant that will be controlled by this dimmer +> The following devices are Feit Dimmers: +> > * Basement Stair Lights/Basement Stair Lights 2 +> > * Computer Light +> > * Family Room Light > > * Kitchen Table Light > > * Office Light - -> ### [MOES Dimmer](https://www.amazon.com/gp/product/B07PLCMR71/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) -> I bought one of these off Amazon. The price is good, I like the ability to touch the level you want on the front (and even better you can change the level from the touch sensor before you turn the light on), and I was able to flash it using [Tuya-Convert](https://github.com/ct-Open-Source/tuya-convert). What I don't like is the loose feeling of the switch and the fact that the Tuya MCU is controlling everything so no ability to do things like double-taps or change the default brightness based on day/night mode. -> > * Family Room Light diff --git a/basement_stair_lights.yaml b/basement_stair_lights.yaml new file mode 100644 index 0000000..d8404e5 --- /dev/null +++ b/basement_stair_lights.yaml @@ -0,0 +1,15 @@ +substitutions: + device_id: basement_stair_lights + device_name: Basement Stair Lights + platform: ESP8266 + board: esp01_1m + ip_address: !secret basement_stair_lights_ip + ota_pwd: !secret basement_stair_lights_ota_pwd + api_pwd: !secret basement_stair_lights_api_pwd + ap_wifi_pwd: !secret basement_stair_lights_ap_wifi_pwd + day_brightness: "1" + night_brightness: ".03" + night_auto_off_time: 15min + linked_lights: "light.basement_stair_lights_2" + +<<: !include common/device_tuya_dimmer.yaml diff --git a/basement_stair_lights_2.yaml b/basement_stair_lights_2.yaml new file mode 100644 index 0000000..f806a8c --- /dev/null +++ b/basement_stair_lights_2.yaml @@ -0,0 +1,15 @@ +substitutions: + device_id: basement_stair_lights_2 + device_name: Basement Stair Lights 2 + platform: ESP8266 + board: esp01_1m + ip_address: !secret basement_stair_lights_2_ip + ota_pwd: !secret basement_stair_lights_2_ota_pwd + api_pwd: !secret basement_stair_lights_2_api_pwd + ap_wifi_pwd: !secret basement_stair_lights_2_ap_wifi_pwd + day_brightness: "1" + night_brightness: ".03" + night_auto_off_time: 15min + linked_lights: "light.basement_stair_lights" + +<<: !include common/device_tuya_dimmer.yaml diff --git a/common/device_tuya_dimmer.yaml b/common/device_tuya_dimmer.yaml new file mode 100644 index 0000000..a219d7c --- /dev/null +++ b/common/device_tuya_dimmer.yaml @@ -0,0 +1,50 @@ +esphome: + <<: !include esphome.yaml + includes: + - tuya_light_control.h + +<<: !include common_tuya_dimmer.yaml +<<: !include logger/logger_none.yaml + +interval: + - interval: 1min + then: + if: + condition: + and: + - binary_sensor.is_off: day_night + - for: + time: ${night_auto_off_time} + condition: + light.is_on: tuya_light + then: + - light.turn_off: tuya_light + +custom_component: + - lambda: |- + auto control = new TuyaLightControl(); + control->set_switch_id(1); + control->set_dimmer_id(2); + control->set_min_value(0); + control->set_max_value(1000); + control->set_tuya_parent(tuya_tuya); + control->set_day_brightness(${day_brightness}); + control->set_night_brightness(${night_brightness}); + control->set_api_server(api_apiserver); + control->set_linked_lights("${linked_lights}"); + return {control}; + +binary_sensor: + - !include binary_sensor/status.yaml + - !include binary_sensor/day_night.yaml + +sensor: + - !include sensor/uptime.yaml + - !include sensor/wifi.yaml + +switch: + - !include switch/restart.yaml + +text_sensor: + - !include text_sensor/version.yaml + - !include text_sensor/wifi.yaml \ No newline at end of file diff --git a/computer_light.yaml b/computer_light.yaml new file mode 100644 index 0000000..b12a3dc --- /dev/null +++ b/computer_light.yaml @@ -0,0 +1,15 @@ +substitutions: + device_id: computer_light + device_name: Computer Light + platform: ESP8266 + board: esp01_1m + ip_address: !secret computer_light_ip + ota_pwd: !secret computer_light_ota_pwd + api_pwd: !secret computer_light_api_pwd + ap_wifi_pwd: !secret computer_light_ap_wifi_pwd + day_brightness: "1" + night_brightness: ".03" + night_auto_off_time: 15min + linked_lights: "" + +<<: !include common/device_tuya_dimmer.yaml diff --git a/family_room_light.yaml b/family_room_light.yaml index 26e8985..ef3f122 100644 --- a/family_room_light.yaml +++ b/family_room_light.yaml @@ -7,23 +7,9 @@ substitutions: ota_pwd: !secret family_room_light_ota_pwd api_pwd: !secret family_room_light_api_pwd ap_wifi_pwd: !secret family_room_light_ap_wifi_pwd + day_brightness: "1" + night_brightness: ".03" + night_auto_off_time: 15min + linked_lights: "" -esphome: - <<: !include common/esphome.yaml - -<<: !include common/common_tuya_dimmer.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 +<<: !include common/device_tuya_dimmer.yaml diff --git a/fire_pit_fountain.yaml b/fire_pit_fountain.yaml index db7acc8..8dff9b9 100644 --- a/fire_pit_fountain.yaml +++ b/fire_pit_fountain.yaml @@ -33,11 +33,13 @@ binary_sensor: inverted: True on_multi_click: - timing: - - ON for at least 5s + - ON for at least 3s + - OFF for at least .1s then: - switch.toggle: fire_pit - timing: - - ON for at most 5s + - ON for at most 3s + - OFF for at least .1s then: - switch.turn_off: fire_pit @@ -52,13 +54,13 @@ switch: name: "Fountain" icon: mdi:fountain pin: D1 - inverted: false + inverted: true - platform: gpio id: fire_pit name: "Fire Pit" icon: mdi:fire pin: D2 - inverted: false + inverted: true text_sensor: - !include common/text_sensor/version.yaml diff --git a/kitchen_table_light.yaml b/kitchen_table_light.yaml index 1a6e762..a3ee3ae 100644 --- a/kitchen_table_light.yaml +++ b/kitchen_table_light.yaml @@ -7,23 +7,9 @@ substitutions: ota_pwd: !secret kitchen_table_light_ota_pwd api_pwd: !secret kitchen_table_light_api_pwd ap_wifi_pwd: !secret kitchen_table_light_ap_wifi_pwd + day_brightness: "1" + night_brightness: ".03" + night_auto_off_time: 15min + linked_lights: "" -esphome: - <<: !include common/esphome.yaml - -<<: !include common/common_tuya_dimmer.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 \ No newline at end of file +<<: !include common/device_tuya_dimmer.yaml diff --git a/office_light.yaml b/office_light.yaml index 427a2f7..d2b55a2 100644 --- a/office_light.yaml +++ b/office_light.yaml @@ -7,23 +7,9 @@ substitutions: ota_pwd: !secret office_light_ota_pwd api_pwd: !secret office_light_api_pwd ap_wifi_pwd: !secret office_light_ap_wifi_pwd + day_brightness: "1" + night_brightness: ".03" + night_auto_off_time: 15min + linked_lights: "" -esphome: - <<: !include common/esphome.yaml - -<<: !include common/common_tuya_dimmer.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 \ No newline at end of file +<<: !include common/device_tuya_dimmer.yaml diff --git a/tuya_light_control.h b/tuya_light_control.h new file mode 100644 index 0000000..477ce9c --- /dev/null +++ b/tuya_light_control.h @@ -0,0 +1,117 @@ +#include "esphome.h" + +class TuyaLightControl : public Component, public CustomAPIDevice { + public: + void setup() 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_tuya_parent(esphome::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; } + void set_day_brightness(float brightness) { this->day_brightness_ = brightness; } + void set_night_brightness(float brightness) { this->night_brightness_ = brightness; } + void set_api_server(api::APIServer *api_server) { this->api_server_ = api_server; }; + void set_linked_lights(const std::string linked_lights); + void set_default_brightness(float brightness); + void on_day_night_changed(std::string state); + + protected: + void handle_datapoint(esphome::tuya::TuyaDatapoint datapoint); + void set_brightness(); + + esphome::tuya::Tuya *parent_; + optional switch_id_{}; + optional dimmer_id_{}; + uint32_t min_value_ = 0; + uint32_t max_value_ = 1000; + float day_brightness_ = 1; + float night_brightness_ = .03; + float default_brightness_ = 1; + api::APIServer *api_server_; + api::HomeAssistantServiceCallAction<> *turn_on_service_; + api::HomeAssistantServiceCallAction<> *turn_off_service_; + bool has_linked_lights_ = false; + bool is_on_; + uint32_t brightness_pct_; +}; + +void TuyaLightControl::setup() { + this->parent_->register_listener(*this->switch_id_, [this](esphome::tuya::TuyaDatapoint datapoint) { + this->handle_datapoint(datapoint); + }); + + this->parent_->register_listener(*this->dimmer_id_, [this](esphome::tuya::TuyaDatapoint datapoint) { + this->handle_datapoint(datapoint); + }); + + register_service(&TuyaLightControl::set_default_brightness, "set_default_brightness", {"brightness"}); + + subscribe_homeassistant_state(&TuyaLightControl::on_day_night_changed, "sensor.day_night"); +} + +void TuyaLightControl::set_linked_lights(const std::string linked_lights) { + if (linked_lights != "") { + this->has_linked_lights_ = true; + + this->turn_on_service_ = new api::HomeAssistantServiceCallAction<>(this->api_server_, false); + this->turn_on_service_->set_service("light.turn_on"); + this->turn_on_service_->add_data("entity_id", linked_lights); + this->turn_on_service_->add_variable("brightness_pct", [=]() { return this->brightness_pct_; }); + this->turn_on_service_->add_data_template("brightness_pct", "{{ brightness_pct }}"); + + this->turn_off_service_ = new api::HomeAssistantServiceCallAction<>(this->api_server_, false); + this->turn_off_service_->set_service("light.turn_off"); + this->turn_off_service_->add_data("entity_id", linked_lights); + } +} + +void TuyaLightControl::set_default_brightness(float brightness) { + this->default_brightness_ = brightness > 1 ? 1 : brightness; + this->set_brightness(); +} + +void TuyaLightControl::on_day_night_changed(std::string state) { + if (state == "Day") { + this->default_brightness_ = this->day_brightness_; + } + else if (state == "Night") + { + this->default_brightness_ = this->night_brightness_; + } + this->set_brightness(); +} + +void TuyaLightControl::handle_datapoint(esphome::tuya::TuyaDatapoint datapoint) { + if (datapoint.id == *this->switch_id_) { + this->is_on_ = datapoint.value_bool; + if (this->has_linked_lights_) { + if (this->is_on_) { + this->turn_on_service_->play(); + } + else { + this->turn_off_service_->play(); + } + } + this->set_brightness(); + } + else if (datapoint.id == *this->dimmer_id_) { + this->brightness_pct_ = static_cast(datapoint.value_uint * 100 / this->max_value_); + if (this->has_linked_lights_) { + if (this->is_on_) { + this->turn_on_service_->play(); + } + } + } +} + +void TuyaLightControl::set_brightness() { + if (!this->is_on_) { + auto brightness_int = static_cast(this->default_brightness_ * this->max_value_); + brightness_int = std::max(brightness_int, this->min_value_); + esphome::tuya::TuyaDatapoint datapoint{}; + datapoint.id = *this->dimmer_id_; + datapoint.type = esphome::tuya::TuyaDatapointType::INTEGER; + datapoint.value_uint = brightness_int; + this->parent_->set_datapoint_value(datapoint); + } +} \ No newline at end of file