I 1st grabbed a couple of these some months ago - and had limited success as at the time Tuya-convert wasnt working. I got one flashed - but had to do it via Serial and it never worked properly - though I was able to sniff the Serial comms to the MCU that controls the dimmer.
I have just bought a fresh couple to try again. Tuya-convert worked like a dream and I now have a working yaml for ESPHome including dimming via the push button. They are a perfect replacement like this for old X10 LD11 dimmer modules that also use a hard wired momentary switch.
There’s lots of very good info here :-
Original tasmota thread :-
related thread on ESPHome git
My Yaml…
key features…
Exposes the light to HA
Push Button - Single Click = Toggle Light
Push Button - Hold = Cycles through Dim->Bright->Dim etc.
No custom components required
esphome:
name: esp_dim01
platform: ESP8266
board: esp01_1m
wifi:
domain: .local
ssid: "xxxxxx"
password: "xxxxx"
manual_ip:
static_ip: 192.168.1.69
gateway: 192.168.1.254
subnet: 255.255.255.0
# Enable logging
logger:
baud_rate: 0
level: DEBUG
logs:
sensor: ERROR
duty_cycle: ERROR
binary_sensor: ERROR
light: ERROR
# level: VERBOSE
# Enable Home Assistant API
api:
ota:
web_server:
time:
- platform: homeassistant
substitutions:
switch_id: "dim_01"
# globals:
# Dummy light brightness tracker Global
globals:
# Dim direction for Switch 1: 0=Up (brighten) 1=down (dim)
- id: g_direction_1
type: int
restore_value: no
initial_value: "1"
# Counter for time pressed for switch 1
- id: g_counter_1
type: int
restore_value: no
initial_value: "0"
# initial brightness
# Uart definition to talk to MCU dimmer
uart:
tx_pin: GPIO1
rx_pin: GPIO3
stop_bits: 1
baud_rate: 9600
sensor:
- platform: wifi_signal
name: "${switch_id} WiFi Signal Sensor"
update_interval: 60s
# Primary template sensor to track Brightness of light object for "on_value" sending to MCU dimmer
- platform: template
name: "${switch_id} Brightness Sensor"
id: sensor_g_bright
internal: true
update_interval: 20ms
# Ensure on_value only triggered when brightness (0-255) changes
filters:
delta: 0.8
# Read brightness (0 - 1) from light , convert to (0-255) for MCU
lambda: |-
if (id(light_main).remote_values.is_on()) {
return (int(id(light_main).remote_values.get_brightness() * 255));
}
else {
return 0;
}
# On Change send to MCU via UART
on_value:
then:
- uart.write: !lambda |-
return {0xFF, 0x55, (char) id(sensor_g_bright).state, 0x05, 0xDC, 0x0A};
- logger.log:
level: INFO
format: "Sensor Value Change sent to UART %3.1f"
args: ["id(sensor_g_bright).state"]
# Sensor to detect button push (via duty_cycle of 50hz mains signal)
- platform: duty_cycle
pin: GPIO13
internal: true
id: sensor_push_switch
name: "${switch_id} Sensor Push Switch"
update_interval: 20ms
binary_sensor:
#Binary sensor (on/off) which reads duty_cyle sensor readings.
- platform: template
id: switch1
internal: true
name: "${switch_id} Switch Binary Sensor"
# read duty_cycle, convert to on/off
lambda: |-
if (id(sensor_push_switch).state < 95.0) {
return true;
} else {
return false;
}
# Short Click - toggle light only
on_click:
max_length: 300ms
then:
light.toggle: light_main
# Generic On_Press - log press, toggle DIM Direction and reset press interval counter
on_press:
then:
- logger.log: "Switch 1 Press"
- lambda: |-
if (id(g_direction_1) == 0) {
id(g_direction_1) = 1;
} else {
id(g_direction_1) = 0;
}
id(g_counter_1) = 0;
# Dummy light output to allow creation of light object
output:
- platform: esp8266_pwm
pin: GPIO14
frequency: 800 Hz
id: dummy_pwm
# Primary Light object exposed to HA
light:
- platform: monochromatic
default_transition_length: 20ms
name: "${switch_id} Light"
output: dummy_pwm
id: light_main
switch:
- platform: restart
name: "${switch_id} Restart"
# Polling object for long press handling of switch for dim/brighten cycle
interval:
- interval: 20ms
then:
- if:
condition:
binary_sensor.is_on: switch1
then:
# Ramp rate for dim is product of interval (20ms) * number of intervals
# Every 20ms Dimmer is increased/decreased by 2/255
# Lower limit = 10%
# Upper limit = 100%
# 100% - 10% = 90% = 230/255. Therefore 230/2 * 20ms = 2.3 seconds for full range
# At full/min brightness - further 16x20ms = 0.32 Seconds "dwell" by resetting counter to 0
# Initial pause for 16x20ms = 0.32s to allow "on_click" to be discounted 1st
# g_direction_1 = 0 (Increasing brightness)
# g_direction_1 = 1 (decreasing brightness)
# g_counter_1 = Interval pulse counter
lambda: |-
float curr_bright = id(light_main).remote_values.get_brightness();
id(g_counter_1) += 1;
// If max bright, change direction
if (curr_bright >= 0.999 && id(g_direction_1) == 0) {
id(g_direction_1) = 1;
id(g_counter_1) = 0;
}
// If below min_bright, change direction
if (curr_bright < 0.1 && id(g_direction_1) == 1) {
id(g_direction_1) = 0;
id(g_counter_1) = 0;
}
if (id(g_direction_1) == 0 && id(g_counter_1) > 15) {
// Increase Bright
auto call = id(light_main).turn_on();
call.set_brightness(curr_bright + (2.0/255.0));
call.perform();
}
else if(id(g_direction_1) == 1 && id(g_counter_1) > 15) {
// Decrease Bright
auto call = id(light_main).turn_on();
call.set_brightness(curr_bright - (2.0/255.0));
call.perform();
}
They work like a charm. I was able to use the Tuya Convert 2.0 instructions at the top of this thread (blakadder) to flash alternative firmware (I chose tasmota basic) & afterwards flashed ESPHome. Integration into HA is a matter of one click in the Integrations panel. Good luck!
PS Not sure what model you have bought an whether this is compatible with the QS-WIFI-D01-TRIAC…
Those devices are not WiFi…but a proprietary RF on 2.4ghz. You can control them via the Wi-Fi box…but there is no feedback for changes made by the RF controllers.
I have some…they work well. I love the multi function wall switch/controller. I integrated through node red. Someone is working On a proper Native integration. The lack of feedback is starting to niggle compared to better integrated Wi-Fi Ones
Hello recently, I have 1 dimmer of 2 channels specifically the QS-WIFI-D02 model, after using Tuya-Convert I have flash your configuration of QS-WIFI-D01, but it does not work. After searching the network I found a tasmota script that does work for the 2 channels https://gist.github.com/thxthx0/ce7f72ea75ab82be2704c9536ea77bf7
From what I have understood, having 2 channels changes the communication configuration with the MCU.
I’m starting with homeassistant, I still don’t have the necessary knowledge to edit your configuration correctly, could you guide me?
The state testing, and the regulation by prolonged pressing works well, but the on-off by a short press, when pressing CH1 the 2 lights come on and when pressing again they turn off, the same happens when pressing CH2.
I have modified 2 things from the original code, the first one may cause the CH1 light to come on, but the second one is only for the log.
This is awesome, great job. I have been using the sonoff version for this but have all my switches on ESPHome. I had planned to convert but you saved me a lot of work.
Works flawlessly, I only changed minimum bright to 0.067 as some of my led bulbs are already quite bright at 10%
This is an alternative way of doing it without attaching a fake output to a pin. In my case this caused some artifacts. No doubt there’s some better way to do Serial.write
uart_output.h:
#include "esphome.h"
using namespace esphome;
class MyCustomFloatOutput : public Component, public FloatOutput {
public:
void setup() override {
// This will be called by App.setup()
}
void write_state(float state) override {
// state is the amount this output should be on, from 0.0 to 1.0
// we need to convert it to an integer first
float zero = 15.0;
float range = 255.0 - zero;
int value = (state==0.0) ? 0 :int((state * range) +zero);
ESP_LOGD("Uart_output","Uart output setting %d", value);
Serial.write(0xFF);
Serial.write(0x55);
Serial.write((char) int(value));
Serial.write(0x05);
Serial.write(0xDC);
Serial.write(0x0A);
}
};