Three case combination causes error in loop.

Hi. I been working on this code for some time and was quite happy with it. Unless i discovered strange error. Basically it is controlling 6 outputs in total: (external on1, off, on2), (gearbox1 on1, off, on2) and (gearbox2 on1, off, off1). Any mode is fine but when external = off , gearbox1 = off, gearbox2 = off it stops reading code in the loop(). Once one of them is in different mode, it works again. I am wondering why, as the code is quite simple, cannot see a reason. I had put some comments against code to make easier see the problem. Also i had to split code, as exceeding 9000 character limit. I thank you for any advice and sorry for my English.

#include <SimpleTimer.h>
#include <RS485_non_blocking.h>
#include <SoftwareSerial.h>
#include <Nextion.h>
#define nextion Serial1
Nextion myNextion(nextion, 9600);
SimpleTimer t;

// the data we broadcast to each other device
struct
{
  byte address;
  byte temp;
  byte wind;
  byte rain;
  int  status;
}  message;

const unsigned long BAUD_RATE = 57600;

// software serial pins
const byte RX_PIN = 10;
const byte TX_PIN ;
// transmit enable
const byte XMIT_ENABLE_PIN = 14;

unsigned long lastMessageTime;
unsigned long lastCommsTime;

SoftwareSerial rs485 (RX_PIN, TX_PIN);

//**************************************************************
int OFF = HIGH;  // states for relays
int ON = LOW;

//****************************************************************
// PINS
#define gear1OpenPin 44
#define gear1ClosePin 46

#define gear2OpenPin 40
#define gear2ClosePin 42

#define extOpenPin 36
#define extClosePin 38

// States
byte gear1Open = 0;
byte gear1Close = 0;

byte gear2Open = 0;
byte gear2Close = 0;

byte windState = 0;
byte windState2 = 0;

unsigned long millis1 = 0;
unsigned long currentMillis = 0;
unsigned long millis2 = 0;
unsigned long currentMillis2 = 0;
unsigned long millis3 = 0;
unsigned long currentMillis3 = 0;
unsigned long millis4 = 0;
unsigned long currentMillis4 = 0;
unsigned long millis5 = 0;
unsigned long currentMillis5 = 0;
unsigned long millis6 = 0;
unsigned long currentMillis6 = 0;
int wind;
int gearbox1;
int gearbox2;
int setpoint;

int temp;

//******************************************************************
// callbacks for the non-blocking RS485 library
size_t fWrite (const byte what)
{
  rs485.write (what);
}

int fAvailable ()
{
  return rs485.available ();
}

int fRead ()
{
  lastCommsTime = micros ();
  return rs485.read ();
}

// RS485 library instance
RS485 myChannel (fRead, fAvailable, fWrite, 20);



void setup ()
{
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }

  rs485.begin (BAUD_RATE);
  myChannel.begin ();

  // set up various pins
  pinMode (XMIT_ENABLE_PIN, OUTPUT);

  myNextion.init();
  for (int i = 1; i <= 10; i++) {
    wind = myNextion.getComponentValue("wind");
    wind = myNextion.getComponentValue("wind");
    temp = myNextion.getComponentValue("temp");
    setpoint = myNextion.getComponentValue("setp");
    Serial.print(temp);
    Serial.print("  ");
    Serial.println(wind);
    Serial.print(setpoint);
    Serial.println(" ........................ ");
    delay(10);
  }
  //*******************************************************

  // Setup Pins.
  pinMode(gear1OpenPin, OUTPUT);
  pinMode(gear1ClosePin, OUTPUT);

  pinMode(gear2OpenPin, OUTPUT);
  pinMode(gear2ClosePin, OUTPUT);

  pinMode(extOpenPin, OUTPUT);
  pinMode(extClosePin, OUTPUT);

  digitalWrite(gear1OpenPin, OFF);
  digitalWrite(gear1ClosePin, OFF);
  digitalWrite(gear2OpenPin, OFF);
  digitalWrite(gear2ClosePin, OFF);
  digitalWrite(extOpenPin, OFF);
  digitalWrite(extClosePin, OFF);

  // Read current pin states.
  gear1Open = digitalRead(gear1OpenPin);
  gear1Close = digitalRead(gear1ClosePin);

  gear2Open = digitalRead(gear2OpenPin);
  gear2Close = digitalRead(gear2ClosePin);

  t.setInterval(1040, Control1);
  t.setInterval(1050, Control2);
  t.setInterval(500, displayData);
  t.setInterval(2000, external);

}  // end of setup
void loop () {

  t.run();

  // incoming message?
  if (myChannel.update ())
  {
    Serial.println("                               >>----------------------------->");  /// This is not happpening when 3 conditions occur
    memset (&message, 0, sizeof message);
    int len = myChannel.getLength ();
    if (len > sizeof message)
      len = sizeof message;
    memcpy (&message, myChannel.getData (), len);
    lastMessageTime = micros ();
    //    setNextAddress (message.address + 1);
    processMessage ();
  }
}  // end of loop

// Here to process an incoming message
void processMessage ()
{
  Serial.println("                                  <--------------------------<<");    /// This is not happpening when 3 conditions occur
  if (message.address == 3) {
    temp = message.temp;
  }
  if (message.address == 2) {
    wind = message.wind;
  }
}

void Control1() {
  //*****************************************
if (wind >20){
  Wind();
}else{

    switch (gearbox1) {
      case 1:
        //manually close
        Serial.println("Closing");
        digitalWrite(gear1OpenPin, OFF);
        t.setTimer(1000, Close1, 1);

        break;

      case 2:
        //manually open
        Serial.println("Opening");
        digitalWrite(gear1ClosePin, OFF);
        t.setTimer(1000, Open1, 1);

        break;

      case 5:              //   This is one of the conditions   ////////////////////////////
        //stop
        t.setTimer(1000, Stop1, 1);

        break;

      case 10:
        //automatic close
        digitalWrite(gear1OpenPin, OFF);
        myNextion.setComponentText("page0.t5", "A CLOSE 1");
        currentMillis = millis();
        if (currentMillis - millis1 >= 5000) {
          millis1 = currentMillis;
          gear1Close = digitalRead(gear1ClosePin);
          if (gear1Close == OFF) {
            gear1Close = ON;
          } else {
            gear1Close = OFF;
          }
          digitalWrite(gear1ClosePin, gear1Close);
        }
        break;

      case 20:
        //automatic open
        digitalWrite(gear1ClosePin, OFF);
        myNextion.setComponentText("page0.t5", "A OPEN 1");
        currentMillis2 = millis();
        if (currentMillis2 - millis2 >= 5000) {
          millis2 = currentMillis2;
          gear1Open = digitalRead(gear1OpenPin);
          if (gear1Open == OFF) {
            gear1Open = ON;
          } else {
            gear1Open = OFF;
          }
          digitalWrite(gear1OpenPin, gear1Open);
        }
        break;
    }
  }
}


void  Control2() {
  if (wind > 20) {
    digitalWrite(gear2OpenPin, OFF);
    t.setTimer(3000, Close2, 1);
  } else {
    switch (gearbox2) {
      case 1:
        //manually close
        digitalWrite(gear2OpenPin, OFF);
        t.setTimer(1000, Close2, 1);

        break;

      case 2:
        //manually open
        digitalWrite(gear2ClosePin, OFF);
        t.setTimer(1000, Open2, 1);

        break;

      case 5:                  //   This is one of the conditions   ////////////////////////////
        //stop
        t.setTimer(1000, Stop2, 1);

        break;

      case 10:
        //automatic close
        digitalWrite(gear2OpenPin, OFF);
        myNextion.setComponentText("page0.t9", "A CLOSE 2");
        currentMillis3 = millis();
        if (currentMillis3 - millis3 >= 5000) {
          millis3 = currentMillis3;
          gear1Close = digitalRead(gear2ClosePin);
          if (gear2Close == OFF) {
            gear2Close = ON;
          } else {
            gear2Close = OFF;
          }
          digitalWrite(gear2ClosePin, gear2Close);
        }

        break;

      case 20:
        //automatic open
        digitalWrite(gear2ClosePin, OFF);
        myNextion.setComponentText("page0.t9", "A OPEN 2");
        currentMillis4 = millis();
        if (currentMillis4 - millis4 >= 5000) {
          millis4 = currentMillis4;
          gear2Open = digitalRead(gear2OpenPin);
          if (gear2Open == OFF) {
            gear2Open = ON;
          } else {
            gear2Open = OFF;
          }
          digitalWrite(gear2OpenPin, gear2Open);
        }

        break;

    }
  }
}

void Wind(){

    digitalWrite(gear1OpenPin, OFF);
    t.setTimer(3000, Close1, 1);

}

void external () {
  if (setpoint < temp && wind < 20) { // too hot, open
    Serial.println("EXT Opening");
    digitalWrite(extClosePin, OFF);
    digitalWrite(extOpenPin, ON);
  }
  if (setpoint == temp && wind < 20) {  //   This is one of the conditions   ////////////////////////////
    Serial.println("EXT Stopped");
    digitalWrite(extClosePin, OFF);    
    digitalWrite(extOpenPin, OFF);      

  }
  if (setpoint > temp || wind > 20) { // too cold, close
    Serial.println("EXT Closing");
    digitalWrite(extOpenPin, OFF);
    digitalWrite(extClosePin, ON);
  }
}


void Open1() {
  digitalWrite(gear1OpenPin, ON);  myNextion.setComponentText("page0.t5", "Opening 1");
}
//**********************************************
void Close1() {
  digitalWrite(gear1ClosePin, ON);  myNextion.setComponentText("page0.t5", "Closing 1");
}
//**********************************************
void Stop1() {                           //   This is one of the conditions   ////////////////////////////
  Serial.println("Stopping1");
  digitalWrite(gear1ClosePin, OFF);
  digitalWrite(gear1OpenPin, OFF);
  myNextion.setComponentText("page0.t5", "Stopped 1");
}
//***********************************************
void Open2() {
  myNextion.setComponentText("page0.t9", "Opening 2"); digitalWrite(gear2OpenPin, ON);
}
//*************************************************
void Close2() {
  myNextion.setComponentText("page0.t9", "Closing 2"); digitalWrite(gear2ClosePin, ON);
}
//*************************************************
void Stop2() {                              //   This is one of the conditions   ////////////////////////////
  Serial.println("Stopping2");
  digitalWrite(gear2ClosePin, OFF);
  digitalWrite(gear2OpenPin, OFF);
  myNextion.setComponentText("page0.t9", "Stopped 2");
}

void displayData() {

  myNextion.setComponentValue("wind", wind);
  myNextion.setComponentValue("wind", wind);
  myNextion.setComponentValue("temp", temp);
  setpoint = myNextion.getComponentValue("setp");
  gearbox1 = myNextion.getComponentValue("G1");
  gearbox2 = myNextion.getComponentValue("G2");

}
// States
byte gear1Open = 0;
byte gear1Close = 0;

This does not make sense. How can gear1 be opened and closed at the same time?

If these are pin states, the names should reflect that. AND, you need to consider whether these REALLY need to be global.

byte windState = 0;
byte windState2 = 0;

When you number what appear to be related variables, number ALL of them.

unsigned long millis1 = 0;
unsigned long currentMillis = 0;
unsigned long millis2 = 0;
unsigned long currentMillis2 = 0;

Stupid! Why the f**k doesn't currentMillis have a suffix? How the hell can there be 6 current times?

millisN is equally stupid. Some even happens that you care about when it happens. Name the variable for the event, NOT the fact that the value it holds is in milliseconds. No one cares that the value isn't in lightyears.

    wind = myNextion.getComponentValue("wind");
    wind = myNextion.getComponentValue("wind");

Are you sure that twice is enough?

void displayData() {

I would surmise, from the name, that this is purely an output function. The code inside proves that it is NOT. So, fix the damned name.

The values that seem to be causing issues are set by calling a function that interacts with a Nextion display that we have NO idea how you have configured, so YOU need to explain what gearbox1 values of 1, 2, 5, etc. mean. You need to explain why you need timers to open and/or close whatever is being opened or closed.

Thank you for critics, got a point.

Gearbox1 value is got by reading value "G1" from Nextion witch is changed when one of the 4 buttons are pressed: 1 for Open, 2 for Close, 5 for Stop, 10 for Auto Close and 20 for Auto Open.

Timers for open/close are needed to give a time delay between opening/closing, to make sure they not ON simultaneously. Also in Auto mode i want chosen output to be turning on and off in 10sec. increments. So it is not constant, but pulsing.

Timers for open/close are needed to give a time delay between opening/closing, to make sure they not ON simultaneously.

There you are wrong. Timing is needed, NOT timers. The Arduino is perfectly capable of making one event happen after another event happens without using SimpleTimer instances.

Learning how to do so would go a long way towards improving your code.

PaulS:
The Arduino is perfectly capable of making one event happen after another event happens

This is what i would like to do. Where i am struggling, how to do that after state is detected :

  String currentState = input;

  if (currentState != lastState) {
    
    if (currentState == "open") {}

As this is called only once.

      currentMillis = millis();
      if (currentMillis - millis1 >= 5000) {
        millis1 = currentMillis;
        gear1Close = digitalRead(gear1ClosePin);
        if (gear1Close == LOW) {
          gear1Close = HIGH;
        } else {
          gear1Close = LOW;
        }
        digitalWrite(gear1ClosePin, gear1Close);
      }

And this will be executed only once as well. I rewrote my code using states. Less parts working now.

I rewrote my code using states. Less parts working now.

Then, you don't understand states and what a state machine does.

Some information about the need to change states comes from outside the Arduino, such as serial input or limit switches being pressed/released.

Some information about the need to change states comes from inside, such as we've been in the DoorIsClosing state long enough with an external input to trigger the change to the DoorIsClosed state, so we need to transition to the DoorIsStuck state or the DoorFellOffTheHinges state or the DoorHasBeenStolen state.

On any given pass through loop(), you need to check whether there has been external input - read the limit switches, read the serial data, etc. If there has been, change state, and record when that happened (if appropriate).

On any given pass through loop(), you need to check whether the internal conditions have been met, such as it has been 15 seconds since we told the door to close, and it shouldn't take more than 10 seconds, so we need to transition to the DoorIsClosed state, regardless of where the door actually is.

There are so many examples online, where you can learn doing many things the same time, but i cannot find any witch would show how to do to one timed thing after another timed thing. Say, if button is pressed, flash LED 3 times with 1 sec. delay, after that flash LED in 10 sec. delays. If you press another button, it stops everything same second. I cannot find tutorials for that.

Answering my own question. Think i am getting there:

const int ledPin =  LED_BUILTIN;
int ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 1000;
int flag = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (flag == 0) {
      flag = 1;
    }
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    flag = 0;
    digitalWrite(ledPin, ledState);
  }
}

unsigned long previousMillis = 0;

Does this name mean anything to you? It doesn't mean a thing to me.

  unsigned long currentMillis = millis();

now is a heck of a lot shorter than currentMillis AND it means something.

    if (flag == 0) {
      flag = 1;
    }
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    flag = 0;

Why bother testing the value is flag when you are going to unconditionally set it to 0?

What is the point of flag, anyway?

ledState = !ledState; is a much shorter way of toggling the value than your code.