This ESP32-C6 Relay Module (ESP32-C6_Relay_X1_V1.1) is available from various sellers on the Internet. It can be powered and programmed via its USB-C socket.
It can also be powered from a 7-60V DC supply according to the silk screen printing on the bottom of the module (although I haven't tried this yet).
I haven't yet been able to find a schematic for the module so I am unsure what isolation exists between the 7-60V DC input and the USB-C socket.
I have programmed this using ESPHome. The initial loading of ESPHome (onto the module) was a pain taking several attempts. I'm guessing this may be due to fairly recent support for the C6 version of ESP32 module.
- GPIO2 LED
- GPIO19 Relay
A basic ESPHome sketch to control the relay integrating with Home Assistant subscribing/publishing to MQTT server.
Its function is to control the module's relay using a virtual switch (relay_control) to switch the relay ON immediately. Switching OFF the relay via the virtual switch starts a time (turn_off_delay) which on expiry switches the relay OFF.
The turn_off_delay is programmable from Home Assistant enabling a turn off time between 0 and 300 seconds
This sketch is provided "as-is" as an example of how to control this ESP32-C6 Relay module with integration with MQTT and Home Assistant.
- turn_off_delay (in seconds, range 0 - 300) before switching off the relay after the virtual switch (relay_control) is switched off
- relay_1 switch (GPIO19) controls the relay off/on state
- status_led switch (GPIO2) controls the onboard LED off/on state
- relay_control is a virtual switch. ON turns on the relay immediately, OFF turns off the relay after programmable time (in seconds) turn_off_delay
Having uploaded the following sketch to the module via ESPHome, a quick test is to paste the following into a browser and check that the relay
opens and closes. Replace relay.localdomain with the IP address of your relay module.
- http://relay.localdomain/switch/relay_control/turn_on and check that the relay is switched on (the relay powered LED should be lit) then...
- http://relay.localdomain/switch/relay_control/turn_off checking that the status_led flashes on/off for the turn_off_delay time (in seconds) then the relay should switch off with the status_led also switching off
- http://relay.localdomain/switch/relay_control will return the status of the virtual switch relay_control
The value of the turn_off_delay (0 to 300 seconds) may be set from Home Assistant OR by publishing the time payload (0 to 300) to mqtt-broker topic relay-controller/switch/relay_control/turn_off_delay/set
The turn-off delay can be read by subscribing to the topic relay-controller/switch/relay_control/turn_off_delay/state
The value of the virtual switch relay_control may be set from Home Assistant OR by publishing the payload "ON" or "OFF" to mqtt-broker topic relay-controller/switch/relay_control/set
esphome:
name: "relay"
friendly_name: relay
min_version: 2025.9.0
name_add_mac_suffix: false
on_boot:
priority: -10
then:
# set boot_complete flag true
- lambda: |-
id(boot_complete) = true;
esp32:
variant: esp32c6
framework:
type: esp-idf
logger:
web_server:
port: 80
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: none
#------------------
# Define MQTT broker and mqtt actions
#------------------
mqtt:
broker: mqtt-broker.localdomain
id: mqtt_client
on_message:
# monitor topic for turn_off_delay value in seconds
- topic: relay-controller/switch/relay_control/turn_off_delay/set
then:
- lambda: |-
int d = atoi(x.c_str());
if (d < 0) d = 0;
if (d > 300) d = 300;
id(turn_off_delay) = d;
# publish delay time to topic
- mqtt.publish:
topic: relay-controller/switch/relay_control/turn_off_delay/state
payload: !lambda "return std::to_string(id(turn_off_delay));"
retain: true
# monitor topic for relay_control ON/OFF values
- topic: relay-controller/switch/relay_control/set
then:
- if:
condition:
lambda: 'return x == "ON";'
then:
- switch.turn_on: relay_control
else:
- switch.turn_off: relay_control
api:
ota:
- platform: esphome
# -----------------------
# Define GLOBALS
# -----------------------
globals:
- id: turn_off_delay
type: int
restore_value: true
initial_value: '10'
- id: relay_control_state
type: bool
restore_value: false
initial_value: "false"
- id: boot_complete
type: bool
restore_value: no
initial_value: "false"
# -----------------------
# SCRIPT (NON-BLOCKING)
# -----------------------
script:
- id: delayed_turn_off
mode: restart
then:
- logger.log: "Delay active - blinking LED"
- repeat:
count: !lambda "return id(turn_off_delay) * 2;"
then:
- switch.toggle: status_led
- delay: 500ms
- switch.turn_off: status_led
- switch.turn_off: relay_1
# Force immediate HA update
- lambda: |-
id(relay_control).publish_state(false);
# --------------------------------------------------------------
# Define SWITCHES, relay_1, status_led and virtual relay_control
# --------------------------------------------------------------
switch:
- platform: gpio
id: relay_1
name: "Main Relay (Physical)"
pin: GPIO19
- platform: gpio
id: status_led
name: "Status LED (Delay Active)"
pin: GPIO2
# virtual switch to control the physical relay on GPIO19
- platform: template
id: relay_control
name: "Relay Control"
turn_on_action:
- lambda: "id(relay_control_state) = true;"
- switch.turn_on: relay_1
- lambda: |-
id(relay_control).publish_state(true);
turn_off_action:
- lambda: "id(relay_control_state) = false;"
- if:
condition:
# if boot is complete, then run delayed_turn_off script when relay_control_state virtual switch goes OFF
# this flag stops the script executing at boot time when the virtual switch is set off
lambda: 'return id(boot_complete);'
then:
- script.execute: delayed_turn_off
lambda: |-
return id(relay_control_state);
# -----------------------
# NUMBER entity (HA)
# -----------------------
number:
- platform: template
id: ha_turn_off_delay
name: "Relay Turn-Off Delay"
min_value: 0
max_value: 300
step: 1
unit_of_measurement: s
optimistic: false
lambda: |-
return id(turn_off_delay);
set_action:
- lambda: |-
id(turn_off_delay) = (int)x;
id(ha_turn_off_delay).publish_state(id(turn_off_delay));
- mqtt.publish:
topic: relay-controller/switch/relay_control/turn_off_delay/state
payload: !lambda "return std::to_string(id(turn_off_delay));"
retain: true

