DUALR3 (Sonoff) Current Based Cover Control - Sensor Timing question

Hello everyone, this is my firts post here but I’ve read a lot while configuring lots of devices in HA. Sorry for my bad english.

I’m trying to use some Sonoff DUALR3 powering motor-blinds with mechanical endstops.

Following some guides on the web (GPIO pinout, BL0939 integration, switch input integration, lambda controls for testing with on-board button and interlock function) I managed to make it work, but with some questions about how it does:

To have the sensor reading fast enough to detect endstops i have to set it to 500ms.

This is causing 4 entries per seconds on the logs which doesn’t sound really efficient.

I see that also wiki example (Current Based Cover - ESPHome) is using this method.

As I don’t need the current to be measured when relays are not triggered, is there a way to force the sensor update at 500ms (or less) when at least 1 relay is on and disable readings when both relays are off?

Here part of the config:

Sensor set-up:

sensor:
  - platform: bl0939
    update_interval: 500ms
    current_1:
      id: open_current
    current_2:
      id: close_current

Cover set-up:

cover:
  - platform: current_based
    name: "$ldn"
    device_class: blind
    id: "$coverid"

    open_sensor: open_current
    open_moving_current_threshold: 2.1
    open_obstacle_current_threshold: 2.5
    open_duration: 35s
    open_action:
      - switch.turn_on: open_cover

    close_sensor: close_current
    close_moving_current_threshold: 2.1
    close_obstacle_current_threshold: 2.5
    close_duration: 35s
    close_action:
      - switch.turn_on: close_cover

    stop_action:
      - switch.turn_off: close_cover
      - switch.turn_off: open_cover

    obstacle_rollback: 2%
    start_sensing_delay: 1.0s
    max_duration: 37s

Current measurement is “internal” so value doesn’t transfer to HA and occupy history space, if that’s what you mean. But in any case measurement are recorded into history only when changed, not at every measurement. So when cover current is zero that value is recorded only once, not every 0.5 s. - until it changes, of course.

Thank you for your reply,
I know that as I disabled sensor names on purpose to remove them from Home Assistant.
I was thinking about resource waste due to continuos sensor monitorin, am I wrong? Is this the best way to make it work?

No, in esphome yaml you set current sensors as “internal: true”. That way they won’t show in HA:
sensor. In below example all sensors are internal - i think that “name” is not needed either… names are just “leftovers” from my testing, when i temporarily created voltage and current sensors available in HA for monitoring…

  - platform: ade7953
    irq_pin: GPIO16
    voltage:
      name: Shelly 2.5 Mains Voltage
      internal: true
      filters:
        - throttle: 5s
    current_a:
      name: Shelly 2.5 Open Current
      id: open_current
      internal: true
    current_b:
      name: Shelly 2.5 Close Current
      id: close_current
      internal: true
    update_interval: 0.5s

I didn’t know about the internal: true option. That’s useful!

But, my question was about the ESP32 device, not the HA instance (which is on a server and doesn’t have performance issues).

Also, is there a way to log button press, but not sensor readings? Do I have to specify platforms?

You said for both current sensor that " This is causing 4 entries per seconds on the logs which doesn’t sound really efficient." internal is the solution for this.

Regarding log: there are a couple of options, see logger component.
This example sets all logs to “verbose”, only switch components to “info”:

logger:
  level: verbose
  logs:
    switch: info

I guess that you could try:

logger:
  logs:
    sensor: none

This way sensors won’t be logged.
But i’m not sure what you’ll gain with it… it’s just an internal esphome’s logger, which is constantly overwritten.

1 Like

Could you please pass me the code for esphome with which you managed to get the current and voltage measurements?

So if anyone can use it, here is a full code example for a current based cover control: Sonoff Dual R3 v2.x

# Pin	Function
# GPIO13	Status LED (blue/inverted)
# GPIO00	Push Button (inverted)
# GPIO27	Relay 1 / LED 1 (red)
# GPIO14	Relay 2 / LED 2 (red)
# GPIO32	Switch 1 (inverted)
# GPIO33	Switch 2 (inverted)
# GPIO25	power sensor UART Tx
# GPIO26	power sensor UART Rx

#####
substitutions:
  name: esphome-web-5375d4
  friendly_name: Wohnzimmer Rolladen
  devicename: wz-rolladen
  fritz: wohnzimmer-rolladen-sonoffdualr3-esphome
  open_duration: 45s
  close_duration: 45s

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  name_add_mac_suffix: false
  area: Wohnzimmer 
  project:
    name: esphome.web
    version: '1.0'

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  level: DEBUG
  logs:
    sensor: WARN

# Enable Home Assistant API
api:

# Allow Over-The-Air updates
ota:
    password: !secret esphome_api_password

wifi:
    ssid: !secret wifi_iot_ssid
    password: !secret wifi_iot_password
    use_address: ${fritz}.fritz.box
    # Enable fallback hotspot (captive portal) in case wifi connection fails
    ap:
      ssid: "${devicename} Fallback Hotspot"
      password: !secret wifi_iot_password  

# In combination with the `ap` this allows the user
# to provision wifi credentials to the device via WiFi AP.
captive_portal:

# To have a "next url" for improv serial
web_server: ## can use when OTA does not work
  port: 80

# Sync time with Home Assistant
time:
  - platform: homeassistant
    id: homeassistant_time

uart:
  tx_pin: GPIO25
  rx_pin: GPIO26
  baud_rate: 4800
  parity: NONE
  stop_bits: 2

sensor:  
  - platform: bl0939
    update_interval: 500ms
    voltage:
      name: 'Voltage'
      internal: true
      filters:
        - throttle: 5s
    current_1:
      name: 'Current 1'
      id: open_current_sensor
      disabled_by_default: True
    current_2:
      name: 'Current 2'
      id: close_current_sensor
      disabled_by_default: True
    active_power_1:
      name: 'Power 1'
      filters:
        - throttle: 5s
    active_power_2:
      name: 'Power 2'
      filters:
        - throttle: 5s
    energy_1:
      name: 'Energy 1'
      filters:
        - throttle: 15s
    energy_2:
      name: 'Energy 2'
      filters:
        - throttle: 15s
    energy_total:
      name: 'Energy Total'
      filters:
        - throttle: 15s
 
  - 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

light:
  - platform: status_led
    name: "LED"
    id: led_status
    pin:
      number: GPIO13
      inverted: True
    internal: True

switch:
  - platform: gpio
    pin: GPIO27
    name: "Relay #1"
    internal: true
    id: relay1
    interlock_wait_time: 350ms
    interlock: &interlock_group [relay1, relay2]
    restore_mode: always off

  - platform: gpio
    pin: GPIO14
    name: "Relay #2"
    internal: true
    id: relay2
    interlock_wait_time: 350ms
    interlock: *interlock_group
    restore_mode: always off

binary_sensor:
  - platform: gpio
    name: "Öffnen-2"
    id: switch2
#    internal: true
    pin:
      number: GPIO32
      mode:
        input: True
        pullup: True
      inverted: True
    filters:
      - delayed_on_off: 50ms
    on_press:
      then:
        - lambda: |
            if (id(rolladen).current_operation == COVER_OPERATION_IDLE) {
              // Cover is idle, check current state and open cover.
              id(rolladen).make_call().set_command_open().perform();
            } 
            else {
              // Cover is opening/closing. Stop it.
              id(rolladen).make_call().set_command_stop().perform();
            }
  #  on_press:
  #    - switch.turn_on: relay_1
  #  on_release:
  #    - switch.turn_off: relay_1

  - platform: gpio
    name: "Schließen-1"
    id: switch1
#    internal: true
    pin:
      number: GPIO33
      mode:
        input: True
        pullup: True
      inverted: True
    filters:
      - delayed_on_off: 50ms
    on_press:
      then:
        - lambda: |
            if (id(rolladen).current_operation == COVER_OPERATION_IDLE) {
              // Cover is idle, check current state and close cover.
              id(rolladen).make_call().set_command_close().perform();
            } 
            else {
              // Cover is opening/closing. Stop it.
              id(rolladen).make_call().set_command_stop().perform();
            }
  #  on_press:
  #    - switch.turn_on: relay_2
  #  on_release:
  #    - switch.turn_off: relay_2


  - platform: gpio
    name: "Button"
    id: sensor_button
    pin:
      number: GPIO00
      mode:
        input: True
        pullup: True
      inverted: True
    disabled_by_default: True
    icon: 'mdi:radiobox-blank'
    filters:
      - delayed_on: 50ms
    on_press:
      - switch.toggle: relay1

cover:
  - platform: current_based
    name: "${friendly_name}"
    id: rolladen
    start_sensing_delay: 800ms
    open_sensor: open_current_sensor
    open_moving_current_threshold: 0.2
    open_obstacle_current_threshold: 2.0
    open_action:
      - switch.turn_on: relay1
    open_duration: ${open_duration}

    close_sensor: close_current_sensor
    close_moving_current_threshold: 0.2
    close_obstacle_current_threshold: 2.0
    close_action:
      - switch.turn_on: relay2
    close_duration: ${close_duration}

    stop_action:
      - switch.turn_off: relay2
      - switch.turn_off: relay1

    obstacle_rollback: 30%
    max_duration: 55s

##BLE uses too much resources if logger is not restricted ##
esp32_ble_tracker:
  scan_parameters:
    interval: 1100ms
    window: 1100ms
    active: true

bluetooth_proxy:
  active: true

I had to restrict the logger to get stability with BLE activated. Without BLE you probably can use standard logging.

1 Like

hey, @Jethro97, sorry to bother, would you mind sharing your full config? I’m trying to follow your steps but I’m missing something.

Thank you in advance!

Sorry for late reply, sure!

substitutions:
  dn: "01-curtain"
  ldn: Curtain
  coverid: curtain1


# ------- FIXED ITEMS ------- #
esphome:
  name: $dn
  platform: ESP32
  board: esp32dev

# ------- LOGGING  ------- #

logger:
  baud_rate: 0
  level: info

# ------ HOME ASSISTANT DEFAULT CONFIGURATIONS ------- #
api:
  encryption:
    key: "*****"

ota:
- platform: esphome
  password: "*****"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 10.10.12.xxx
    gateway: 10.10.12.1
    subnet: 255.255.255.0

# ------SENSORS ------- #
uart:
  tx_pin: GPIO25
  rx_pin: GPIO26
  baud_rate: 38400
  parity: EVEN

sensor:
  - platform: cse7761
    update_interval: 500ms
    current_1:
      internal: true
      id: open_current
    current_2:
      internal: true
      id: close_current

  - platform: wifi_signal
    name: $ldn WiFi Sensor
    update_interval: 120s

text_sensor:
  - platform: wifi_info
    mac_address:
      name: MAC $ldn
      icon: mdi:wifi

# ------- STATUS LED ------- #
#status_led:
#  pin:
#    number: GPIO13
#    inverted: yes

# ------- ON_BOARD PHISYCAL BUTTON ------- #
binary_sensor: 
- platform: gpio
  pin:
    number: GPIO0
    mode: INPUT_PULLUP
    inverted: true
  id: button
  on_press:
    then:
      # logic for cycling through movements: open->stop->close->stop->...
      - lambda: !lambda |-
          if (id($coverid).current_operation == CoverOperation::COVER_OPERATION_IDLE) {
            // Cover is idle, check current state and either open or close cover.
            if (id($coverid).position == COVER_CLOSED) {
              auto call = id($coverid).make_call();
              call.set_command_open();
              call.perform();
            } else {
              auto call = id($coverid).make_call();
              call.set_command_close();
              call.perform();
            }
          } else {
            // Cover is opening/closing. Stop it.
              auto call = id($coverid).make_call();
              call.set_command_stop();
              call.perform();
          }

# ------- OPENING PHISICAL COMMAND ------- #
- platform: gpio
  pin:
    number: GPIO32
    mode: INPUT_PULLUP
    inverted: True
  name: "$ldn Opening Command"
  on_press:
    then:
      # Logic for cycling trough movements: open -> stop -> open -> ...
    - lambda: !lambda |-
          if (id($coverid).current_operation == CoverOperation::COVER_OPERATION_IDLE) {
            // Cover is idle. Open it.
            auto call = id($coverid).make_call();
            call.set_command_open();
            call.perform();
          } else {
            // Cover is opening/closing. Stop it.
            auto call = id($coverid).make_call();
            call.set_command_stop();
            call.perform();
          }

# ------- CLOSING PHISICAL COMMAND ------- #
- platform: gpio
  pin:
    number: GPIO33
    mode: INPUT_PULLUP
    inverted: True
  name: "$ldn Closing Command"
  on_press:
    then:
      # Logic for cycling trough movements: close -> stop -> close -> ...
    - lambda: !lambda |-
          if (id($coverid).current_operation == CoverOperation::COVER_OPERATION_IDLE) {
            // Cover is idle. Close it.
            auto call = id($coverid).make_call();
            call.set_command_close();
            call.perform();
          } else {
            // Cover is opening/closing. Stop it.
            auto call = id($coverid).make_call();
            call.set_command_stop();
            call.perform();
          }

# ------- POWER INTERLOCKED RELAYS ------- #
switch:
- platform: gpio
  pin: GPIO27
  interlock: &interlock [open_cover, close_cover]
  id: open_cover

- platform: gpio
  pin: GPIO14
  interlock: *interlock
  id: close_cover     

# ------- COVER CONFIGURATION ------- #

cover:
  - platform: current_based
    name: "$ldn"
    device_class: blind
    id: "$coverid"

    open_sensor: open_current
    open_moving_current_threshold: 0.5
    open_obstacle_current_threshold: 3.0
    open_duration: 30s
    open_action:
      - switch.turn_on: open_cover

    close_sensor: close_current
    close_moving_current_threshold: 0.5
    close_obstacle_current_threshold: 3.0
    close_duration: 30s
    close_action:
      - switch.turn_on: close_cover

    stop_action:
      - switch.turn_off: close_cover
      - switch.turn_off: open_cover

    start_sensing_delay: 1s
    max_duration: 35s