LoraTap SC500W-V1 shutter switch with ESPHome

Hi,

the last few days I spent on dealing with this cheap, but good shutter switch. Because I did not wanted to register and deal with Tuya, I desided to change it to ESPHome.
Now I would like to share my knowledge and .yaml.

first of all the unit:
-get shure to buy the version V1 with the Tuya ESP8285
-it works with a Remote Control on 868MHz, WiFi and you can connect normal wall-buttons
-its small enought to fit in a standard 68mm wallbox

After simple opening the case, it is needed to solder the contacts or cables for the flash process.
Here is a very good tutorial allready and was as well my base to do the hole change. thanks to @zry98

my testunit with flash and reset buttons:
PXL_20230919_163328564 (Handy) PXL_20230919_163148139 (Handy)

YAML:
-Because I do not need this working in three different ways, I desided to deactivate WiFi and have it only as a backup for ota changings of the .yaml. As well I dont want in every corner of my house a wifi client.

-There is a delay of 1sec.between quick up and down changes to protect the motor. A interlock is not needed, because there is always a stop command before changing up or down direction.

-Wall-push-buttons: press once the push-button and the curtain opens/closes completely, to stop press during the open/close action more then 1sec. and keep it pressed until you reach the position you like, after release the button, the curtain will stop.

-There are some other settings you can include, exclude or change like you need.

19.09.23-18.24.19

esphome:
  name: "curtain-test"
  friendly_name: "curtain-test"

###turn wifi off, also set (api: --> reboot_timeout: 0s) to prevent bootloop
  on_boot:
     then:
       - delay: 300s
       - wifi.disable:

  #esp8266 1MB flash
esp8266:
  board: esp8285
  restore_from_flash: false

# Enable logging
logger:

# Enable Home Assistant API
api:
###turn wifi off, set (api: --> reboot_timeout: 0s) to prevent bootloop
  reboot_timeout: 0s
  
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  

wifi:
  #wifi powersafe mode: NONE,LIGHT,HIGH
  power_save_mode: HIGH
#  fast_connect: true  
  
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  
  manual_ip:
    static_ip: 192.168.1.00
    gateway: 192.168.1.0
    subnet: 255.255.255.0
    dns1: 192.168.1.0

  # Enable fallback hotspot (captive portal) in case wifi connection fails, http:192.168.4.1
  ap:
    ssid: "Esphome-Web-22xx22"
    password: "xxxxxx"

captive_portal:
  

      # reduce write frequency to flash to avoid wearing it out, adjust it as needed
preferences:
  flash_write_interval: 1h
 

substitutions:
  device_name: 'shutter 1'
  
  
  # for hard restart 
button:
  - platform: restart
    id: restart_button
    name: 'Restart ${device_name}'
    entity_category: diagnostic

status_led:  # onboard LED
  pin:
    number: 3
    inverted: true


 
  # external switches
binary_sensor: 
  - platform: gpio
    id: switch_open
    pin:
      number: 4
      inverted: true
    on_click:
    - min_length: 50ms        # Short press
      max_length: 500ms
      then:
        - cover.open: shutter
    - min_length: 1000ms      # Medium press / long
      max_length: 5000ms
      then:
        - cover.stop: shutter      
     
  - platform: gpio
    id: switch_close
    pin:
      number: 5
      inverted: true     
    on_click:
    - min_length: 50ms        # Short press
      max_length: 500ms
      then:
        - cover.close: shutter
    - min_length: 1000ms      # Medium press / long
      max_length: 5000ms
      then:
        - cover.stop: shutter     

  - platform: gpio
    id: stop_button
    pin:
      number: 13
      inverted: true
    on_click: 
      then:
        - cover.stop: shutter



  # relays
output:
  - platform: gpio
    id: relay_open
    pin: 12
  - platform: gpio
    id: relay_close
    pin: 14



  # cover with 1000ms delay inbetween change of directions
cover:
  - platform: time_based
    id: shutter
    name: '${device_name}'
    device_class: shutter
    open_action:   
      - output.turn_off: relay_close
      - delay: 1000ms    # additional delay   
      - output.turn_on: relay_open
    open_duration: 40s   # adjust it to the actual duration to fully open
    close_action:   
      - output.turn_off: relay_open
      - delay: 1000ms    # additional delay 
      - output.turn_on: relay_close
    close_duration: 40s  # adjust it to the actual duration to fully close
    stop_action:
      - output.turn_off: relay_open
      - output.turn_off: relay_close      
    assumed_state: true



   #optional
#sensor:
#  - platform: wifi_signal
#    name: "WiFi Signal Strength"
#    update_interval: 60s

#  - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB
#    name: "WiFi Signal dB"
#    id: wifi_signal_db
#    update_interval: 60s
#    entity_category: "diagnostic"

#  - platform: copy # Reports the WiFi signal strength in %
#    source_id: wifi_signal_db
#    name: "WiFi Signal Percent"
#    filters:
#      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
#    unit_of_measurement: "Signal %"
#    entity_category: "diagnostic"
    
#  - platform: uptime
#    name: Uptime Sensor
#    update_interval: 60s
    
    
###on_click:  standard timings
#    - min_length: 50ms        # Short press
#      max_length: 500ms
#      then:
#        # Some action
#    - min_length: 500ms      # Medium press
#      max_length: 3000ms
#      then:
#        # Some other action
#    - min_length: 3000ms        # Long press
#      max_length: 10000ms
#      then:
#        # Some other action

enjoy

3 Likes

wifi.disable did not work properly and got repaired in ESPHome 2023.9.0 (stable)

Meanwhile I did receive the shutters for my house and have installed them.

Finally in reality it looks all different with the code for the LoraTap shutter switch and I did find out, that the cover-component is useless in my case.

There is the problem with the timing.
If you open/stop/close/stop/open/stop/open… it looses the real position an the shutters stops anywhere but not where you want them.
I understood now that the cover-component is a compromise because there is only a virtual position recognitioning. It works great only if you always fully open or close the shutters.

Now I decided to make the code based on a simple double relay.
Like this you loose the comfortable shutter switch control in HA, but all the rest works like I wanted.
My prefered control units are anyway the RF remote and the wall buttons what works like a charme now.
And the relay switches in HA I do use to connect the shutter-motors into theirs programming mode.

To intergrate the shutters better in HA with the double relay, its needed to create a automatism for it. But this is no problem at all.

So finally I`m glad with this code and maybe somebody else gets happy with it as well:

esphome:
  name: "rolladen-test"
  friendly_name: "rolladen-test"

  #turn wifi off, set (api: --> reboot_timeout: 0s) to prevent bootloop
#  on_boot:
#     then:
#       - delay: 300s
#       - wifi.disable:
   
#external_components:
#  - source: github://ssieb/esphome@wifioff
#    components: [ wifi ]
#    refresh: 1min
 

  #esp8266 1MB flash
esp8266:
  board: esp8285
  restore_from_flash: false

# Enable logging
logger:

# Enable Home Assistant API
api:
  #turn wifi off, set (api: --> reboot_timeout: 0s) to prevent bootloop
  reboot_timeout: 0s
  
  encryption:
    key: "xxxxxxxx"

ota:
   password: "xxxxxxxx"
  

wifi:
  #wifi powersafe mode: NONE,LIGHT,HIGH
  power_save_mode: HIGH
#  fast_connect: true  
  
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  
  manual_ip:
    static_ip: 192.168.1.x
    gateway: 192.168.1.x
    subnet: 255.255.255.0
    dns1: 192.168.1.x

  # Enable fallback hotspot (captive portal) in case wifi connection fails, http:192.168.4.1
#  ap:
#    ssid: "Esphome-Web-xxxxxx"
#    password: "xxxxxx"

#captive_portal:
  

      # reduce write frequency to flash to avoid wearing it out, adjust it as needed
preferences:
  flash_write_interval: 24h
 

substitutions:
  device_name: 'Rolladen test'
  
  
  # for hard restart 
button:
   - platform: restart
     id: restart_button
     name: 'Restart ${device_name}'
     entity_category: diagnostic

status_led:  # onboard LED
     pin:
         number: 3
         inverted: true


  # relays
switch:
   - platform: gpio
     id: open_relay
     name: open ${device_name}
     pin: 12
#     interlock: [close_relay]
   - platform: gpio
     id: close_relay
     name: close ${device_name}
     pin: 14
#     interlock: [open_relay]


script:
   - id: open_script
     mode: restart
     then:
         - switch.turn_off: close_relay 
         - delay: 500ms          
         - switch.turn_on: open_relay
         - delay: 30s        
         - switch.turn_off: open_relay
        
   - id: open_halt_script
     then:   
         - switch.turn_off: open_relay
        
   - id: close_script
     mode: restart
     then:   
         - switch.turn_off: open_relay
         - delay: 500ms          
         - switch.turn_on: close_relay
         - delay: 30s
         - switch.turn_off: close_relay 
        
   - id: close_halt_script
     then:  
         - switch.turn_off: close_relay  
      

  # external switches
binary_sensor: 
   - platform: gpio
     id: open_button
     pin:
         number: 4
         inverted: true
     on_click:
       - min_length: 50ms        # Short press
         max_length: 500ms
         then:
             - script.execute: open_script
       - min_length: 1000ms      # Medium press / long
         max_length: 30000ms
         then:
             - script.execute: open_halt_script
             - script.stop: open_script
             - script.stop: close_script       
        
   - platform: gpio
     id: close_button
     pin:
         number: 5
         inverted: true     
     on_click:
       - min_length: 50ms        # Short press
         max_length: 500ms
         then:
             - script.execute: close_script       
       - min_length: 1000ms      # Medium press / long
         max_length: 30000ms
         then:
             - script.execute: close_halt_script
             - script.stop: open_script
             - script.stop: close_script      
      
   - platform: gpio
     id: stop_button
     pin:
         number: 13
         inverted: true
     on_click: 
         then:
             - script.execute: open_halt_script
             - script.execute: close_halt_script      
             - script.stop: open_script
             - script.stop: close_script       
        
    
    
 #on_click:
#    - min_length: 50ms        # Short press
#      max_length: 500ms
#      then:
#        # Some action
#    - min_length: 500ms      # Medium press
#      max_length: 3000ms
#      then:
#        # Some other action
#    - min_length: 3000ms        # Long press
#      max_length: 10000ms
#      then:
#        # Some other action
1 Like

Meanwhile I changed some things. Added double-click to “close shutter only half” etc.
my optimised .yaml looks like this now:

esphome:
  name: "rolladen-test"
  friendly_name: "rolladen-test"
  min_version: 2024.11.0
  name_add_mac_suffix: false

  #turn wifi off, set (api: --> reboot_timeout: 0s) to prevent bootloop
  on_boot:
     then:
       - delay: 300s
       - wifi.disable:
   
 
  #esp8266 1MB flash
esp8266:
  board: esp8285
  restore_from_flash: true

  # reduce write frequency to flash to avoid wearing it out, adjust it as needed
preferences:
  flash_write_interval: 24h

# Enable logging
logger:

# Enable Home Assistant API
api:
  #turn wifi off, set (api: --> reboot_timeout: 0s) to prevent bootloop
  reboot_timeout: 0s
  
  encryption:
    key: "xxx"

ota:
  - platform: esphome
    password: "xxx"
  

wifi:
  #wifi powersafe mode: NONE,LIGHT,HIGH
  power_save_mode: LIGHT
#  fast_connect: true  

  #turn wifi off, set reboot_timeout: 0s) to prevent bootloop
  reboot_timeout: 0s
  
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  
  manual_ip:
    static_ip: 192.168.1.xxx
    gateway: 192.168.1.1
    subnet: 255.255.255.0
    dns1: 192.168.1.xxx

  # Enable fallback hotspot (captive portal) in case wifi connection fails, http:192.168.4.1
  ap:
    ssid: "Esphome-Web-xxx"
    password: "xxx"

captive_portal:
  
substitutions:
  device_name: 'Rolladen test'
  
  
  # for hard restart 
button:
   - platform: restart
     id: restart_button
     name: 'Restart ${device_name}'
     entity_category: diagnostic

  # onboard LED
status_led:
    pin:
     number: 3
     inverted: true


  # relays
switch:
   - platform: gpio
     id: open_relay
     name: open ${device_name}
     pin:
         number: 12
#     interlock: [close_relay]
   - platform: gpio
     id: close_relay
     name: close ${device_name}
     pin:
         number: 14         
#     interlock: [open_relay]


script:
   - id: open_script
     mode: restart
     then:
         - switch.turn_off: close_relay 
         - delay: 500ms          
         - switch.turn_on: open_relay
         - delay: 30s        
         - switch.turn_off: open_relay
        
   - id: open_halt_script
     then:   
         - switch.turn_off: open_relay
        
   - id: close_script
     mode: restart
     then:   
         - switch.turn_off: open_relay
         - delay: 500ms          
         - switch.turn_on: close_relay
         - delay: 30s
         - switch.turn_off: close_relay 
        
   - id: close_halt_script
     then:  
         - switch.turn_off: close_relay    
   
   - id: close_half
     mode: restart
     then:   
         - switch.turn_off: open_relay
         - delay: 500ms          
         - switch.turn_on: close_relay
         - delay: 9s
         - switch.turn_off: close_relay

   - id: open_half
     mode: restart
     then:        
         - switch.turn_off: close_relay 
         - delay: 500ms          
         - switch.turn_on: open_relay
         - delay: 9s        
         - switch.turn_off: open_relay  

  # external switches
binary_sensor: 
   - platform: gpio
     id: open_button
     pin:
         number: 4
         inverted: true

     on_click:
       - min_length: 25ms        # Short press
         max_length: 1000ms
         then:
             - script.execute: open_script
       - min_length: 1000ms      # Medium press / long
         max_length: 30000ms
         then:
             - script.execute: open_halt_script
             - script.stop: open_script
             - script.stop: close_script       
 
     on_double_click:
         min_length: 20ms
         max_length: 350ms
         then:
             - script.execute: open_half   
 
   - platform: gpio
     id: close_button
     pin:
         number: 5
         inverted: true
      
     on_click:
       - min_length: 25ms        # Short press
         max_length: 1000ms
         then:
             - script.execute: close_script       
       - min_length: 1000ms      # Medium press / long
         max_length: 30000ms
         then:
             - script.execute: close_halt_script
             - script.stop: open_script
             - script.stop: close_script      

     on_double_click:
         min_length: 20ms
         max_length: 350ms
         then:
             - script.execute: close_half
      
   - platform: gpio
     id: stop_button
     pin:
         number: 13
         inverted: true

     on_click: 
         then:
             - script.execute: open_halt_script
             - script.execute: close_halt_script      
             - script.stop: open_script
             - script.stop: close_script

dashboard tile looks like this now:

The uppest button switches up- an down- botton together.
In my case tis is needed to readjust the endpoints from the shutter motor by remote. Otherwise I would need to unmount the wall-switch-buttons and do this manually.

update:

Meanwhile my script got a little modified for a newer SC-500W Version with CB2S (BK7231N) module. For these, the pin numbers are different.

In this two years, some of the switches did break. Power stages burned, because of overload. This always happend after power cuts of the public grid.
I don’t know if it was a peak of overvoltage killed them or if the infinite search for the WiFi, which was not availlable, caused this.
I think it was last of them, because I do have a good overvoltage protection built in the main fuse board.

But the good news is that the CB2S boards are more efficient on ESPhome than the old MCU with ESP8285. (at least in my usecase.)
The power consumption on 8285 (wifi off) is the same as BK7231N (wifi on).
But “wifi off” does have no benefits on BK7231N. Maybe this will be optimized someday.

Anyways, I’m still happy with this solution. It’s a pitty that they are not designed more robust, but what do we aspect from a €10 shutter switch.

yaml script
esphome:
  name: "rolladen-4"
  friendly_name: RF Stube Nord

  #turn wifi off, set (api: --> reboot_timeout: 0s) to prevent bootloop  (!!!no power save benefits on CB2S!!!)
  on_boot:
     then:
       - delay: 600s
       - wifi.disable:

bk72xx:
  board: cb2s
#  restore_from_flash: false (!!!not working on CB2S!!!)

# Enable logging
logger:

# Enable Home Assistant API
api:
  #turn wifi off, set (api: --> reboot_timeout: 0s) to prevent bootloop
  reboot_timeout: 0s

  encryption:
    key: "!secret encryption_key"

ota:
  - platform: esphome
    password: "!secret ota_password"
  
wifi:
  #wifi powersafe mode: NONE,LIGHT,HIGH
  power_save_mode: HIGH
#  fast_connect: true  
  
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  
  manual_ip:
    static_ip: 192.168.1.100
    gateway: 192.168.1.1
    subnet: 255.255.255.0
    dns1: 192.168.1.1

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esphome-Web-r4"
    password: !secret wifi_ap_password

captive_portal:

substitutions:
  device_name: 'RT Stube Nord'


  # for hard restart
button:
   - platform: restart
     id: restart_button
     name: 'Restart ${device_name}'
     entity_category: diagnostic

  # onboard LED
status_led:
  pin:
    number: 10
    inverted: true


  # relays
switch:
   - platform: gpio
     id: open_relay
     name: open ${device_name}
     pin:
         number: 24
#     interlock: [close_relay]
   - platform: gpio
     id: close_relay
     name: close ${device_name}
     pin:
         number: 26
#     interlock: [open_relay]


script:
   - id: open_script
     mode: restart
     then:
         - switch.turn_off: close_relay
         - delay: 500ms
         - switch.turn_on: open_relay
         - delay: 50s
         - switch.turn_off: open_relay

   - id: open_halt_script
     then:
         - switch.turn_off: open_relay

   - id: close_script
     mode: restart
     then:
         - switch.turn_off: open_relay
         - delay: 500ms
         - switch.turn_on: close_relay
         - delay: 50s
         - switch.turn_off: close_relay

   - id: close_halt_script
     then:
         - switch.turn_off: close_relay

   - id: close_half
     mode: restart
     then:
         - switch.turn_off: open_relay
         - delay: 500ms
         - switch.turn_on: close_relay
         - delay: 12s
         - switch.turn_off: close_relay

   - id: open_half
     mode: restart
     then:
         - switch.turn_off: close_relay
         - delay: 500ms
         - switch.turn_on: open_relay
         - delay: 16s
         - switch.turn_off: open_relay

  # external switches
binary_sensor:
   - platform: gpio
     id: open_button
     pin:
         number: 7
         inverted: true
     on_click:
       - min_length: 25ms
         max_length: 1000ms
         then:
             - script.execute: open_script
       - min_length: 1000ms
         max_length: 30000ms
         then:
             - script.execute: open_halt_script
             - script.stop: open_script
             - script.stop: close_script

     on_double_click:
         min_length: 20ms
         max_length: 350ms
         then:
             - script.execute: open_half

   - platform: gpio
     id: close_button
     pin:
         number: 6
         inverted: true
     on_click:
       - min_length: 25ms
         max_length: 1000ms
         then:
             - script.execute: close_script
       - min_length: 1000ms
         max_length: 30000ms
         then:
             - script.execute: close_halt_script
             - script.stop: open_script
             - script.stop: close_script

     on_double_click:
         min_length: 20ms
         max_length: 350ms
         then:
             - script.execute: close_half

   - platform: gpio
     id: stop_button
     pin:
         number: 8
         inverted: true
     on_click:
         then:
             - script.execute: open_halt_script
             - script.execute: close_halt_script
             - script.stop: open_script
             - script.stop: close_script
1 Like

Hi, could you explain better where you soldered the gipo0 to make the flash?

One possibilty would be to use the link in my first post from Zry.IO or search the net. There are many howtos.