Hi all. I have been working on a couple of custom components to support the Gosund SW2 Wifi dimmer. At this point I have it working fine, but I can’t find answers to a couple questions and I think there may be a better way to do what I’m doing here.
The first question is whether or not there’s a way to update the state of a light without calling light.turn_on. The SW2 dimmer has a capacitive touch panel on the front, which dims the light and then informs the ESP8285 module of the new value over the UART interface. My custom UART component reads this value, and then calls light.turn_on with the new value in order to update the state. That causes the light component to tell the custom output component to send a new value to the dimmer, so I used a global variable as a flag to prevent that serial write when the user has changed the output manually at the dimmer.
The second question is regarding the power LED on the dimmer. My custom component is an output instead of a light so I could use the power_supply property of the output to turn on the LED on the along with the light itself. Is there a better way to do that? Should I be writing a custom light component that does all this instead?
Here’s the code for reference (any comments about stupid mistakes are welcome…):
gosund_sw2_output.h
#include "esphome.h"
using namespace esphome;
class GosundSW2Output : public Component, public FloatOutput
{
public:
void setup() override
{
// This will be called by App.setup()
}
void write_state(float state) override
{
uint8_t dimmerVal;
if (id(set_by_touch))
{ /* Set the set_by_touch flag to prevent sending the value back to the hardware */
id(set_by_touch) = false;
return;
}
// Write to HW
if (state > 0.0)
{
dimmerVal = (127.0 * state);
dimmerVal |= 0x80; /* Bit 7 seems to control the relay */
}
else
{
dimmerVal = 0;
}
ESP_LOGD("gosund_sw2_out", "Writing dimmer value %02X", dimmerVal);
Serial.write(dimmerVal);
}
};
gosund_sw2_uart.h
#include "esphome.h"
using namespace esphome;
class GosundSW2Uart : public Component, public UARTDevice {
protected:
light::LightState *dimmer_{nullptr};
public:
GosundSW2Uart(UARTComponent *parent, light::LightState *dimmer)
: UARTDevice(parent), dimmer_(dimmer) {} // Need a pointer to the light component we're controlling
void setup() override {
// nothing to do here
}
void loop() override {
if (Serial.available() >= 5)
{
char buff[5];
while (Serial.available()) Serial.readBytes(buff, 5);
float dimmerVal = buff[1] / 100.0;
id(set_by_touch) = true;
auto call = dimmer_->turn_on();
call.set_brightness(dimmerVal);
call.perform();
ESP_LOGD("gosund_sw2_uart", "Received dimmer value %02X", buff[1]);
}
}
};
dining_room_light.yaml
...
# Disable logging via the UART
logger:
baud_rate: 0
globals:
id: set_by_touch
type: bool
binary_sensor:
- platform: gpio
pin:
number: GPIO4
inverted: true
id: button
on_press:
- light.toggle: dining_room_light
on_click:
min_length: 5s
max_length: 10s
then:
- switch.turn_on: dining_room_light_restart
power_supply:
- id: green_led
pin:
number: GPIO13
inverted: true
enable_time: 0s
keep_on_time: 0s
output:
- platform: custom
type: float
lambda: |-
auto float_out = new GosundSW2Output();
App.register_component(float_out);
return {float_out};
outputs:
- id: dimmer
power_supply: green_led
light:
- platform: monochromatic
name: "Dining Room Light"
id: dining_room_light
output: dimmer
gamma_correct: 1.0
default_transition_length: 0s
custom_component:
- lambda: |-
auto uart_out = new GosundSW2Uart(id(uart_bus), id(dining_room_light));
return {uart_out};
status_led:
pin:
number: GPIO12
inverted: true
...