Wemos D1 mini pins on HIGH on startup

Hi. I have a project with a Wemos D1 mini and a 4-channel relay module with optocouplers. I only use 3 of the relays in the module, and on startup, two of them are on HIGH, even though I've set them on low in the setup:

void setup() {
  Serial.begin(115200);
  pinMode(luz_balcon, OUTPUT);
  pinMode(persiana, OUTPUT);
  pinMode(fase, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(int_sube_persiana, INPUT_PULLUP);
  pinMode(int_baja_persiana, INPUT_PULLUP);
  pinMode(interruptor, INPUT_PULLUP);
  digitalWrite(luz_balcon, LOW);
  digitalWrite(persiana, LOW);
  digitalWrite(fase, LOW);
  ConectarWiFi();
  alexa.addDevice("Luz balcon", FuncionLuz);
  alexa.addDevice("Persiana comedor", FuncionPersiana);
  alexa.begin();
}

persiana and fase are always high, regardless of the digitalWrite value I give them on the setup function. They are on pins D5 and D6 respectively, and they work as expected when the code is running.
Any idea why is this happening and how can I fix it? I really need them to be on LOW (off) at startup.

And another kind of off-topic question (though it's related to the same board): I have another Wemos D1 mini I can't load any code into. Looks like it's stuck with the code it already has, which works, but looks like the bootloader is failing or something. How can I reset it?

Thank you

Hi Juraj. Not sure I understand that message in stack exchange. I think from it, I get to the following conclussions, but I'm not sure if I'm right:
a) I can't use pin D0 (int_baja_persiana) as an INPUT_PULLUP. Can I use it as an OUTPUT instead?
b) most digital IO start as INPUT_PULLUP, and I guess that's what's triggering those two relays to be on HIGH at startup. Is there any way to negate this behaviour? or at least, immediately turn them off (LOW) afterwards? Right now they're not turning LOW even if I include that in the code (in the setup function).
c) only pins D3 and D4 have internal pullup resistors. I need 3 pullup pins for 3 switches (I was advised to use pullup instead of pulldown for ESP boards). What values should these be? I've read some articles about it, but I'm not sure about the Wemos in particular. Would 100k be a good standard value?

Thank you

a) you can, but it goes over the RTC peripheral so it is slower
b) the right way is to control the relays with inverted logic. some relay modules close the relay at LOW signal. does your relay module have inverted logic?
c) pins D3 and D4 have external on-board pull-up resistors. all io except of D0 have the internal pull-up option

a) I'm guessing we're talking about milliseconds, right? if that's the case, I'm fine with that.
b) I believe the module I have doesn't have inverted logic. As I mentioned before, for some reason those two relays stay open with either value. I've tried loading the sketch with the HIGH value and with the LOW value. In the first case, all 3 relays are on. In the second, only the relay in pin D7 is off. The other two, in pins D5 and D6 are on. I think it has something to do with the board pins more than the module itself.
c) when you are talking about external and internal in the board, what exactly do you mean? When I talk about external resistor I mean to add an actual resistor to my circuit, connected to the proper pins. Are you saying that as long as I don't use D0 as an input, I really don't need to solder any additional resistor?

Please read the sticky at the top of the forum: "How to get the best out of this forum".

Without a schematic (not a useless Fritzing picture) and your complete sketch, we would only be guessing.

pinMode INPUT_PULLUP turns on internal pull-up of the io pin in the MCU. but the esp8266 boot config pins require to set the boot config with resistor external to esp8266 chip. so the esp8266 dev boards like the Wemos D1 have on the PCB a pull-up circuit on those pins of the esp8266.

It's a super super basic design, but here it is. Also a picture of the device:


The 2-terminal connector is connected to GND and one end of the switches go there.
The 3-terminal connector is for the other end of the switches, and each terminal goes to one pin (D1, D2 and D5).
The power comes from an external PSU that has the conector underneath the Wemos board.

First I was using D0, D1 and D2 for the switches, but since @Juraj mentioned that D0 does not have a pull-up resistor, I switched it to D5 and used D0 as an output pin instead. Is my circuit now correct? And how can I make pins D0 and D6 to be on LOW at startup?

And the full code:

/*
   This is a basic example on how to use Espalexa and its device declaration methods.
*/
#ifdef ARDUINO_ARCH_ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <Espalexa.h>

int encendido = 0;
int apagado = 1;
int luz_balcon = D7;
int persiana = D0;
int fase = D6;
int interruptor = D1;
int int_sube_persiana = D2;
int int_baja_persiana = D5;
int status_luz;
int status_sube_persiana;
int status_baja_persiana;

const char* ssid = "MiFibra-5FB8";
const char* password = "cbYjPvi6";

Espalexa alexa;

void FuncionLuz(uint8_t brightness);
void FuncionPersiana(uint8_t brightness);

void setup() {
  Serial.begin(115200);
  pinMode(luz_balcon, OUTPUT);
  pinMode(persiana, OUTPUT);
  pinMode(fase, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(int_sube_persiana, INPUT_PULLUP);
  pinMode(int_baja_persiana, INPUT_PULLUP);
  pinMode(interruptor, INPUT_PULLUP);
  digitalWrite(luz_balcon, LOW);
  digitalWrite(persiana, LOW);
  digitalWrite(fase, LOW);
  ConectarWiFi();
  alexa.addDevice("Luz balcon", FuncionLuz);
  alexa.addDevice("Persiana comedor", FuncionPersiana);
  alexa.begin();
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(LED_BUILTIN, 0);
  }  else {
    digitalWrite(LED_BUILTIN, 1);
  }
  alexa.loop();
  if (status_luz != digitalRead(interruptor)) {
    digitalWrite(luz_balcon, !digitalRead(luz_balcon));
    status_luz = digitalRead(interruptor);
  }
  if ((status_sube_persiana != digitalRead(int_sube_persiana)) || (status_baja_persiana != digitalRead(int_baja_persiana))) {
    status_sube_persiana = digitalRead(int_sube_persiana);
    status_baja_persiana = digitalRead(int_baja_persiana);
    if ((digitalRead(int_sube_persiana) == LOW) && (digitalRead(int_baja_persiana) == LOW)) {
      digitalWrite(fase, apagado);
    }
    else if (digitalRead(int_sube_persiana) == HIGH) {
      digitalWrite(fase, encendido);
      digitalWrite(persiana, encendido);
    }
    else if (digitalRead(int_baja_persiana) == HIGH) {
      digitalWrite(fase, encendido);
      digitalWrite(persiana, apagado);
    }

  }

  delay(1);

}

void ConectarWiFi() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
  }
}

void FuncionLuz(uint8_t brightness) {
  if (brightness) {
    digitalWrite(luz_balcon, encendido);
  }
  else {
    digitalWrite(luz_balcon, apagado);
  }
}
void FuncionPersiana(uint8_t brightness) {
  if (brightness > 240) {
    if (digitalRead(fase) == apagado) { digitalWrite(fase, encendido); }
    digitalWrite(persiana, encendido);
  }
  else if (brightness < 20) {
    if (digitalRead(fase) == apagado) { digitalWrite(fase, encendido); }
    digitalWrite(persiana, apagado);
  }
  else {
    digitalWrite(fase, apagado);
  }
}

I've found the issue. It was a code issue. Since I'm using pull-up inputs, I had the behaviour of the switches the other way around.