ESP8266 Relay (active low): how to prevent triggering on boot or reset (SOLVED)

I have a 4 Relay Module board which uses optocouplers, and has an active low. It’s easy to control through esphomelib, the following does it:

switch:
  - platform: gpio
    pin:
      number: D0
      inverted: True
    name: "Relay 1"

However, on boot or reset, the relay triggers momentarily which causes the connected device to come on which is unwanted behaviour. I have read quite a few articles describing the state of the pins on boot so I have tried to connect to one that is “High” on boot, but it seems to have had no effect.

Apparently the solution if coding it yourself would be to write “HIGH” to the pin before setting the pinMode:
(http://arduinoinfo.mywikis.net/wiki/ArduinoPower#More_Complex_Systems:)

digitalWrite(Relay, HIGH);
pinMode(Relay, OUTPUT);

but I don’t know how to do that via esphomelib.

Edit: solution here
Edit2: better solution here following an update of esphomelib

Hi, I think you need to use a pin that doesn’t change on boot, have you tried 12 to 15 ?
I found this quite informative http://www.thesmarthomehookup.com/nodemcu-esp32-and-esp8266-pin-modes-analog-and-digital-inputs-and-outputs/

Thanks, that website is really useful. It mentions another article and that provides a great explanation of which pin is best to use as in- or output and why:
http://www.thesmarthomehookup.com/post-320/

tl;dr

However that didn’t solve my problem :thinking:

For clarification, I’m using a “Wemos” D1 Mini from Aliexpress. It has less pins than the NodeMCU, but the pins that are present and have the same label (D0-D8) are connected to the same GPIO pins as on the NodeMCU, which may be obvious to some but I wanted to cover all bases.

1 Like

Turns out the solution was right in front of me from the beginning!

After creating/compiling the firmware for the first time, a directory with the device’s name specified in the YAML file is created (“relay_test” in my example) and in there, a “src” subdirectory with the file “main.cpp”. After reading the documentation to create a custom sensor I worked out how to edit “main.cpp” and manually inserted the digitalWrite() statement, but for this to work with esphomeyaml requires an extra flag in the device’s YAML file:

relay_test.yaml

esphomeyaml:
  name: relay_test
  platform: ESP8266
  board: d1_mini
  use_custom_code: True  #<<---- this is the extra flag

#wifi, mqtt, ota etc goes here

switch:
  - platform: gpio
    pin:
      number: D5 #remember to change in main.cpp if changed here
      inverted: True
    name: "Relay 1"
#two more relays on D6 and D7 but the YAML is the same

relay_test/src/main.cpp

void setup() {
  //write HIGH to the relay pins before anything else to avoid
  //triggering on boot / reset (this is for active low relays)
  digitalWrite(14, HIGH); //D5
  digitalWrite(12, HIGH); //D6
  digitalWrite(13, HIGH); //D7
  // ===== DO NOT EDIT ANYTHING BELOW THIS LINE =====
  // ========== AUTO GENERATED CODE BEGIN ===========
  ....
}

The pinMode is set by the auto generated code, so in my solution digitalWrite() is called before pinMode() as described in the explanation in the first post.

Changes made to main.cpp (outside the auto generation area) are persistent, so any changes to my relay_test.yaml won’t break the fix. Of course if you change GPIO pins in YAML you would have to manually edit the number in the digitalWrite() statement.

This has (so far) fixed the problem of triggering the relay on boot and reset!

2 Likes

From version 1.10.0 of esphomelib ESPHome this has been implemented in YAML, and the documentation can be found here: https://esphomelib.com/esphomeyaml/components/switch/gpio.html#configuration-variables

You can now use

restore_mode: RESTORE_DEFAULT_OFF # or ALWAYS_OFF, see the docs for difference

to add digitalWrite(relay, HIGH) before pinMode(relay, OUTPUT) to the generated code by writing the switch definition as follows:

switch:
  - platform: gpio
    id: r1_boilerdemand
    restore_mode: RESTORE_DEFAULT_OFF
    pin:
      number: D5
      inverted: True

Please note that restore_mode takes into account the value of inverted, so for restore_mode: ..._OFF when inverted is true, the switch will be off, which means the GPIO is HIGH.

1 Like

hello. I use same hardware. Use this solution, but have little problem.
When ESP loaded, in web UI it show all switches enabled, but really they are disabled.
So i need click on this switches to move they in disabled state.
How can i fix it?

switch:

  • platform: gpio
    name: “Relay 1”
    pin: D1
    inverted: True
    restore_mode: ALWAYS_OFF
  • platform: gpio
    name: “Relay 2”
    pin: D2
    inverted: True
    restore_mode: ALWAYS_OFF
  • platform: gpio
    name: “Relay 3”
    pin: D4
    inverted: True
    restore_mode: ALWAYS_OFF
  • platform: gpio
    name: “Relay 4”
    pin: D5
    inverted: True
    restore_mode: ALWAYS_OFF

There’s been a bugfix for that recently, but the quick solution is to move the inverted into the pin schema.

switch:
- platform: gpio
  # ...
  pin:
    number: D1
    inverted: True

Hi,

I am struggling with I think might be a similar issue. I am using an idea from link below to connect large quantities of relays using ESP 8266 + MCP23017

https://khaz.me/cheap-and-easy-control-of-8-relays-through-home-assistant/

Despite using restore_mode: ALWAYS_OFF during reset/boot after power off there is a quick short trigger of all relays one ater each other. Have anyone of You had this issue or was able to solve this problem? Below my code + logs from ESPHome.

Hm… i’m just guessing, but why do you use “inverted: true” with MCP? That might be the cause of relay trigger: ESP board first defines MCP pins as output. Since you have relays connected reverse in this moment relay activates. Then board re-defines pins as reverse, so pin changes state and relay releases → startup click happens.

I just play with MCP and my relays doesn’t move at startup, but, as said, i don’t have inverted outputs. MCP has normal outuputs, not open collector or open drain (ok it does, but only if you specifically want them to be), so you just connect relay between output and ground (and add diode in reverse, of course).

I use “inverted: true” because in case it is as default (false) then all relays are ON after boot. I need to have them OFF during boot and use them as momentary switches, that is why a template is used to turn off after 500ms.

I have tried now again with inverted as false to be sure that it affects my idea but it is as mentioned above. My setup is exactly connected as below but with change that I use all other 8 pins from MCP for second 8 relays.

Could You share Your setup/code with relays so I could analyze it a little?

  name: "UP"
  pin:
    pcf8574: pcf8574_hub
    number: 2
    mode: OUTPUT
    inverted: no #True
  id: top_endstop #гиркон верх

Sure, code attached. I have reversed only inputs.
I’m not sure, how your relay board works, but it seems that it’s reversed: when GND relay is active and when it’s +3,3V relay is deactivated, that’s why you get all relays active at startup when you use inverted: false. Check out what function have that jumper on the right of relay board - maybe you can reverse function with it.
I have relays connected directly to MCP outputs (not through optocouplers) and in such way that +3,3V from MCP activates relay.

EDIT: i just tested direct outputs (from ESP8266, GPIO12, 13 and 14) with inverted: false and restore_mode: always off (or default_off). Relay still clicks at startup… If i use inverted:true, and re-wire my relays accordingly, then startup click doesn’t happen, no matter if i have statement “restore_mode…” present or not, so above solution doesn’t work at all…

switch:
#reboot
  - platform: restart
    name: "Reboot zunaj"
    
  # OPEN button 
  - platform: gpio
    id: zunaj_odpiranje_internal
    internal: true
    pin:
      mcp23xxx: mcp23017_hub
      number: 0
      mode: OUTPUT
      inverted: False
      
      
  #STOP button     
  - platform: gpio
    id: zunaj_stop_internal
    internal: true
    pin:
      mcp23xxx: mcp23017_hub
      number: 1
      mode: OUTPUT
      inverted: False
      
#------------------------------------------------------------------------------- relay OPEN
  - platform: template
    name: "Zunaj odpiranje"
    id: zunaj_odpiranje
    turn_on_action:
    - switch.turn_on: zunaj_odpiranje_internal
    - switch.template.publish:
        id: zunaj_odpiranje
        state: ON
    - delay: 1000ms
    - switch.turn_off: zunaj_odpiranje_internal
    - switch.template.publish:
        id: zunaj_odpiranje
        state: OFF 
    #tole je zato, ker če dvokliknem rele brez tegale ostane vključen  
    turn_off_action:
    - switch.turn_on: zunaj_odpiranje_internal
    - switch.template.publish:
        id: zunaj_odpiranje
        state: ON
    - delay: 1000ms
    - switch.turn_off: zunaj_odpiranje_internal
    - switch.template.publish:
        id: zunaj_odpiranje
        state: OFF  
        
 # ----------------------------------------------------------------------------- relay STOP     
  - platform: template
    name: "Zunaj STOP"
    id: zunaj_stop
    turn_on_action:
    - switch.turn_on: zunaj_stop_internal
    - switch.template.publish:
        id: zunaj_stop
        state: ON      
    turn_off_action:
    - switch.turn_off: zunaj_stop_internal  
    - switch.template.publish:
        id: zunaj_stop
        state: OFF  
        
#------------------------------------------------------------------------------- inputs 3x
binary_sensor:
#door openng
  - platform: gpio
    name: "Zunaj vrata odpiranje"
    pin:
      mcp23xxx: mcp23017_hub
      number: 8
      mode: INPUT_PULLUP
      inverted: true
      
#door closing
  - platform: gpio
    name: "Zunaj vrata zapiranje"
    pin:
      mcp23xxx: mcp23017_hub
      number: 9
      mode: INPUT_PULLUP
      inverted: true      

#door is open
  - platform: gpio
    name: "zunaj vrata odprta"
    pin:
      mcp23xxx: mcp23017_hub
      number: 10
      mode: INPUT_PULLUP
      inverted: true   
      
#door aux
  - platform: gpio
    name: "zunaj vrata reserve"
    pin:
      mcp23xxx: mcp23017_hub
      number: 11
      mode: INPUT_PULLUP
      inverted: true

As I understand this jumper allows to connect to relay module external power supply to trigger relay which is isolated from the one from MCP (in our case).

So is there any other idea to avoid this triggering during boot? Maybe not software but hardware? The worst thing is that during blackout and having the power back it will shortly start all my lights in house and open the gates…

Maybe there is a ready module which will delay providing power supply on relays after power is restored?

I know how you feel, i use similar setup for garage door, too, and startup click is absoutely not acceptable.
I can’t tell how your realy board works, but it seems that relays are triggered when you have GND at inputs, is that correct? (You can test them by connect, say, IN1 to GND and to Vcc and see when relay is turned on.)
If so, one option is to use a different relay board, which has selectable low/high active trigerring (you need relay active when +5V is at input) like THIS ONE
The main point is NOT to use “reversed:true” with MCP. At bootup all MCP pins are by default inputs, then ESP8266 defines them as outputs (set them at low state, thus activating your relays), next it changes state to high, because you have inverted output defined and relays deactivate. And this causes relay click.
Or, if you are good in soldering and electronics you could make an adapter with transistors, like picture below. I used this setup for my test, explained above (in bold).

Maybe this will help:

esp8266_restore_from_flash¶
With this option you can control where the state of certain components is kept on the ESP. Components like light, switch, fan and globals can restore their state upon boot.

However, by default this data is stored in the “RTC memory” section of the ESP8266s. This memory is cleared when the ESP8266 is disconnected from power. So by default the state cannot be recovered after power loss.

To still have these components restore their state upon power loss the state can additionally be saved in flash memory by setting this option to true.

Beware: The flash has a limited number of write cycles (usually around 100 000), after that the flash section will fail. So do not use this option when you have components that update rapidly. These include GPIO switches that are used internally (disable restoring with the restore_mode option), certain light effects like random and the on_value_range trigger.

Thanks for Your ideas.

@Protoncek - this adapter seems to be possible but in case of quantity of my relays it will be hard to achieve…

I’ve found a relay with delay on power on which I am planning to use for delaying power on relays board. It is not the best solution but in case of blackout it will not trigger relays during boot. What is Your opinion?

@lordzid - I already tought about this but it has to many cons with limitation of writing cycles for my solution.

on_boot (Optional, Automation): An automation to perform when the node starts. See on_boot. can this help you? the operation will be performed before loading the main when.

I have not seen earlier ‘on_boot’ options but this might lead to solving another way around my challenge using software solution. Will make some tests and get back with feedback.

wow… you really have quite big block of relays…
Your idea with power delay is a good one. Connect additional relay to an empty GPIO pin of ESP board. Then configure “on boot” function in ESPHome: you define delay and then turn on a relay. That way relay will turn on after, say, 2 seconds.
It’s something like this:

esphome:
  name: esp-201_demo
  platform: ESP8266
  board: esp01_1m
  comment: demo module
  on_boot:
    - delay: 2000 ms
    - switch.turn_on: power_to_relays
    
# ---------------------------------------------------------------------- SWITCH SENSORs
switch: 
  - platform: gpio
    pin: GPIO12
    id: power_to_relays
    internal: true 

You can make this output internal, so it won’t show in HA interface.

Regarding connection type: you’ll have to experiment. First try to connect a relay normally, with one transistor. If bootup-click appears then connect it reversed (via above two-transistor circuit). (you don’t use MCP module here!)

EDIT: or maybe you could use one of MCP relays. Define one of them as reversed and so i guess it should turn on at boot and off after two seconds…