devices.esphome.io
Sonoff M5 Wall Switch 1/2/3-gang
Sonoff M5 Wall Switch 1/2/3-gang
Device Type: switchElectrical Standard: euBoard: esp32Difficulty: Disassembly required, 3/5
Notes
- the Matter compatible version of this switch (part numbers ending in W, e.g. M5-2C-86W) is locked and cannot be flashed
 - status LED (blue) in left-most button
 - channel LEDs (red) are dimmable (PWM) while relays OFF; 100% bright when ON
 - in 1-gang version LED 1 to/can be activated separately from Relay
 - in 2-gang version LED 2 to/can be activated separately from Relay
 
      
  
        
GPIO Pinout
1-Gang Version
| Pin | Function | 
|---|---|
| GPIO00 | Button 1 | 
| GPIO23 | Relay 1 | 
| GPIO19 | LED 1 | 
| GPIO05 | Status LED | 
| GPIO18 | PWM for LED 1 | 
2-Gang Version
| Pin | Function | 
|---|---|
| GPIO04 | Button 1 | 
| GPIO15 | Button 2 | 
| GPIO23 | Relay 1 / LED 1 | 
| GPIO19 | Relay 2 | 
| GPIO22 | LED 2 | 
| GPIO05 | Status LED | 
| GPIO18 | PWM for LED 1/2 | 
3-Gang Version
| Pin | Function | 
|---|---|
| GPIO04 | Button 1 | 
| GPIO00 | Button 2 | 
| GPIO15 | Button 3 | 
| GPIO23 | Relay 1 / LED 1 | 
| GPIO19 | Relay 2 / LED 2 | 
| GPIO22 | Relay 3 / LED 3 | 
| GPIO05 | Status LED | 
| GPIO18 | PWM for LED 1/2/3 | 
Basic Configuration (2-Gang)
esphome:  name: Sonoff M5 2gang
esp32:  board: esp32dev  framework:    type: arduino
logger:  level: INFO
wifi:  ssid: !secret wifi_ssid  password: !secret wifi_password
api:  encryption:    key: !secret esp_api_key
ota:  password: !secret ota_secret
sensor:    - platform: wifi_signal    name: "RSSI"    id: sensor_rssi    update_interval: 90s    entity_category: "diagnostic"
  - platform: uptime    name: "Uptime"    id: sensor_uptime    update_interval: 300s    entity_category: "diagnostic"
button:  - platform: restart    name: "Restart"    id: button_restart
switch:  - platform: gpio    name: "Left"    pin: GPIO23    id: relay_1
  - platform: gpio    name: "Right"    pin: GPIO19    id: relay_2    on_turn_on:      - output.turn_on: led_2    on_turn_off:      - output.turn_off: led_2
output:  - platform: gpio    id: led_2    pin:      number: GPIO22      inverted: False
  - platform: ledc    id: pwm_output    pin: GPIO18    frequency: 1000 Hz
binary_sensor:  - platform: status    name: "Status"    id: sensor_status
  - platform: template    name: "API connected"    id: sensor_api_connected    internal: True    entity_category: 'diagnostic'    device_class: 'connectivity'    lambda: return global_api_server->is_connected();    on_press:      - light.turn_on: led_status    on_release:      - light.turn_off: led_status
  - platform: gpio    name: "Left"    pin:      number: GPIO04      mode: INPUT_PULLUP      inverted: False    on_press:      - switch.toggle: relay_1
  - platform: gpio    name: "Right"    pin:      number: GPIO15      mode: INPUT_PULLUP      inverted: False    on_press:      - switch.toggle: relay_2
light:  - platform: status_led    name: "LED"    id: led_status    pin:      number: GPIO05      inverted: True    internal: True    restore_mode: ALWAYS_OFF
  - platform: monochromatic    output: pwm_output    name: "LEDs"    restore_mode: RESTORE_DEFAULT_OFF    icon: 'mdi:led-outline'    entity_category: 'config'Advanced Configuration (3-Gang, US Version)
# ESPHome Firmware# Sonoff Switchman M5 3-Gang US# Copyright (c) 2024 Mario Di Vece# License: [MIT](https://opensource.org/license/mit/)# Decription:# Aims to provide a feature-rich, production-ready firmware for this elegant device# - Provides Diagnostic data plus, status LED indicator when not connected to Home Assistant API# - Relays may be configured individually on the UI to work in decoupled mode.#   LEDs are physically connected to the relays, and they can't be individually controlled :(# - Exposes gestures via events:#   esphome.on_gesture { button: (A|B|C), gesture: (click|double_click|hold) }# - Off-state (Background Brightness) of the LEDs is configurable via the UI## For the below example, you need to keep the following entries in your secrets.yaml file:#  - wifi_ssid: "<secret>"#  - wifi_password: "<secret>"#  - ota_password: "<secret>"#  - esp_key: "<32-byte-base-64-secret>"## Example file (sonoff-m5-3g-office-01.yaml)## substitutions:#   usemac: "false"#   friendly: "Sonoff M5 3G - Office Switch - 01"#   uniquename: "sonoff-m5-3g-office-01"## packages:#   base_package:#     url: https://github.com/mariodivece/esphometemplates/#     ref: main#     files: [sonoff-m5-3g-us.yaml]#     refresh: 0d## wifi:#   use_address: "10.16.40.49"
# Basic substitutions (can be safely overriden)substitutions:  usemac: "true"  friendly: "Sonoff Switchman M5 3G US"  uniquename: "switch-m5-3g"  loglevel: INFO  apikey: !secret esp_key  wifi_ssid: !secret wifi_ssid  wifi_password: !secret wifi_password  ota_password: !secret ota_password  device_name: "M53G"  device_make: "Sonoff"  sw_version: "2024.2.4"  package_url: "github://mariodivece/esphometemplates/sonoff-m5-3g-us.yaml@main"
# Define the board for the compileresp32:  board: esp32dev  framework:    type: arduino
# Setup the integration and define some project variablesesphome:  name: "${uniquename}"  friendly_name: "${friendly}"  comment: "${device_name} by ${device_make}"  name_add_mac_suffix: ${usemac}  min_version: "2023.2.0"  project:    name: "${device_make}.${device_name}"    version: "${sw_version}"
# Allow importing this packagedashboard_import:  package_import_url: ${package_url}  import_full_config: false
# Enable logginglogger:  level: "${loglevel}"
# Enable Home Assistant APIapi:  encryption:    key: "${apikey}"
# Enable OTAota:  safe_mode: true  password: !secret ota_password
# Enable WiFi and AP for captive portalwifi:  fast_connect: false  power_save_mode: none  ssid: "${wifi_ssid}"  password: "${wifi_password}"
  # Enable fallback hotspot (captive portal) in case wifi connection fails  # password for hostspot is the same as password for net AP (needs captive_portal)  ap:    ssid: "${uniquename}-setup"    password: "${wifi_password}"
captive_portal:
# Diagnostic output sensorstext_sensor:  - platform: template    name: "Deployment Version"    lambda: return {"${sw_version}"};    icon: "mdi:tag"    entity_category: diagnostic
  - platform: wifi_info    ip_address:      id: ip_address      name: "IP Address"      icon: "mdi:wan"
sensor:  - platform: template    id: internal_temp    name: "Internal Temperature"    icon: "mdi:thermometer"    unit_of_measurement: "°C"    entity_category: diagnostic    disabled_by_default: true    lambda: return temperatureRead();
  - platform: wifi_signal    name: "RSSI"    id: sensor_rssi    update_interval: 90s    entity_category: "diagnostic"
  - platform: uptime    name: "Uptime"    id: sensor_uptime    update_interval: 300s    entity_category: "diagnostic"
# Provide a pre-built button for restarting the devicebutton:  - platform: restart    name: "Restart"    id: button_restart
switch:  # Physical GPIO Relay  - platform: gpio    name: "Relay A"    pin: GPIO23    id: relay_a
  # Physical GPIO Relay  - platform: gpio    name: "Relay B"    pin: GPIO19    id: relay_b
  # Physical GPIO Relay  - platform: gpio    name: "Relay C"    pin: GPIO22    id: relay_c
  # Config-only switch to decouple relay from button  - platform: template    name: "Decoupling - Relay A"    id: relay_a_decoupled    optimistic: true    restore_mode: RESTORE_DEFAULT_OFF    icon: 'mdi:link-box-outline'    entity_category: 'config'
  # Config-only switch to decouple relay from button  - platform: template    name: "Decoupling - Relay B"    id: relay_b_decoupled    optimistic: true    restore_mode: RESTORE_DEFAULT_OFF    icon: 'mdi:link-box-outline'    entity_category: 'config'
  # Config-only switch to decouple relay from button  - platform: template    name: "Decoupling - Relay C"    id: relay_c_decoupled    optimistic: true    restore_mode: RESTORE_DEFAULT_OFF    icon: 'mdi:link-box-outline'    entity_category: 'config'
output:  # Physical GPIO PWM for off-state background brightness  # This pin controls the background brightness for all LEDs  # physically attached to the relays  - platform: ledc    id: pwm_output    pin: GPIO18    frequency: 1000 Hz
binary_sensor:  # Diagnostic sensor for connection  - platform: status    name: "Status"    id: sensor_status
  # Make the status LED blink when not connected/trying to connect  - platform: template    name: "API connected"    id: sensor_api_connected    internal: true    entity_category: 'diagnostic'    device_class: 'connectivity'    lambda: return global_api_server->is_connected();    on_press:      - light.turn_off: led_status    on_release:      - light.turn_on: led_status
  # Physical Button A  - platform: gpio    name: "Button A"    id: button_a    pin:      number: GPIO04      mode: INPUT_PULLUP      inverted: true
    filters:      - delayed_on: 10ms
    on_press:      - if:          condition:            switch.is_off: relay_a_decoupled          then:            - switch.toggle: relay_a
    on_multi_click:      # single click detection      - timing:        - ON for at most 900ms        - OFF for at least 600ms        then:          - homeassistant.event:              event: esphome.on_gesture              data:                button: "A"                gesture: "single_click"
      # double click detection      - timing:          - ON for at most 500ms          - OFF for at most 400ms          - ON for at most 500ms          - OFF for at least 250ms        then:          - homeassistant.event:              event: esphome.on_gesture              data:                button: "A"                gesture: "double_click"
      # hold detection      - timing:          - ON for at least 1s        then:          - while:              condition:                binary_sensor.is_on: button_a              then:                - light.toggle: led_status                - homeassistant.event:                    event: esphome.on_gesture                    data:                      button: "A"                      gesture: "button_hold"                - delay: 100ms          - light.turn_off: led_status
  - platform: gpio    name: "Button B"    id: button_b    pin:      number: GPIO00      mode: INPUT_PULLUP      inverted: true
    filters:      - delayed_on: 10ms
    on_press:      - if:          condition:            switch.is_off: relay_b_decoupled          then:            - switch.toggle: relay_b
    on_multi_click:      # single click detection      - timing:        - ON for at most 900ms        - OFF for at least 600ms        then:          - homeassistant.event:              event: esphome.on_gesture              data:                button: "B"                gesture: "single_click"
      # double click detection      - timing:          - ON for at most 500ms          - OFF for at most 400ms          - ON for at most 500ms          - OFF for at least 250ms        then:          - homeassistant.event:              event: esphome.on_gesture              data:                button: "B"                gesture: "double_click"
      # hold detection      - timing:          - ON for at least 1s        then:          - while:              condition:                binary_sensor.is_on: button_b              then:                - light.toggle: led_status                - homeassistant.event:                    event: esphome.on_gesture                    data:                      button: "B"                      gesture: "button_hold"                - delay: 100ms          - light.turn_off: led_status
  - platform: gpio    name: "Button C"    id: button_c    pin:      number: GPIO15      mode: INPUT_PULLUP      inverted: true
    filters:      - delayed_on: 10ms
    on_press:      - if:          condition:            switch.is_off: relay_c_decoupled          then:            - switch.toggle: relay_c
    on_multi_click:      # single click detection      - timing:        - ON for at most 900ms        - OFF for at least 600ms        then:          - homeassistant.event:              event: esphome.on_gesture              data:                button: "C"                gesture: "single_click"
      # double click detection      - timing:          - ON for at most 500ms          - OFF for at most 400ms          - ON for at most 500ms          - OFF for at least 250ms        then:          - homeassistant.event:              event: esphome.on_gesture              data:                button: "C"                gesture: "double_click"
      # hold detection      - timing:          - ON for at least 1s        then:          - while:              condition:                binary_sensor.is_on: button_c              then:                - light.toggle: led_status                - homeassistant.event:                    event: esphome.on_gesture                    data:                      button: "C"                      gesture: "button_hold"                - delay: 100ms          - light.turn_off: led_status
light:  # Physical pin to the connection status LED  # We don't expose this to the HA UI (internal)  - platform: status_led    name: "LED"    id: led_status    pin:      number: GPIO05      inverted: true    internal: true    restore_mode: RESTORE_DEFAULT_ON
  # HA UI connection to the background brightness (PWM) pin  - platform: monochromatic    output: pwm_output    name: "Background Brightness"    restore_mode: RESTORE_DEFAULT_OFF    icon: 'mdi:led-outline'    entity_category: 'config'