Flashing Sonoff POW R3 to ESPHome

Good morning. I couldn’t find any information on how to hack a Sonoff POW R3 to make it an ESPHome device. Can someone please help me?
Thank you

Have you had any joy with this? I have a POW R3 on order and also want to intigrated with HA using ESPHome (I am migrating devices to ESPHome to avoid having to run a seperate MQTT server).

Almost… for some reason the switch want work, and the V showing 15v - but its a start, to get you online.

esphome:
name: sonoffvpkids

esp32:
board: nodemcu-32s

Enable logging

logger:

wifi:
ssid: xxxxx
password: xxxxx

Optional manual IP

manual_ip:
static_ip: x.x.x.x
gateway: x.x.x.x
subnet: 255.255.255.0
dns1: x.x.x.x

Enable fallback hotspot (captive portal) in case wifi connection fails

ap:
ssid: “sonoffvpkids Fallback Hotspot”
password: “xxxxxxxxxxxxx”

captive_portal:

Enable Home Assistant API

api:
password: “xxxxx”

ota:
password: “xxxxx”

uart:
rx_pin: GPIO16
baud_rate: 4800

sensor:

  • platform: cse7766
    update_interval: 2s
    current:
    name: sonoffvpkids Current
    id: a_sensor
    voltage:
    name: sonoffvpkids Voltage
    id: v_sensor
    power:
    name: sonoffvpkids Power
    id: w_sensor
    on_value_range:
    - above: 4.0
    then:
    - light.turn_on: switch_led
    - below: 3.0
    then:
    - light.turn_off: switch_led
    energy:
    name: sonoffvpkids Energy
    id: wh_sensor

output:

  • platform: ledc
    id: led
    pin:
    number: GPIO18
    inverted: True

light:

  • platform: monochromatic
    id: switch_led
    output: led
    internal: True
  • platform: status_led
    id: wifi_status_led
    internal: True
    pin:
    number: GPIO05
    inverted: True

switch:

  • platform: template
    name: sonoffvpkids sw
    optimistic: true
    id: relay_1
    lambda: |-
    if (isnan(id(w_sensor).state)) {
    return {};
    } else if (id(w_sensor).state > 4) {
    // Running
    return true;
    } else {
    // Not running
    return false;
    }
    turn_off_action:
    • switch.turn_on: relay_off
      turn_on_action:
    • switch.turn_on: relay_on
  • platform: gpio
    restore_mode: ALWAYS_OFF
    internal: true
    id: relay_off
    pin: GPIO04
    on_turn_on:
    • switch.turn_on: relay_off
    • delay: 500ms
    • switch.turn_off: relay_off # bi-stable relay so no need to keep on.
    • light.turn_off: switch_led
      interlock: [relay_on]
  • platform: gpio
    restore_mode: ALWAYS_OFF
    internal: true
    id: relay_on
    pin: GPIO02
    on_turn_on:
    • switch.turn_on: relay_on
    • delay: 500ms
    • switch.turn_off: relay_on # bi-stable relay so no need to keep on.
    • light.turn_on: switch_led
      interlock: [relay_off]
  • platform: restart
    name: sonoffvpkids Restart
2 Likes

Not sure if this is helpful, but I recently set up a Sonoff POW R3 with ESPHome for use with a hot water tank immersion heater.

Took various bits of code from various sources locally and online. In my case, I’ve added 3 Dallas temperature sensors connecting to GPIO4 so I can monitor the tank temperature.

I’m using this to utilise spare solar power after the car is charged. (better than selling to the grid for 4p a kWh :stuck_out_tongue: )

I initially used GPIO15 for the temperature sensors but that stopped everything from working.

substitutions:
  esphome_name: hotwatersonoff
  esphome_friendly_name: Hot Water Sonoff

esphome:
  name: ${esphome_name}
  friendly_name: Hot Water Heater Sonoff

esp8266:
  board: esp8285

# Enable logging
logger:
  baud_rate: 0

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxx"

ota:
  password: "xxxxxxxxx"

wifi:
  output_power: 18db
  power_save_mode: light
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Hot-Water-Heater-Sonoff"
    password: "xxxxxxxxx"

captive_portal:

dallas:
  - pin: GPIO4

# Enable web server
web_server:
  port: 80

time:
  - platform: homeassistant
    timezone: Europe/London

#GPIO0 Button (inverted)
#GPIO12 Relay and Red LED
#GPIO13 Blue LED (inverted)


uart:
  rx_pin: RX
  baud_rate: 4800

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO0
      mode: INPUT_PULLUP
      inverted: True
    name: "${esphome_friendly_name} Button"
    on_press:
      - switch.toggle: fakebutton

switch:
  - platform: template
    name: "Hot Water Relay"
    optimistic: true
    id: fakebutton
    turn_on_action:
    - switch.turn_on: relay
    - light.turn_on: led
    turn_off_action:
    - switch.turn_off: relay
    - light.turn_off: led
  - platform: gpio
    id: relay
    inverted: yes
    pin: GPIO12
    restore_mode: RESTORE_DEFAULT_ON

output:
  - platform: esp8266_pwm
    id: pow_blue_led
    pin:
      number: GPIO13
      inverted: True

light:
  - platform: monochromatic
    name: "${esphome_friendly_name} Blue LED"
    output: pow_blue_led
    id: led
    internal: true

sensor:
  - platform: wifi_signal
    name: "${esphome_friendly_name} WiFi Signal"
    update_interval: 60s
  - platform: uptime
    name: "${esphome_friendly_name} Uptime"
  - platform: cse7766
    update_interval: 2s
    current:
      name: "${esphome_friendly_name} Current"
    voltage:
      name: "${esphome_friendly_name} Voltage"
    power:
      name: "${esphome_friendly_name} Power"
    energy:
      name: "${esphome_friendly_name} Energy"
  - platform: dallas
    address: 0xb60000001284c428
    name: "${esphome_friendly_name} Temperature Sensor 1"
    id: temp_1
    icon: "mdi:water-thermometer"
    filters:
      - filter_out: nan
  - platform: dallas
    address: 0x4f00000012821c28
    name: "${esphome_friendly_name} Temperature Sensor 2"
    id: temp_2
    icon: "mdi:water-thermometer"
    filters:
      - filter_out: nan
  - platform: dallas
    address: 0xb10000001483f228
    name: "${esphome_friendly_name} Temperature Sensor 3"
    id: temp_3
    icon: "mdi:water-thermometer"
    filters:
      - filter_out: nan
  - platform: template
    name: "{esphome_friendly_name} Average Tank Temperature"
    icon: "mdi:water-thermometer"
    unit_of_measurement: "°C"
    lambda: |-
      return (id(temp_1).state + id(temp_2).state + id(temp_3).state)/3;
    update_interval: 60s
  - platform: template
    name: "{esphome_friendly_name} Max Tank Temperature"
    icon: "mdi:water-thermometer"
    unit_of_measurement: "°C"
    lambda: |-
      return ((id(temp_1).state > id(temp_2).state) ? ((id(temp_1).state > id(temp_3).state) ? id(temp_1).state : id(temp_3).state) : (id(temp_2).state > id(temp_3).state) ? id(temp_2).state : id(temp_3).state);
    update_interval: 60s
  - platform: template
    name: "{esphome_friendly_name} Min Tank Temperature"
    icon: "mdi:water-thermometer"
    unit_of_measurement: "°C"
    lambda: |-
      return ((id(temp_1).state < id(temp_2).state) ? ((id(temp_1).state < id(temp_3).state) ? id(temp_1).state : id(temp_3).state) : (id(temp_2).state < id(temp_3).state) ? id(temp_2).state : id(temp_3).state);
    update_interval: 60s
    

Hi Rich/Thansen1980 , can any of you post the clean configuration that will work with pow r3 (25A) for esp home

Thank you so much :heartbeat:

+1, any clean fully working config?

define “clean”, pls :rofl:

This one should be undaerstandable, tho it has some extra lambdas, but all are explainded with comments. Working fawlessly here with my Sonoff pow origin (POWR316). The 3 dashes at the beginning are to make things easier for the yaml parser, but it’s not mandatory.

---
##### information #####
# model: Sonoff pow origin (POWR316)
# explication: https://templates.blakadder.com/sonoff_POWR316.html
# buy:  https://www.aliexpress.com/wholesale?SearchText=sonoff+powr316

# GPIO Pinout
# ---------------------------------------
# | Pin    | Component                  |
# |========|============================|
# | GPIO0  | Button                     |
# |--------|----------------------------|
# | GPIO05 | Status LED (inverted)      |
# |--------|----------------------------|
# | GPIO13 | Relay                      |
# |--------|----------------------------|
# | GPIO16 | CSE7766 Rx                 |
# |--------|----------------------------|
# | GPIO18 | LED (inverted)             |
# ---------------------------------------

# As the communication with the CSE7766 is done using UART, you need to have an UART bus in your configuration with the rx_pin connected to the CSE7766.
# Additionally, you need to set the baud rate to 4800.

##### basic configs #####

# set up variables
substitutions:
  my_name: 'POW316-WM'
  my_device: pow316-wm
  my_reboot_timeout: 30min
  my_update_interval: 12sec
  my_static_ip: 10.11.12.13

# define core configs
esphome:
  name: ${my_device}
  friendly_name: ${my_name}
  area: 'Waschküche'
  comment: I usually comment the last change here
  on_boot:
    priority: -100
    then:
      - switch.turn_on: relay

esp32:
  board: esp32dev

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true
  reboot_timeout: ${my_reboot_timeout}
  manual_ip:
    static_ip: ${my_static_ip}
    gateway: 192.168.1.1
    subnet: 255.255.255.0
    dns1: 192.168.1.1
    dns2: 9.9.9.9
  ap:
    # after connecting to it, navigate to http://192.168.4.1/
    ssid: '${my_name} AP'
    password: !secret ap_wifi_password
    ap_timeout: 1min

captive_portal:

api:
  reboot_timeout: ${my_reboot_timeout}
  encryption:
    key: !secret native_api_key

ota:
  safe_mode: true
  password: !secret ota_password

logger:
  level: DEBUG
  # Disable logging to serial
  baud_rate: 0

web_server:
  port: 80
  auth:
    username: !secret web_srv_user
    password: !secret web_srv_pswd

time:
  - platform: homeassistant
    id: homeassistant_time

    on_time:
        # device restart (5 minutes after dhcp router and WiFi APs reboot)
      - days_of_week: THU
        hours: 4
        minutes: 35
        seconds: 0
        then:
          - button.press: reboot
        
        # shift values sortly before midnight reset
      - hours: 23
        minutes: 59
        seconds: 59
        then:
          - sensor.template.publish:
              id: power_today_minus_3
              state: !lambda return id(power_today_minus_2).state;
          - sensor.template.publish:
              id: power_today_minus_2
              state: !lambda return id(power_today_minus_1).state;
          - sensor.template.publish:
              id: power_today_minus_1
              state: !lambda return id(power_today).state;

#### specific configs #####
uart:
  rx_pin: GPIO16
  baud_rate: 4800
  data_bits: 8
  parity: EVEN
  stop_bits: 1

binary_sensor:
  # define button on device and it's press action
  - platform: gpio
    name: '${my_name} Taster'
    pin:
      number: GPIO0
      mode:
        input: true
        pullup: true
    filters:
      # eliminate bouncing noise
      - delayed_on_off: 25ms
    on_press:
      then:
        - switch.toggle: relay

  # show as active when power reading is above 0W, idle when it's 0W. Both if state persists for at least 2 update cicles.
  - platform: template
    name: '${my_name} aktivity'
    device_class: power
    filters:
      # eliminate bouncing noise
      - delayed_on_off: 24s
    lambda: 'if (id(power).state>(0)) return true; else return false;'

  - !include common/binary_sensors/status.yaml

switch:
  - platform: gpio
    name: '${my_name} Relais'
    icon: 'mdi:lightning-bolt-circle'
    id: relay
    pin: GPIO13
    restore_mode: RESTORE_DEFAULT_ON
    on_turn_on:
      light.turn_on: led
    on_turn_off:
      light.turn_off: led

button:
  - !include common/buttons/restart_button.yaml
  - !include common/buttons/restart_safe_mode.yaml

sensor:
  # energy measurement
  - platform: cse7766

    # voltage sensor
    voltage:
      name: '${my_name} voltage'
      id: voltage
      unit_of_measurement: 'V'
      accuracy_decimals: 1
      device_class: voltage
      state_class: measurement
      icon: 'mdi:alpha-v'
      filters:
        # agreggate values of polls
        - throttle_average: ${my_update_interval}
        # map from sensor -> measured value
        - calibrate_linear:
            - 0.647 -> 0.0
            - 221.1-> 219
            - 230 -> 226.5
        # set not a number and values below 5V to zero or state value in V
        - lambda: 'if (isnan(x)) return(0); else if (x<(5)) return(0); else return(x);'
        # don't report minor changes from previous value
        - delta: 1

    # current sensor
    current:
      name: '${my_name} current'
      id: current
      unit_of_measurement: 'A'
      accuracy_decimals: 3
      state_class: measurement
      icon: 'mdi:alpha-a'
      filters:
        # agreggate values of polls
        - throttle_average: ${my_update_interval}
        # map from sensor -> measured value
        - calibrate_linear:
           - 0.0 -> 0.004
           - 3.374 -> 3.37
           - 4.846 -> 4.864
           - 8.045 -> 8.097
        # set not a number and low values plus own consumption to zero or correct higher values with own consumption and state value
        - lambda: 'if (isnan(x)) return(0); else if (x<(0.025 + 0.008)) return(0); else return(x - 0.008);'
        # don't report minor changes from previous value
        - delta: 0.02

    # power sensor
    power:
      name: '${my_name} power'
      id: power
      device_class: power
      state_class: measurement
      unit_of_measurement: W
      accuracy_decimals: 1
      icon: 'mdi:alpha-w'
      filters:
        # agreggate values of polls
        - throttle_average: ${my_update_interval}
        # map from sensor -> measured value
        - calibrate_linear:
           - 0.0 -> 1.2
           - 768.4 -> 771.7
           - 1110.3 -> 1109
           - 1807.4 -> 1802
        # set not a number and values below 5W plus own consumption to zero or correct higher values with own consumption and state value
        - lambda: 'if (isnan(x)) return(0); else if (x<(5 + 1.2)) return(0); else return(x - 1.2);'
        # don't report minor changes from previous value
        - delta: 1

    # energy sensor
    energy:
      name: '${my_name} energy'
      id: energy
      device_class: energy
      state_class: measurement
      accuracy_decimals: 1
      unit_of_measurement: 'Wh'
      filters:
        # agreggate values of polls
        - throttle_average: ${my_update_interval}        
        # set not a number to zero or state value
        - lambda: 'if (isnan(x)) return(0); else return(x);'
        # don't report minor changes from previous value
        - delta: 0.5
  
  # power factor
  - platform: template
    update_interval: ${my_update_interval}
    name: '${my_name} power factor'
    unit_of_measurement: '%'
    device_class: power_factor
    state_class: measurement
    id: power_factor
    accuracy_decimals: 1
    icon: 'mdi:decagram-outline'
    lambda: 'return id(power).state / id(voltage).state / id(current).state;'
    filters:
      # set not a number to zero or state value
      - lambda: 'if (isnan(x)) return(0); else return(x*100);'
      # don't report changes from previous value lower than 1%
      - delta: 1

  # total daily energy 
  - platform: total_daily_energy
    name: '${my_name} total daily energy'
    id: power_today
    power_id: power
    accuracy_decimals: 1
    unit_of_measurement: 'Wh'
    state_class: total_increasing
    device_class: energy    
    icon: 'mdi:numeric-0-box-outline'
    filters:
      # set not a number to zero or state value
      - lambda: 'if (isnan(x)) return(0); else return(x);'

  # shifting total daily energy short before reset at midnight
  - platform: template
    name: '${my_name} total energy today -1'
    id: power_today_minus_1
    accuracy_decimals: 1
    unit_of_measurement: 'Wh'
    icon: 'mdi:numeric-1-box-outline'
    filters:
      # set not a number to zero or state value
      - lambda: 'if (isnan(x)) return(0); else return(x);'

  - platform: template
    name: '${my_name} total energy today -2'
    id: power_today_minus_2
    unit_of_measurement: 'Wh'
    accuracy_decimals: 1
    icon: 'mdi:numeric-2-box-outline'
    filters:
      # set not a number to zero or state value
      - lambda: 'if (isnan(x)) return(0); else return(x);'

  - platform: template
    name: '${my_name} total energy today -3'
    id: power_today_minus_3
    accuracy_decimals: 1
    unit_of_measurement: 'Wh'
    icon: 'mdi:numeric-3-box-outline'
    filters:
      # delete not a number or state value
      - lambda: 'if (isnan(x)) return(0); else return(x);'

  - platform: uptime
    id: uptime_sensor
    internal: true
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: uptime_human
            state: !lambda |-
              int seconds = round(id(uptime_sensor).raw_state);
              int days = seconds / (24 * 3600);
              seconds = seconds % (24 * 3600);
              int hours = seconds / 3600;
              seconds = seconds % 3600;
              int minutes = seconds /  60;
              seconds = seconds % 60;
              return (
                (days ? to_string(days) + "d " : "") +
                (hours ? to_string(hours) + "h " : "") +
                (minutes ? to_string(minutes) + "m " : "") +
                (to_string(seconds) + "s")
              ).c_str();

  # WiFi rssi in dBs
  - platform: wifi_signal
    id: wifi_rssi_dbs
    internal: true
    update_interval: 5min
    filters:
      # set not a number to zero or state value
      - lambda: 'if (isnan(x)) return(0); else return(x);'

  # WiFi rssi in percents
  - platform: template
    name: '${my_name} WiFi Signalstärke'
    id: wifi_rssi
    update_interval: 5min
    unit_of_measurement: '%'
    accuracy_decimals: 0
    icon: mdi:wifi-strength-2
    lambda: |-
      if (id(wifi_rssi_dbs).state < -92.0)
        return 1.0;
      if (id(wifi_rssi_dbs).state > -21.0)
        return 100.0;
      else
        return round(( -0.0154 * id(wifi_rssi_dbs).state * id(wifi_rssi_dbs).state ) - ( 0.3794 * id(wifi_rssi_dbs).state ) + 98.182 );
    filters:
      # set not a number to zero or state value
      - lambda: 'if (isnan(x)) return(0); else return(x);'
      # do not report changes lower than +-2%
      - delta: 2.0

output:
  - platform: ledc
    pin: GPIO18
    id: onboard_led
    inverted: true
    max_power: 0.66

light:
  - platform: monochromatic
    output: onboard_led
    id: led
    internal: true

text_sensor:
  - platform: wifi_info
    ip_address:
      name: '${my_name} IP'
      id: espip
      icon: mdi:ip-network-outline
    ssid:
      name: '${my_name} SSID'
      id: espssid
      icon: mdi:access-point-network
    bssid:
      name: '${my_name} BSSID'
      id: espbssid
      icon: mdi:plus-network-outline
  - platform: template
    name: '${my_name} MAC'
    id: espmac
    icon: mdi:minus-network-outline
    update_interval: 15min
    lambda: |-
      return {WiFi.macAddress().c_str()};
  - platform: version
    name: '${my_name} ESPHome Version'
  - platform: template
    name: '${my_name} Uptime'
    id: uptime_human
    icon: mdi:clock-start

status_led:
  # use blue LED as status indicator
  pin:
    number: GPIO05
    inverted: true

Is it possible to output to the serial port on the board? I need some help with the UART I think,