Martin Jerry RP-SD01
Description
The Martin Jerry RP-SD01 is a US-style wall dimmer switch based on the ESP32-C3-12F module. It ships with Tasmota preinstalled, but its default configuration can be unintuitive — the up/down rocker only controls dimming, while toggling the relay requires pressing a small Wi-Fi button on the front panel. After attempting to adjust this behavior using Tasmota rules, flashing ESPHome provided a much more intuitive and responsive experience.

This ESPHome configuration enables:
- Full control of the light dimming and relay via the rocker buttons.
- LED indicators to reflect the brightness level.
- Automatic restoration of the previous brightness setting after power loss.
- A default relay state of OFF on power-up.
Flashing Instructions
To open the device:
- Firmly squeeze the dimmer from the sides — the case will flex slightly.
- Gently pry off the back cover, starting from the top. Be careful not to damage the dimmer wheel.

Once opened:
- Disconnect the 4-pin cable — this is where you'll connect your serial adapter for flashing.
- Use a 3.3V USB-to-TTL adapter and connect it to the header as shown below.

To enter flash mode:
- Press and hold both the Up rocker and the Wi-Fi button (bottom left).
- While holding them, press and release the RST button (bottom right).
- Release the buttons — the device is now in flash mode.
You can now flash ESPHome using the ESPHome Dashboard or the CLI.
GPIO Mapping
| Pin | Use |
|---|---|
| 9 | Up Button |
| 21 | Down Button |
| 8 | WiFi Button |
| 5 | PWM |
| 18 | Activity LED (inverted) |
| 2 | Relay and Dim level 1 LED |
| 3 | Dim level 2 LED |
| 4 | Dim level 3 LED |
| 19 | Dim level 4 LED |
| 20 | Dim level 5 LED |
Button Behavior (using advanced example below)
The up/down rocker provides intuitive control of both brightness and relay state:
| Button | Single Press | Hold | Double Click |
|---|---|---|---|
| Up | Turn On | Dim Up | Turn On (100%) |
| Down | Turn Off | Dim Down | Turn On (1%) |
- The Wi-Fi button is still available but not used in the default configuration.
- The LED indicators show brightness level when the relay is ON.
Example Configurations
Basic Example
substitutions:
name: "rp-sd01"
esphome:
name: "${name}"
name_add_mac_suffix: true
esp32:
board: esp32-c3-devkitm-1
variant: esp32c3
framework:
type: esp-idf
logger:
api:
reboot_timeout: 0s
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap: {}
captive_portal:
# Relay control
switch:
- platform: gpio
name: "Relay"
id: relay
pin:
number: 2
inverted: true
restore_mode: ALWAYS_OFF
# PWM dimmer output
output:
- platform: ledc
id: pwm_output
pin: GPIO5
frequency: 1000 Hz
min_power: 0.01
max_power: 0.9
light:
- platform: monochromatic
name: "Dimmer"
id: pwm_light
output: pwm_output
restore_mode: RESTORE_AND_OFF
# Button GPIOs (no logic attached yet)
binary_sensor:
- platform: gpio
id: button_wifi
name: "Wi-Fi Button"
pin: GPIO8
- platform: gpio
id: button_up
name: "Up Button"
pin:
number: GPIO9
mode: INPUT_PULLUP
inverted: true
- platform: gpio
id: button_down
name: "Down Button"
pin:
number: GPIO21
mode: INPUT_PULLUP
inverted: true
Advanced Example which includes
- Dimmer control
- Relay switching
- Brightness feedback via LEDs
- Power-on behavior
- Optional fallback AP + captive portal
substitutions:
name: "rp-sd01"
esphome:
name: "${name}"
name_add_mac_suffix: true
friendly_name: "${friendly_name}"
name_add_mac_suffix: true
platformio_options:
board_build.flash_mode: dio
on_boot:
then:
- script.execute: update_led_bar
esp32:
board: esp32-c3-devkitm-1
variant: esp32c3
framework:
type: esp-idf
version: latest
logger:
api:
reboot_timeout: 0s
ota:
- platform: esphome
wifi:
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
ap: {}
captive_portal:
script:
- id: update_led_bar
mode: restart
then:
- lambda: |-
if (!id(relay1).state) {
id(led2).turn_off();
id(led3).turn_off();
id(led4).turn_off();
id(led5).turn_off();
return;
}
float brightness = id(pwm_light).current_values.get_brightness();
if (brightness > 0.20) id(led2).turn_on(); else id(led2).turn_off();
if (brightness > 0.40) id(led3).turn_on(); else id(led3).turn_off();
if (brightness > 0.60) id(led4).turn_on(); else id(led4).turn_off();
if (brightness > 0.80) id(led5).turn_on(); else id(led5).turn_off();
light:
- platform: binary
name: "Activity LED"
output: led_activity
- platform: binary
name: "Indicator LED 2"
output: led2
- platform: binary
name: "Indicator LED 3"
output: led3
- platform: binary
name: "Indicator LED 4"
output: led4
- platform: binary
name: "Indicator LED 5"
output: led5
- platform: monochromatic
name: "PWM Light"
id: pwm_light
output: pwm_output
restore_mode: RESTORE_AND_OFF
on_turn_on:
then:
- switch.turn_on: relay1
- script.execute: update_led_bar
on_turn_off:
then:
- switch.turn_off: relay1
- script.execute: update_led_bar
switch:
- platform: gpio
name: "Relay"
id: relay1
pin:
number: 2
inverted: true
restore_mode: ALWAYS_OFF
on_turn_off:
then:
- lambda: |-
id(led2).turn_off();
id(led3).turn_off();
id(led4).turn_off();
id(led5).turn_off();
globals:
- id: dimming
type: bool
restore_value: no
initial_value: 'false'
- id: saved_brightness
type: float
restore_value: yes
initial_value: '0.5'
binary_sensor:
- platform: gpio
pin: GPIO8
id: button_wifi
name: "Wi-Fi Button"
- platform: gpio
pin:
number: GPIO9
mode: INPUT_PULLUP
inverted: true
id: button_up
name: "Up Button"
on_multi_click:
- timing:
- ON for at most 350ms
- OFF for at most 250ms
- ON for at most 350ms
then:
- switch.turn_on: relay1
- light.turn_on:
id: pwm_light
brightness: 100%
transition_length: 0ms
- script.execute: update_led_bar
on_click:
min_length: 50ms
max_length: 350ms
then:
- switch.turn_on: relay1
- light.turn_on: pwm_light
on_press:
then:
- lambda: 'id(dimming) = true;'
- delay: 300ms
- if:
condition:
lambda: 'return id(dimming);'
then:
- while:
condition:
lambda: 'return id(dimming);'
then:
- lambda: |-
auto call = id(pwm_light).make_call();
float current = id(pwm_light).current_values.get_brightness();
current += 0.05;
if (current > 1.0) current = 1.0;
call.set_transition_length(100);
call.set_brightness(current);
call.perform();
id(update_led_bar)->execute();
- delay: 200ms
on_release:
then:
- lambda: 'id(dimming) = false;'
- platform: gpio
pin:
number: GPIO21
mode: INPUT_PULLUP
inverted: true
id: button_down
name: "Down Button"
on_multi_click:
- timing:
- ON for at most 350ms
- OFF for at most 250ms
- ON for at most 350ms
then:
- switch.turn_on: relay1
- light.turn_on:
id: pwm_light
brightness: 1%
transition_length: 0ms
- script.execute: update_led_bar
on_click:
min_length: 50ms
max_length: 350ms
then:
- switch.turn_off: relay1
- light.turn_off: pwm_light
on_press:
then:
- lambda: 'id(dimming) = true;'
- delay: 300ms
- if:
condition:
lambda: 'return id(dimming);'
then:
- while:
condition:
lambda: 'return id(dimming);'
then:
- lambda: |-
auto call = id(pwm_light).make_call();
float current = id(pwm_light).current_values.get_brightness();
current -= 0.05;
if (current < 0.01) current = 0.01;
call.set_transition_length(100);
call.set_brightness(current);
call.perform();
id(update_led_bar)->execute();
- delay: 200ms
on_release:
then:
- lambda: 'id(dimming) = false;'
output:
- platform: ledc
id: pwm_output
pin: GPIO5
frequency: 1000 Hz
min_power: 0.01
max_power: 0.9
- platform: gpio
id: led_activity
pin:
number: GPIO18
inverted: true
- platform: gpio
id: led2
pin:
number: GPIO3
inverted: true
- platform: gpio
id: led3
pin:
number: GPIO4
inverted: true
- platform: gpio
id: led4
pin:
number: GPIO19
inverted: true
- platform: gpio
id: led5
pin:
number: GPIO20
inverted: true