Invertir polaridad

Hola a todos.

Me he hecho un programador de riego con un Arduino y una placa de 4 reles. Funciona perfectamente, es decir desde la app Blynk consigo programar el riego, conectar cada rele y apagarlos todos. Hasta aquí perfecto. Utilizó una fuente de alimentación de 9V que alienta las electrovalvulas.

El problema es que las electrovalvulas son de 9V por impulsos ya que el programador era de pilas. Esto quiere decir que el programador lanza un impulso corto POSITIVO y las electrovalvulas abren y riegan, cuando el riego tiene que terminar según el programador, lanza un impulso corto NEGATIVO y cierra la electrovalvula. En cambio el Arduino lo que hace es mandar siempre un impulso POSITIVO y lo mantiene mientras el rele está cerrado, cuando el rele abre y deja de pasar corriente, la electrovalvula sigue abierta.

He buscado solenoides que me valgan pero sólo los hay de 12V por lo que tendría que comprar una fuente de 12V + 4 solenoides y antes de hacer esta inversión quisiera saber si hay alguna manera de hacer este cambio de polaridad.

  1. Emviar una señal Positiva de 2 segundos o menos para que el solenoide abra.
  2. Enviar una señal Negstiva de 2 segundos o menos para que el solenoide cierre.

Primero quería saber si hay algún hardware que haga esto y luego si es fácil modificar el software que tengo para que funcione de esta manera.

Sino lo consigo no me quedará otra que hacer la inversión.

Gracias y saludos.

1 Like

Lo que necesitas es un puente H.
Puente H. Wikipedia
O bien lo montas con un par de reles o puedes buscar un transistor H como este.

Hola, gracias. Había leído algo de los Puente H pero sinceramente no se donde buscar información para saber como programarlo. He visto en amazon este:

H BRIDGE

podría poner la salida del cable positivo y negativo de la fuente a la IN + o - de la placa H Bridge y luego el OUT + o - a los relés, que luego conecto a los solenoides. Hasta ahí lo tengo claro. Luego tendría que unir el H Bridge a la Arduino y luego programar que el primer impulso sea Positivo, y luego Negativo para cerrar la electrovalvula. Luego el relé 2, luego el 3 y finalmente el 4, esto en la programación, luego también tendría que programa cuando conecto manualmente el riego.

Si me podéis ayudar con la programación os lo agradecería. Aquí os dejo el código que tengo actualmente y que necesitaría modificar para que funcionar por impulsos y revertiendo la polaridad:

 Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************
  This example runs directly on ESP8266 chip.

  Note: This requires ESP8266 support package:
    https://github.com/esp8266/Arduino

  Please be sure to select the right ESP8266 module
  in the Tools -> Board menu!

  Change WiFi ssid, pass, and Blynk auth token to run :)
  Feel free to apply it to any other example. It's simple!
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
#define WIFI_LED 10

// define configuration (number of switches and number of timers)
#define SWITCH_CNT 4
#define TIME_CNT 4

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>


// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "XXXXXXX";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "XXXXXXX";
char pass[] = "XXXXX";


byte switch_pins[] = {14 , 12 , 16 , 13}; // number of gpio to be used as switch/relay control

bool switch_default[] = {HIGH,HIGH,HIGH,HIGH}; // switches that use reverse polarity should be set to HIGH here

////////////////////////////////////////////////////////////////////////////////////////
// This code can control up to 4 switches                                            //
// For each switch up to 4 schedule start and end times can be configured - (V0..V15) //
// A default duration can be defined per switch                           - (V16..V19)//
// If an end time is not defined at the app the default duration is used              //
// default duration is also used when manually activating the switch       - (V20..V23)//
// for each switch when start time is reached the switch turns on for the duration    //
//                                                                                    //
// maximum duration is used for safety (to limit activation time)          - (V24..V27)//
////////////////////////////////////////////////////////////////////////////////////////
int  start_time_sec[SWITCH_CNT][TIME_CNT];     // array of 4 start times (in seconds) for 4 switches [switch number][schedual timer number]
bool start_valid[SWITCH_CNT][TIME_CNT];        // is the start time valid ?
bool weekdays[SWITCH_CNT][TIME_CNT][8];        // array of 8 days (day 0 not used) for each schedual time
int  active_duration[SWITCH_CNT][TIME_CNT+1];  // duration per switch per time(in sec)
bool end_valid[SWITCH_CNT][TIME_CNT];          // is the end time valid ?
int  max_duration[SWITCH_CNT];                 // max duration per switch
int auto_off = 1;           // 1 is auto or on

// when activating a switch a timer is set for the configured duration
// when the duration ends the switch is turned off by the timer
// the id of the timer is saved using end_timer_id
// if switch is manually turned off the end_timer_id is used to stop the timer.

// end_timer_id is initialized to 32 (per entry) at the setup section
int end_timer_id[SWITCH_CNT];

// timer object declaration
BlynkTimer timer;

// this code use Real Time Clock widget in the blynk app to keep the clock updated from net
WidgetRTC rtc;


BLYNK_CONNECTED() {
  // Synchronize time on connection
  rtc.begin();
  Blynk.syncAll();
}
WidgetLED led1(V55);

bool ledStatus = auto_off;



// V55 LED Widget is ON or OFF
void LedWidget()
{ledStatus = auto_off;
  if (ledStatus) {
   led1.on();
  } else {
    led1.off();
    
  }
}

//////////////////////////////////////////////////////////
// get schedual parameters from App                     //
//////////////////////////////////////////////////////////
void set_time(BlynkParam param, byte switch_no, byte time_no){

     TimeInputParam t(param);
  // Process start time

  if (t.hasStartTime())
  {
    
    Serial.println(String("Start: ") +
                   t.getStartHour() + ":" +
                   t.getStartMinute() + ":" +
                   t.getStartSecond());
    Serial.println(String("Start in sec: ") + param[0].asLong() + String(" for switch") + switch_no + String(" time_no: ") + time_no);
    start_time_sec[switch_no][time_no]= param[0].asLong();
    start_valid[switch_no][time_no] = true;

  }
  else
  {
    // Do nothing
    Serial.println(String("No Start Time Given for switch: ") + switch_no + String(" time_no: ") + time_no);
    start_valid[switch_no][time_no] = false;
  }
//////////////////////////////////////////////////////////////////////////////
  // check if end time is received convert and save it as day time in seconds //
  //////////////////////////////////////////////////////////////////////////////
  if (t.hasStopTime())
  {
    
    Serial.println(String("Stop: ") +
                   t.getStopHour() + ":" +
                   t.getStopMinute() + ":" +
                   t.getStopSecond());
    Serial.println(String("Stop in sec: ") + param[1].asLong() + String(" for switch") + switch_no + String(" time_no: ") + time_no);

    active_duration[switch_no][time_no] = (param[1].asLong()-start_time_sec[switch_no][time_no]);
    
    // if end time is smaller than start time this means end time is at next day
    if (active_duration[switch_no][time_no]<0) active_duration[switch_no][time_no]=86400+active_duration[switch_no][time_no];
    
    Serial.println(String("Stop duration: ") + active_duration[switch_no][time_no]);

    end_valid[switch_no][time_no] = true;


  }
  else // if end time is not defined //
  {
    // Do nothing
    Serial.println(String("No Stop Time Given for switch: ") + switch_no + String(" time_no: ") + time_no);
    end_valid[switch_no][time_no] = false;
  }

 
  // Process weekdays (1. Mon, 2. Tue, 3. Wed, ...)

  for (int i = 1; i <= 7; i++) {
    if (t.isWeekdaySelected(i)) {
      Serial.println(String("Day ") + i + " is selected");
      weekdays[switch_no][time_no][i] = true;
    }
    else {
      weekdays[switch_no][time_no][i] = false;
    }
    
  }

    Serial.println();

}
//this reads status of on/off mode and displays on screen
BLYNK_WRITE(V50) { int Vpin50 = param.asInt();
  auto_off = Vpin50;}


// V0..V3 for switch 0, V4..V7 for switch 1 ...
BLYNK_WRITE(V0)  { set_time(param, 0,0);  }
BLYNK_WRITE(V1)  { set_time(param, 0,1);  }
BLYNK_WRITE(V2)  { set_time(param, 0,2);  }
BLYNK_WRITE(V3)  { set_time(param, 0,3);  }

BLYNK_WRITE(V4)  { set_time(param, 1,0);  }
BLYNK_WRITE(V5)  { set_time(param, 1,1);  }
BLYNK_WRITE(V6)  { set_time(param, 1,2);  }
BLYNK_WRITE(V7)  { set_time(param, 1,3);  }

BLYNK_WRITE(V8)  { set_time(param, 2,0);  }
BLYNK_WRITE(V9)  { set_time(param, 2,1);  } 
BLYNK_WRITE(V10) { set_time(param, 2,2);  }
BLYNK_WRITE(V11) { set_time(param, 2,3);  }

BLYNK_WRITE(V12) { set_time(param, 3,0);  }
BLYNK_WRITE(V13) { set_time(param, 3,1);  }
BLYNK_WRITE(V14) { set_time(param, 3,2);  }
BLYNK_WRITE(V15) { set_time(param, 3,3);  }

// use a slider to define default activation duration (slider count in minute)
BLYNK_WRITE(V16) { active_duration[0][TIME_CNT] = param.asInt()*60; }
BLYNK_WRITE(V17) { active_duration[1][TIME_CNT] = param.asInt()*60; }
BLYNK_WRITE(V18) { active_duration[2][TIME_CNT] = param.asInt()*60; }
BLYNK_WRITE(V19) { active_duration[3][TIME_CNT] = param.asInt()*60; }


// use a slider to define default max duration (slider count in minute)   ***HARD CODE THIS*** NL
BLYNK_WRITE(V24) { max_duration[0] = param.asInt()*60; }
BLYNK_WRITE(V25) { max_duration[1] = param.asInt()*60; }
BLYNK_WRITE(V26) { max_duration[2] = param.asInt()*60; }
BLYNK_WRITE(V27) { max_duration[3] = param.asInt()*60; }

/////////////////////////////////////////////////////////////////
// Handle switch events (from app or from scheduler )          //
/////////////////////////////////////////////////////////////////

// turn off switch after active duration ends
// duration number is not important here 
void turn_off_switch_no_0(){ turn_on_off(0,0,0); Blynk.virtualWrite(V20,0); Serial.println(String("timer turn off switch 0 ") );}
void turn_off_switch_no_1(){ turn_on_off(0,1,0); Blynk.virtualWrite(V21,0); Serial.println(String("timer turn off switch 1 ") );}
void turn_off_switch_no_2(){ turn_on_off(0,2,0); Blynk.virtualWrite(V22,0); Serial.println(String("timer turn off switch 2 ") );}
void turn_off_switch_no_3(){ turn_on_off(0,3,0); Blynk.virtualWrite(V23,0); Serial.println(String("timer turn off switch 3 ") );}

// handle switch state
void turn_on_off(int on_off, byte switch_no , byte time_no){
    long active_duration_ms ;
    char Time_print[16];
    
    if ((on_off==1) && (auto_off == 1)) //auto_off is a slider in app to shut off the program
    {
      // create time as string to print on activation butten
      sprintf(Time_print, "%02d:%02d", hour(), minute());

      // turn on the switch (or off if default is on)
      digitalWrite(switch_pins[switch_no],!switch_default[switch_no]);

      // if end time is valid use the active duration assigned to this time
      // (change to msec will be done later)
      if (end_valid[switch_no][time_no])
         active_duration_ms = ((long)active_duration[switch_no][time_no]);
      else // otherwise use the general time duration
         active_duration_ms = ((long)active_duration[switch_no][4]);

      
      // max duration smaller than two min is not valid
      if ( (max_duration[switch_no]< 120) | (max_duration[switch_no]>active_duration_ms) )
         active_duration_ms = active_duration_ms*1000;
      else
        active_duration_ms = ((long)max_duration[switch_no])*1000;
       

      // if new timer is set before another one ended then disable previous timer
      if (end_timer_id[switch_no]!=32) timer.deleteTimer(end_timer_id[switch_no]);

      // turn on switch and set timer 
      switch (switch_no) {
        case 0: 
          Blynk.setProperty(V20, "onLabel", String(Time_print));
          Blynk.virtualWrite(V20,1);
          end_timer_id[0]=timer.setTimeout(active_duration_ms, turn_off_switch_no_0);
          
         break;
        case 1: 
          Blynk.setProperty(V21, "onLabel", String(Time_print));
          Blynk.virtualWrite(V21,1);
          end_timer_id[1]=timer.setTimeout(active_duration_ms, turn_off_switch_no_1);
         break;
        case 2: 
          Blynk.setProperty(V22, "onLabel", String(Time_print));
          Blynk.virtualWrite(V22,1);
          end_timer_id[2]=timer.setTimeout(active_duration_ms, turn_off_switch_no_2);
         break;
        case 3: 
          Blynk.setProperty(V23, "onLabel", String(Time_print));
          Blynk.virtualWrite(V23,1);
          end_timer_id[3]=timer.setTimeout(active_duration_ms, turn_off_switch_no_3);
         break;    
      } 
      Serial.println(String("turn ON switch: ") + switch_no + String(" for duration: ") + active_duration_ms/60000 + String("min "));
    }
    else 
    {
      digitalWrite(switch_pins[switch_no],switch_default[switch_no]);
      timer.deleteTimer(end_timer_id[switch_no]);
      end_timer_id[switch_no]=32;
      Serial.println(String("turn OFF switch: ") + switch_no);
    }   
}

// set switch state from APP
BLYNK_WRITE(V20) { turn_on_off(param.asInt(),0,TIME_CNT); }
BLYNK_WRITE(V21) { turn_on_off(param.asInt(),1,TIME_CNT); }
BLYNK_WRITE(V22) { turn_on_off(param.asInt(),2,TIME_CNT); }
BLYNK_WRITE(V23) { turn_on_off(param.asInt(),3,TIME_CNT); }
/////////////////////////////////////////////////////////////////////////////////////////////
// the following function is called every 60 seconds by a timer                            //
//  the function checks if a start time is reached and if yes it will call                 //
//   the turn_on_off function (to turn on the switch and set timer for turning off switch) //
/////////////////////////////////////////////////////////////////////////////////////////////
void activetoday(){         // check if schedule #1 should run today

  if(Blynk.connected()) // set wifi led if no connection
  {
    digitalWrite(WIFI_LED,LOW); 
  }
  else
  {
    digitalWrite(WIFI_LED,HIGH); 
  }
  
  if(year() != 1970){
    unsigned int nowseconds = ((hour() * 3600) + (minute() * 60) + second());
    int dayadjustment = -1;  
    if(weekday() == 1){
      dayadjustment = 6; // needed for Sunday Time library is day 1 and Blynk is day 7
    }
   
 
     for (int switch_cnt = 0;  switch_cnt< SWITCH_CNT; switch_cnt++) {
         for (int timer_cnt = 0;  timer_cnt< TIME_CNT; timer_cnt++) {
              if (start_valid[switch_cnt][timer_cnt] == true) {
                if (weekdays[switch_cnt][timer_cnt][weekday() + dayadjustment]==true){
                  
                   if (nowseconds >= start_time_sec[switch_cnt][timer_cnt]){
                      
                      if(nowseconds < start_time_sec[switch_cnt][timer_cnt]+90){
                        turn_on_off(1,switch_cnt,timer_cnt);
                        Serial.println(String("turn ON switch: ") + switch_cnt);

                      }
                   }
                }
              }
         }
      
     }
 
  } 
}

/////////////////////////////////////

// Digital clock display of the time
void clockDisplay()
{
  // You can call hour(), minute(), ... at any time
  // Please see Time library examples for details

  String currentTime = String(hour()) + ":" + minute() + ":" + second();
  String currentDate = String(day()) + " " + month() + " " + year();
  Serial.print("Current time: ");
  Serial.print(currentTime);
  Serial.print(" ");
  Serial.print(currentDate);
  Serial.println();

  // Send DATE and DATE to Blynk APP
  Blynk.virtualWrite(V101, currentTime);
  // Send date to the App--Not used but is available--this will show processor date if it is important to you
  Blynk.virtualWrite(V102, currentDate);
}


void setup()
{
  
  Serial.begin(9600);  // Debug console
  
  // reset output pins used and system variables
  for (int i = 0; i<SWITCH_CNT ; i++){
    pinMode(switch_pins[i], OUTPUT); // reset output pins
    digitalWrite(switch_pins[i],switch_default[i]); // set switch to default
    end_timer_id[i] = 32;            // reset end timer id's

    for (int j = 0; j<TIME_CNT ; j++)
    {
      end_valid[i][j] = false;       // reset end valid array
    }
    
  }

  
  pinMode(WIFI_LED, OUTPUT);

  
  Blynk.begin(auth, ssid, pass);
    rtc.begin();  // Begin synchronizing time
    timer.setInterval(10000L, clockDisplay);
    timer.setInterval(60000L, activetoday);  // check every 60s if ON / OFF trigger time has been reached
    setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)

}

void loop()
{
  Blynk.run();
  timer.run();
  LedWidget();
}

Creo que esta web me puede ayudar:

https://electronilab.co/tutoriales/tutorial-de-uso-driver-dual-l298n-para-motores-dc-y-paso-a-paso-con-arduino/

Y adaptando este código puedo hacerlo. Ya tengo trabajo para las vacas :slight_smile:

/* 
 Ejemplo de control de motor DC usando modulo L298
 http://electronilab.co/tienda/driver-dual-para-motores-full-bridge-l298n/
 
 El programa activa el motor en un sentido por 4 segundos, 
 para el motor por 500 ms, activa el motor en sentido inverso por 4 segundos 
 y se detiene por 5 segundos. Luego repite la acción indefinidamente.
 
 Creado 16/05/14
 por Andres Cruz
 ELECTRONILAB.CO
 */

int IN3 = 5; 
int IN4 = 4;

void setup()
{
  pinMode (IN4, OUTPUT);    // Input4 conectada al pin 4 
  pinMode (IN3, OUTPUT);    // Input3 conectada al pin 5
}
void loop()
{
  // Motor gira en un sentido
  digitalWrite (IN4, HIGH);
  digitalWrite (IN3, LOW); 
  delay(4000);
  // Motor no gira
  digitalWrite (IN4, LOW); 
  delay(500);
  // Motor gira en sentido inverso
  digitalWrite (IN3, HIGH);
  delay(4000);
  // Motor no gira
  digitalWrite (IN3, LOW); 
  delay(5000);
}

Lo mas sencillo es que pruebes con 3 reles.
1 de ellos puede ser interruptor y los otros 2 conmutados.
Te explico el siguiente esquema:
Puente-H.jpg
Tendrás que utilizar 3 salidas para los 3 relays.
Quieres enviar un pulso positivo:
Configuras las salidas de los relays 2 y 3
R2 Off
R3 On
Entonces activas R1 por el tiempo que quieras que dure el pulso.
Quieres enviar un pulso negativo:
R2 On
R3 Off
Activas R1 por el tiempo que quieras que dure el pulso.

Cuando no estés enviando ningún pulso, R2 y R3 pueden estar apagados.

Puente-H.jpg

Hi,
Podrias anadir el tipo de valvula y el modelo de esta para ver como en si trabaja.

Muy bien!! lo mejor que vi es que separaste tu código Blynk del control de la electroválvula de impulso.
Asi es como se debe hacer, separar las cosas y resolver lo que te da problemas y luego intergrarlo a lo que sabes que funciona bien.

Buen trabajo.

EDITO:
Un L298 en módulo vendido en China cuesa 1.08 dolares, no hay mejor opción que comprarlo hecho aún vs armar un puente H con transistores. Nada funcionará igual.

tauro0221:
Hi,
Podrias anadir el tipo de valvula y el modelo de esta para ver como en si trabaja.

Son los HIT 210-000. Son por impulsos ya que están conectados a un programador de pilas 9V.

Hi,
Muchas gracias pregunte porque nunca habia usado/oido de esa valvula y queria saber como opera.

Hice una busqueda de esa valvula y segun la especificaciones dice que es una valvula de 24 AC y una corriente inicial de 350ma y un consumo de 250ma. Podrias verificar el modelo. Adjjunto link que tiene las especificaciones de esa valvula.

http://www.hitproductscorp.com/products/valves/200_series.pdfRain Pro Valve Hit 210-000 FPT Control Valve.

La válvula es la HIT que os pongo, he visto la pegatina, pero el solenoide es el galcon gcs 3050 / 3051 6-18 VDC LATCH 3 Ohm. Es de 9V por pulso ya que lo controla un programador de un pila 9V de la marca Rainbird WP4.

Entiendo que si me decanto por el H Bridge, tendré que quitar el módulo de 4 reles y sustituirlo por 4 H Bridges, uno por cada solenoide. Verdad?

Exacto. Es que no tienes alternativa si quieres lograr ese control de modo simple. Sino debes usar el esquema sugerido por Sereno. Que es un puente H con reles.

Ok. Pues voy a pillar uno a ver si soy capaz de adaptar mi código actual. Intentaré añadir parte del código nuevo que posteo a. Mi código.

Una duda, en mi rele de 4 actual tengo conectado la placa Arduino a IN1, IN2, IN3 e IN4. En los H Bridge veo que hay también 4 pins IN1, IN2, IN3 e IN4. Quiere decir que puedo conectar los cables que van a los IN de la placa rele actual a cada uno de IN del H Bridge? O hay que poner 4 HBridge y en cada uno de ellos pongo el cable en un IN distinto? Creo que es esta segunda opción, verdad?

Si es así, la conexión de lo actual a lo nuevo lo tengo claro.

Gracias, os iré comentando.

No. NO son la misma cosa.
Cada par IN1 e IN2 mas su ENA controlan un lado del L298. El otro lado es IN3, IN4 y ENB
Me acabo de dar cuenta que necesitas 2 L298 para controlar tus 4 electrovalvulas.
Porque cada L298 tiene 2 puentes H.

Ok. Voy a hacerme un dibujo con mis conexiones y así lo tengo más claro. Cuando lo tenga os lo enseño.

Se agradece toda la ayuda, soy un novato total, pero poco a poco voy aprendiendo

Lo que debes hacer es poner los ENA y ENB en 1 o sea a HIGH y tus comandos serán IN1/2 para una valvula y IN3/4 para otra.
Con dos modulos de 2 dolares c/u lo resuelves. Merito de @Sereno.

Surbyte, Sereno, gracias por vuestros comentarios.

Ya he pedido 2 H Bridge.

Actualmente tengo una NodeMCU conectada a una placa de 4 relés que me funciona de lujo con el programa que he posteado al principio de este post.

Las conexiones con los relés son:

NodeMCU Placa Relés
D0 (GPIO16) IN1
D5 (GPIO14) IN2
D6 (GPIO12) IN3
D7 (GPIO13) IN4

La placa la alimente con una fuente de 9V (con una placa que baja a 5V para la placa relés y 3.3V para la NodeMCU). Los 9V van directo a los relés también para alimentar los solenoides.

Esto me funcionaría si los Solenoides no fueran de pulsos como he explicado, y después de mucho buscar no los hay en el mercado.

Ahora según creo haber entendido:

  1. Tengo que coger 8 pines de la NodeMCU para los Solenoides (2 por Solenoide). Usaré los 4 que pongo arriba y buscaré otros 4 que pongan I/O (creo).
  2. Por cada H Bridge tengo para 2 solenoides por lo que solo describo las conexiones de una de las partes.
  3. Tengo una fuente de 9V que alimenta a los solenoides que son de 9V. el positivo de la fuente lo conecto al +12V del H Bridge. El negativo de la fuente lo conecto al GND del H Bridge.
  4. El OUT 1 y OUT 2 del H Bridge los conecto al positivo y negativo del solenoide. Así le llegará los 9V con un pulso positivo y se abrirá el solenoide, luego regará, y cuando acabe el tiempo de regado tendrá que enviar un pulso negativo para cerrar el solenoide.
  5. Habrá que conectar la NodeMCU a la H Bridge: el D0/GPIO16 al IN1 y el D5/GPIO14 al IN2.

Lo mismo haré con el resto. Una vez lo tenga todo conectado intentaré modificar mi código añadiendo el código que he puesto mas arriba.

A ver si soy capaz.