fix relay not turning on at boot (#5315)

These changes eliminate an elaborate race condition
* add dedicated function to handle on/off and relay
* add clarifying comment on output set order
* add define for relay delay, honor forceOff in all cases
This commit is contained in:
Damian Schneider
2026-01-31 17:40:53 +01:00
committed by GitHub
parent 2c4ed4249d
commit 1ca55e42af
5 changed files with 21 additions and 14 deletions

View File

@@ -156,7 +156,7 @@ class DeepSleepUsermod : public Usermod {
delay(1000); // just in case: give user a short ~10s window to turn LEDs on in UI (delaycounter is 10 by default)
return;
}
if (powerup == false && delaycounter) { // delay sleep in case a preset is being loaded and turnOnAtBoot is disabled (handleIO() does enable offMode temporarily in this case)
if (powerup == false && delaycounter) { // delay sleep in case a preset is being loaded and turnOnAtBoot is disabled (beginStrip() / handleIO() does enable offMode temporarily in this case)
delaycounter--;
if (delaycounter == 1 && offMode) { // force turn on, no matter the settings (device is bricked if user set sleepDelay=0, no bootup preset and turnOnAtBoot=false)
if (briS == 0) bri = 10; // turn on and set low brightness to avoid automatic turn off

View File

@@ -367,24 +367,29 @@ void handleIO()
// if we want to control on-board LED (ESP8266) or relay we have to do it here as the final show() may not happen until
// next loop() cycle
if (strip.getBrightness()) {
handleOnOff();
}
void handleOnOff(bool forceOff)
{
if (strip.getBrightness() && !forceOff) {
lastOnTime = millis();
if (offMode) {
BusManager::on();
if (rlyPin>=0) {
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
digitalWrite(rlyPin, rlyMde);
delay(50); // wait for relay to switch and power to stabilize
// note: pinMode is set in first call to handleOnOff(true) in beginStrip()
digitalWrite(rlyPin, rlyMde); // set to on state
delay(RELAY_DELAY); // let power stabilize before sending LED data (#346 #812 #3581 #3955)
}
offMode = false;
}
} else if (millis() - lastOnTime > 600 && !strip.needsUpdate()) {
} else if ((millis() - lastOnTime > 600 && !strip.needsUpdate()) || forceOff) {
// for turning LED or relay off we need to wait until strip no longer needs updates (strip.trigger())
if (!offMode) {
BusManager::off();
if (rlyPin>=0) {
digitalWrite(rlyPin, !rlyMde); // set output before disabling high-z state to avoid output glitches
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
digitalWrite(rlyPin, !rlyMde);
}
offMode = true;
}

View File

@@ -114,6 +114,8 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit");
#endif
#endif
#define RELAY_DELAY 50 // delay in ms between switching on relay and sending data to LEDs
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2)
#define WLED_MAX_COLOR_ORDER_MAPPINGS 5
#else

View File

@@ -20,6 +20,7 @@ void longPressAction(uint8_t b=0);
void doublePressAction(uint8_t b=0);
bool isButtonPressed(uint8_t b=0);
void handleButton();
void handleOnOff(bool forceOff = false);
void handleIO();
void IRAM_ATTR touchButtonISR();

View File

@@ -591,6 +591,10 @@ void WLED::beginStrip()
strip.setShowCallback(handleOverlayDraw);
doInitBusses = false;
// init offMode and relay
offMode = false; // init to on state to allow proper relay init
handleOnOff(true); // init relay and force off
if (turnOnAtBoot) {
if (briS > 0) bri = briS;
else if (bri == 0) bri = 128;
@@ -606,7 +610,8 @@ void WLED::beginStrip()
}
briLast = briS; bri = 0;
strip.fill(BLACK);
strip.show();
if (rlyPin < 0)
strip.show(); // ensure LEDs are off if no relay is used
}
colorUpdated(CALL_MODE_INIT); // will not send notification but will initiate transition
if (bootPreset > 0) {
@@ -614,12 +619,6 @@ void WLED::beginStrip()
}
strip.setTransition(transitionDelayDefault); // restore transitions
// init relay pin
if (rlyPin >= 0) {
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
digitalWrite(rlyPin, (rlyMde ? bri : !bri));
}
}
void WLED::initAP(bool resetAP)